* config.gcc: Add cris-*-aout, cris-*-elf, cris-*-none,
authorhp <hp@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 11 Oct 2001 17:02:36 +0000 (17:02 +0000)
committerhp <hp@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 11 Oct 2001 17:02:36 +0000 (17:02 +0000)
cris-*-linux* cases.
* config/cris/cris-protos.h: New file.
* config/cris/cris.c: New file.
* config/cris/cris.h: New file.
* config/cris/cris.md: New file.
* config/cris/linux.h: New file.
* config/cris/aout.h: New file.
* config/cris/arit.c: New file.
* config/cris/cris_abi_symbol.c: New file.
* config/cris/mulsi3.asm: New file.
* config/cris/t-aout: New file.
* config/cris/t-cris: New file.
* config/cris/t-elfmulti: New file.
* config/cris/t-linux: New file.
* doc/invoke.texi: Add CRIS options.
* doc/install.texi (Specific): Add blurb for CRIS.

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

17 files changed:
gcc/ChangeLog
gcc/config.gcc
gcc/config/cris/aout.h [new file with mode: 0644]
gcc/config/cris/arit.c [new file with mode: 0644]
gcc/config/cris/cris-protos.h [new file with mode: 0644]
gcc/config/cris/cris.c [new file with mode: 0644]
gcc/config/cris/cris.h [new file with mode: 0644]
gcc/config/cris/cris.md [new file with mode: 0644]
gcc/config/cris/cris_abi_symbol.c [new file with mode: 0644]
gcc/config/cris/linux.h [new file with mode: 0644]
gcc/config/cris/mulsi3.asm [new file with mode: 0644]
gcc/config/cris/t-aout [new file with mode: 0644]
gcc/config/cris/t-cris [new file with mode: 0644]
gcc/config/cris/t-elfmulti [new file with mode: 0644]
gcc/config/cris/t-linux [new file with mode: 0644]
gcc/doc/install.texi
gcc/doc/invoke.texi

index 7086dc3..607e979 100644 (file)
@@ -1,3 +1,23 @@
+2001-10-11  Hans-Peter Nilsson  <hp@axis.com>
+
+       * config.gcc: Add cris-*-aout, cris-*-elf, cris-*-none,
+       cris-*-linux* cases.
+       * config/cris/cris-protos.h: New file.
+       * config/cris/cris.c: New file.
+       * config/cris/cris.h: New file.
+       * config/cris/cris.md: New file.
+       * config/cris/linux.h: New file.
+       * config/cris/aout.h: New file.
+       * config/cris/arit.c: New file.
+       * config/cris/cris_abi_symbol.c: New file.
+       * config/cris/mulsi3.asm: New file.
+       * config/cris/t-aout: New file.
+       * config/cris/t-cris: New file.
+       * config/cris/t-elfmulti: New file.
+       * config/cris/t-linux: New file.
+       * doc/invoke.texi: Add CRIS options.
+       * doc/install.texi (Specific): Add blurb for CRIS.
+
 2001-10-10  Hartmut Schirmer <SchirmerH@Innovative-Systems.de>
 
        * config/float-i128.h: Make sure __STDC__VERSION__ is defined
index 0998151..f608595 100644 (file)
@@ -657,6 +657,27 @@ clipper-intergraph-clix*)
        extra_parts="crtbegin.o crtend.o"
        install_headers_dir=install-headers-cpio
        ;;
+cris-*-aout)
+       tm_file="dbxelf.h cris/cris.h cris/aout.h"
+       gas=yes
+       tmake_file="cris/t-cris cris/t-aout"
+       ;;
+cris-*-elf | cris-*-none)
+       tm_file="elfos.h cris/cris.h"
+       tmake_file="cris/t-cris cris/t-elfmulti"
+       gas=yes
+       ;;
+cris-*-linux*)
+       tm_file="linux.h cris/cris.h cris/linux.h"
+       tmake_file="cris/t-cris t-slibgcc-elf-ver cris/t-linux"
+       extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+       case x${enable_threads} in
+       x | xyes | xpthreads | xposix)
+               thread_file=posix
+               ;;
+       esac
+       gas=yes
+       ;;
 d30v-*)
        float_format=i64
        ;;
diff --git a/gcc/config/cris/aout.h b/gcc/config/cris/aout.h
new file mode 100644 (file)
index 0000000..dc998f1
--- /dev/null
@@ -0,0 +1,422 @@
+/* Definitions for GCC.  Part of the machine description for CRIS.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Contributed by Axis Communications.  Written by Hans-Peter Nilsson.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* After the first "Node:" comment comes all preprocessor directives and
+   attached declarations described in the info files, the "Using and
+   Porting GCC" manual (uapgcc), in the same order as found in the "Target
+   macros" section in the gcc-2.9x CVS edition of 2000-03-17.  FIXME: Not
+   really, but needs an update anyway.
+
+   There is no generic copy-of-uapgcc comment, you'll have to see uapgcc
+   for that.  If applicable, there is a CRIS-specific comment.  The order
+   of macro definitions follow the order in the manual.  Every section in
+   the manual (node in the info pages) has an introductory `Node:
+   <subchapter>' comment.  If no macros are defined for a section, only
+   the section-comment is present.  */
+
+/* This file defines the macros for a.out that are not covered by cris.h.
+   Many macros are copied from elfos.h and should be in some generic
+   config/gas-aout.h.  */
+
+/* Node: Driver */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+ "%{melinux:crt0.o%s}\
+  %{!melinux:\
+   %{sim2:s2crt0.o%s}\
+   %{!sim2:\
+    %{sim:scrt0.o%s}\
+    %{!sim:%{pg:gcrt0.o%s}\
+     %{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}}}"
+
+/* Which library to get.  The only difference from the default is to get
+   libsc.a if -sim is given to the driver.  Repeat -lc -lsysX
+   {X=sim,linux}, because libsysX needs (at least) errno from libc, and
+   then we want to resolve new unknowns in libc against libsysX, not
+   libnosys.  Assume everything is in libc for -mlinux.  */
+#undef LIB_SPEC
+#define LIB_SPEC \
+ "%{melinux:-lc -lsyslinux -lc -lsyslinux -lic}\
+  %{!melinux:\
+   %{sim*:-lc -lsyssim -lc -lsyssim}\
+   %{!sim*:%{g*:-lg}\
+     %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} -lbsp}\
+   -lnosys}"
+
+#undef CRIS_CPP_SUBTARGET_SPEC
+#define CRIS_CPP_SUBTARGET_SPEC \
+ "-D__AOUT__\
+  %{melinux:-D__linux__ -D__unix__ -D__elinux__ -D__uclinux__\
+    %{!nostdinc:\
+      %{!mbest-lib-options:%{isystem*}}\
+      -isystem elinux/include%s\
+      %{mbest-lib-options:%{isystem*}}}\
+    %{!ansi:%{!std=*:%{!undef:-Dlinux -Dunix -Delinux -Duclinux}}}}\
+  %{mbest-lib-options:\
+   %{!moverride-best-lib-options:\
+    %{!march=*:%{!metrax*:%{!mcpu=*:-D__tune_v8 -D__CRIS_arch_tune=8}}}}}"
+
+#undef CRIS_CC1_SUBTARGET_SPEC
+#define CRIS_CC1_SUBTARGET_SPEC \
+ "%{mbest-lib-options:\
+   %{!moverride-best-lib-options:\
+    %{!march=*:%{!mcpu=*:-mtune=v8}}}}"
+
+#undef CRIS_ASM_SUBTARGET_SPEC
+#define CRIS_ASM_SUBTARGET_SPEC "--em=crisaout"
+
+#undef CRIS_LINK_SUBTARGET_SPEC
+#define CRIS_LINK_SUBTARGET_SPEC \
+ "-mcrisaout\
+  %{sim2:%{!T*:-Tdata 0x4000000 -Tbss 0x8000000}}\
+  %{melinux:-Ur -d\
+   %{!shlib:%{!symbolic:-Bstatic}}\
+   %{shlib:-Bdynamic}\
+   %{symbolic:-Bdynamic}\
+   %{static:-Bstatic}}\
+  %{melinux-stacksize=*:-defsym __Stacksize=%*}"
+
+#undef CRIS_SUBTARGET_SWITCHES
+#define CRIS_SUBTARGET_SWITCHES                                                \
+  {"elinux", (TARGET_MASK_SVINTO                                       \
+             + TARGET_MASK_STACK_ALIGN                                 \
+             + TARGET_MASK_CONST_ALIGN                                 \
+             + TARGET_MASK_DATA_ALIGN                                  \
+             + TARGET_MASK_ETRAX4_ADD                                  \
+             + TARGET_MASK_ALIGN_BY_32),                               \
+   N_("Compile for the MMU-less Etrax 100-based elinux system")},      \
+  /* Legacy option.  */                                                        \
+  {"aout",   0,        ""},
+
+#undef CRIS_SUBTARGET_LONG_OPTIONS
+#define CRIS_SUBTARGET_LONG_OPTIONS \
+  {"elinux-stacksize=", &cris_elinux_stacksize_str,                    \
+   N_("For elinux, request a specified stack-size for this program")}, \
+
+#undef CRIS_SUBTARGET_VERSION
+#define CRIS_SUBTARGET_VERSION " - a.out"
+
+#undef CRIS_SUBTARGET_DEFAULT
+#define CRIS_SUBTARGET_DEFAULT 0
+
+/* Node: Storage Layout */
+
+/* We can align to 16 bits (only) with CRIS a.out.  */
+#define MAX_OFILE_ALIGNMENT 16
+
+
+/* Node: Library Calls */
+
+#define TARGET_MEM_FUNCTIONS
+
+
+/* Node: Data Output */
+
+#define ESCAPES \
+"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1"
+
+/* Some svr4 assemblers have a limit on the number of characters which
+   can appear in the operand of a .string directive.  If your assembler
+   has such a limitation, you should define STRING_LIMIT to reflect that
+   limit.  Note that at least some svr4 assemblers have a limit on the
+   actual number of bytes in the double-quoted string, and that they
+   count each character in an escape sequence as one byte.  Thus, an
+   escape sequence like \377 would count as four bytes.
+
+   If your target assembler doesn't support the .string directive, you
+   should define this to zero.  */
+
+#define STRING_LIMIT   ((unsigned) 256)
+
+#define STRING_ASM_OP  "\t.string\t"
+#define ASCII_DATA_ASM_OP      "\t.ascii\t"
+#define TYPE_ASM_OP    "\t.type\t"
+#define SIZE_ASM_OP    "\t.size\t"
+#define TYPE_OPERAND_FMT       "@%s"
+
+/* The routine used to output NUL terminated strings.  We use a special
+   version of this for most svr4 targets because doing so makes the
+   generated assembly code more compact (and thus faster to assemble)
+   as well as more readable, especially for targets like the i386
+   (where the only alternative is to output character sequences as
+   comma separated lists of numbers).  */
+
+#define ASM_OUTPUT_LIMITED_STRING(FILE, STR)           \
+  do                                                   \
+    {                                                  \
+      register const unsigned char *_limited_str =     \
+       (const unsigned char *) (STR);                  \
+      register unsigned ch;                            \
+                                                       \
+      fprintf ((FILE), "%s\"", STRING_ASM_OP);         \
+                                                       \
+      for (; (ch = *_limited_str); _limited_str++)     \
+        {                                              \
+         register int escape;                          \
+                                                       \
+         switch (escape = ESCAPES[ch])                 \
+           {                                           \
+           case 0:                                     \
+             putc (ch, (FILE));                        \
+             break;                                    \
+           case 1:                                     \
+             fprintf ((FILE), "\\%03o", ch);           \
+             break;                                    \
+           default:                                    \
+             putc ('\\', (FILE));                      \
+             putc (escape, (FILE));                    \
+             break;                                    \
+           }                                           \
+        }                                              \
+                                                       \
+      fprintf ((FILE), "\"\n");                                \
+    }                                                  \
+  while (0)
+
+/* The routine used to output sequences of byte values.  We use a special
+   version of this for most svr4 targets because doing so makes the
+   generated assembly code more compact (and thus faster to assemble)
+   as well as more readable.  Note that if we find subparts of the
+   character sequence which end with NUL (and which are shorter than
+   STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING.  */
+
+#undef  ASM_OUTPUT_ASCII
+#define ASM_OUTPUT_ASCII(FILE, STR, LENGTH)                            \
+  do                                                                   \
+    {                                                                  \
+      register const unsigned char *_ascii_bytes =                     \
+       (const unsigned char *) (STR);                                  \
+      register const unsigned char *limit = _ascii_bytes + (LENGTH);   \
+      register unsigned bytes_in_chunk = 0;                            \
+                                                                       \
+      for (; _ascii_bytes < limit; _ascii_bytes++)                     \
+        {                                                              \
+         register const unsigned char *p;                              \
+                                                                       \
+         if (bytes_in_chunk >= 60)                                     \
+           {                                                           \
+             fprintf ((FILE), "\"\n");                                 \
+             bytes_in_chunk = 0;                                       \
+           }                                                           \
+                                                                       \
+         for (p = _ascii_bytes; p < limit && *p != '\0'; p++)          \
+           continue;                                                   \
+                                                                       \
+         if (p < limit && (p - _ascii_bytes) <= (long)STRING_LIMIT)    \
+           {                                                           \
+             if (bytes_in_chunk > 0)                                   \
+               {                                                       \
+                 fprintf ((FILE), "\"\n");                             \
+                 bytes_in_chunk = 0;                                   \
+               }                                                       \
+                                                                       \
+             ASM_OUTPUT_LIMITED_STRING ((FILE), _ascii_bytes);         \
+             _ascii_bytes = p;                                         \
+           }                                                           \
+         else                                                          \
+           {                                                           \
+             register int escape;                                      \
+             register unsigned ch;                                     \
+                                                                       \
+             if (bytes_in_chunk == 0)                                  \
+               fprintf ((FILE), "%s\"", ASCII_DATA_ASM_OP);            \
+                                                                       \
+             switch (escape = ESCAPES[ch = *_ascii_bytes])             \
+               {                                                       \
+               case 0:                                                 \
+                 putc (ch, (FILE));                                    \
+                 bytes_in_chunk++;                                     \
+                 break;                                                \
+               case 1:                                                 \
+                 fprintf ((FILE), "\\%03o", ch);                       \
+                 bytes_in_chunk += 4;                                  \
+                 break;                                                \
+               default:                                                \
+                 putc ('\\', (FILE));                                  \
+                 putc (escape, (FILE));                                \
+                 bytes_in_chunk += 2;                                  \
+                 break;                                                \
+               }                                                       \
+           }                                                           \
+       }                                                               \
+                                                                       \
+      if (bytes_in_chunk > 0)                                          \
+        fprintf ((FILE), "\"\n");                                      \
+    }                                                                  \
+  while (0)
+
+
+/* Node: Label Output */
+
+#define SET_ASM_OP     "\t.set\t"
+
+#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \
+  ASM_GLOBALIZE_LABEL (FILE, XSTR (FUN, 0))
+
+#define ASM_WEAKEN_LABEL(FILE, NAME)   \
+  do                                   \
+    {                                  \
+      fputs ("\t.weak\t", (FILE));     \
+      assemble_name ((FILE), (NAME));  \
+      fputc ('\n', (FILE));            \
+    }                                  \
+  while (0)
+
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)    \
+  do                                                   \
+    {                                                  \
+      fprintf (FILE, "%s", TYPE_ASM_OP);               \
+      assemble_name (FILE, NAME);                      \
+      putc (',', FILE);                                        \
+      fprintf (FILE, TYPE_OPERAND_FMT, "function");    \
+      putc ('\n', FILE);                               \
+                                                       \
+      ASM_OUTPUT_LABEL(FILE, NAME);                    \
+    }                                                  \
+  while (0)
+
+#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL)              \
+  do                                                           \
+    {                                                          \
+      fprintf (FILE, "%s", TYPE_ASM_OP);                       \
+      assemble_name (FILE, NAME);                              \
+      putc (',', FILE);                                                \
+      fprintf (FILE, TYPE_OPERAND_FMT, "object");              \
+      putc ('\n', FILE);                                       \
+                                                               \
+      size_directive_output = 0;                               \
+                                                               \
+      if (!flag_inhibit_size_directive                         \
+         && (DECL) && DECL_SIZE (DECL))                        \
+       {                                                       \
+         size_directive_output = 1;                            \
+         fprintf (FILE, "%s", SIZE_ASM_OP);                    \
+         assemble_name (FILE, NAME);                           \
+         putc (',', FILE);                                     \
+         fprintf (FILE, HOST_WIDE_INT_PRINT_DEC,               \
+                  int_size_in_bytes (TREE_TYPE (DECL)));       \
+         fputc ('\n', FILE);                                   \
+       }                                                       \
+                                                               \
+      ASM_OUTPUT_LABEL (FILE, NAME);                           \
+    }                                                          \
+  while (0)
+
+#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END)\
+  do                                                           \
+    {                                                          \
+      const char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0);  \
+                                                               \
+      if (!flag_inhibit_size_directive                         \
+         && DECL_SIZE (DECL)                                   \
+         && ! AT_END && TOP_LEVEL                              \
+         && DECL_INITIAL (DECL) == error_mark_node             \
+         && !size_directive_output)                            \
+       {                                                       \
+         size_directive_output = 1;                            \
+         fprintf (FILE, "%s", SIZE_ASM_OP);                    \
+         assemble_name (FILE, name);                           \
+         putc (',', FILE);                                     \
+         fprintf (FILE, HOST_WIDE_INT_PRINT_DEC,               \
+                  int_size_in_bytes (TREE_TYPE (DECL)));       \
+         fputc ('\n', FILE);                                   \
+       }                                                       \
+    }                                                          \
+  while (0)
+
+#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL)           \
+  do                                                           \
+    {                                                          \
+      if (!flag_inhibit_size_directive)                                \
+       {                                                       \
+         char label[256];                                      \
+         static int labelno;                                   \
+                                                               \
+         labelno++;                                            \
+                                                               \
+         ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno);  \
+         ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno);     \
+                                                               \
+         fprintf (FILE, "%s", SIZE_ASM_OP);                    \
+         assemble_name (FILE, (FNAME));                        \
+         fprintf (FILE, ",");                                  \
+         assemble_name (FILE, label);                          \
+         fprintf (FILE, "-");                                  \
+         assemble_name (FILE, (FNAME));                        \
+         putc ('\n', FILE);                                    \
+       }                                                       \
+    }                                                          \
+  while (0)
+
+
+/* Node: Alignment Output */
+
+#define SKIP_ASM_OP    "\t.zero\t"
+
+#undef  ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(FILE, SIZE) \
+  fprintf (FILE, "%s%u\n", SKIP_ASM_OP, (SIZE))
+
+/* Node: All Debuggers */
+
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+
+/* Node: Misc */
+
+#define HANDLE_SYSV_PRAGMA
+
+/* In theory, this one isn't necessary, but over time, external tools have
+   been primed on names with "." rather than "$".  */
+#define NO_DOLLAR_IN_LABEL
+
+/* These are undocumented, but to keep a single
+   CRIS_ASM_OUTPUT_ALIGNED_DECL_COMMON, we set this to an asm that will
+   emit an error if ever output.  It will not be emitted for a.out modulo
+   careless hacking.  */
+#define COMMON_ASM_OP  "\t.err\t"
+#define LOCAL_ASM_OP   "\t.err\t"
+
+#if defined(__CRIS__) && defined (__AOUT__) && defined (IN_GCC)
+
+#define CRIS_ABI_VERSION_SYMBOL_STRING ".$CRIS_ABI_V2"
+
+/* Make all a.out library functions have undefined references to the
+   .$CRIS_ABI_V2 symbol, so it will be picked up.  Used by GDB.  GDB has
+   a bug with reading a.out symbols; it does not see the GNU weak
+   extensions, so we can't have .$CRIS_ABI_V2 weak.  Weak.  */
+__asm__ (".set .$abi_referer," CRIS_ABI_VERSION_SYMBOL_STRING);
+#endif
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/gcc/config/cris/arit.c b/gcc/config/cris/arit.c
new file mode 100644 (file)
index 0000000..91f4e05
--- /dev/null
@@ -0,0 +1,302 @@
+/* Signed and unsigned multiplication and division and modulus for CRIS.
+   Contributed by Axis Communications.
+   Written by Hans-Peter Nilsson <hp@axis.se>, c:a 1992.
+
+   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file 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 this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+   As a special exception, if you link this library with files, some of
+   which are compiled with GCC, this library does not by itself cause
+   the resulting object or executable to be covered by the GNU General
+   Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file or object might be covered by the GNU General
+   Public License.  */
+
+
+/* Note that we provide prototypes for all "const" functions, to attach
+   the const attribute.  This is necessary in 2.7.2 - adding the
+   attribute to the function *definition* is a syntax error.
+    This did not work with e.g. 2.1; back then, the return type had to
+   be "const".  */
+
+#include "config.h"
+
+#if defined (__CRIS_arch_version) && __CRIS_arch_version >= 3
+#define LZ(v) __extension__ \
+ ({ int tmp_; __asm__ ("lz %1,%0" : "=r" (tmp_) : "r" (v)); tmp_; })
+#endif
+
+
+#if defined (L_udivsi3) || defined (L_divsi3) || defined (L_umodsi3) \
+    || defined (L_modsi3)
+/* Result type of divmod worker function.  */
+struct quot_rem
+ {
+   long quot;
+   long rem;
+ };
+
+/* This is the worker function for div and mod.  It is inlined into the
+   respective library function.  */
+static __inline__ struct quot_rem
+do_31div (unsigned long a, unsigned long b) __attribute__ ((__const__));
+
+static __inline__ struct quot_rem
+do_31div (unsigned long a, unsigned long b)
+{
+  /* Adjust operands and result if a is 31 bits.  */
+  long extra = 0;
+  int quot_digits = 0;
+
+  if (b == 0)
+    {
+      struct quot_rem ret;
+      ret.quot = 0xffffffff;
+      ret.rem = 0xffffffff;
+      return ret;
+    }
+
+  if (a < b)
+    return (struct quot_rem) { 0, a };
+
+#ifdef LZ
+  if (b <= a)
+    {
+      quot_digits = LZ (b) - LZ (a);
+      quot_digits += (a >= (b << quot_digits));
+      b <<= quot_digits;
+    }
+#else
+  while (b <= a)
+    {
+      b <<= 1;
+      quot_digits++;
+    }
+#endif
+
+  /* Is a 31 bits?  Note that bit 31 is handled by the caller.  */
+  if (a & 0x40000000)
+    {
+      /* Then make b:s highest bit max 0x40000000, because it must have
+        been 0x80000000 to be 1 bit higher than a.  */
+      b >>= 1;
+
+      /* Adjust a to be maximum 0x3fffffff, i.e. two upper bits zero.  */
+      if (a >= b)
+       {
+         a -= b;
+         extra = 1 << (quot_digits - 1);
+       }
+      else
+       {
+         a -= b >> 1;
+
+         /* Remember that we adjusted a by subtracting b * 2 ** Something.  */
+         extra = 1 << quot_digits;
+       }
+
+      /* The number of quotient digits will be one less, because
+        we just adjusted b.  */
+      quot_digits--;
+    }
+
+  /* Now do the division part.  */
+
+  /* Subtract b and add ones to the right when a >= b
+     i.e. "a - (b - 1) == (a - b) + 1".  */
+  b--;
+
+#define DS __asm__ ("dstep %2,%0" : "=r" (a) : "0" (a), "r" (b))
+
+  switch (quot_digits)
+    {
+    case 32: DS; case 31: DS; case 30: DS; case 29: DS;
+    case 28: DS; case 27: DS; case 26: DS; case 25: DS;
+    case 24: DS; case 23: DS; case 22: DS; case 21: DS;
+    case 20: DS; case 19: DS; case 18: DS; case 17: DS;
+    case 16: DS; case 15: DS; case 14: DS; case 13: DS;
+    case 12: DS; case 11: DS; case 10: DS; case 9: DS;
+    case 8: DS; case 7: DS; case 6: DS; case 5: DS;
+    case 4: DS; case 3: DS; case 2: DS; case 1: DS;
+    case 0:;
+    }
+
+  {
+    struct quot_rem ret;
+    ret.quot = (a & ((1 << quot_digits) - 1)) + extra;
+    ret.rem = a >> quot_digits;
+    return ret;
+  }
+}
+
+/* Note that unsigned and signed division both build when L_divsi3, but
+   the unsigned variant is then inlined, as with do_31div above.  */
+#if defined (L_udivsi3) || defined (L_divsi3)
+#ifndef L_udivsi3
+static __inline__
+#endif
+unsigned long
+__Udiv (unsigned long a, unsigned long b) __attribute__ ((__const__));
+
+#ifndef L_udivsi3
+static __inline__
+#endif
+unsigned long
+__Udiv (unsigned long a, unsigned long b)
+{
+  long extra = 0;
+
+  /* Adjust operands and result, if a and/or b is 32 bits.  */
+  /* Effectively: b & 0x80000000.  */
+  if ((long) b < 0)
+    return a >= b;
+
+  /* Effectively: a & 0x80000000.  */
+  if ((long) a < 0)
+    {
+      int tmp = 0;
+
+      if (b == 0)
+       return 0xffffffff;
+#ifdef LZ
+      tmp = LZ (b);
+#else
+      for (tmp = 31; (((long) b & (1 << tmp)) == 0); tmp--)
+       ;
+
+      tmp = 31 - tmp;
+#endif
+
+      if ((b << tmp) > a)
+       {
+         extra = 1 << (tmp-1);
+         a -= b << (tmp - 1);
+       }
+      else
+       {
+         extra = 1 << tmp;
+         a -= b << tmp;
+       }
+    }
+
+  return do_31div (a, b).quot+extra;
+}
+
+
+#ifdef L_divsi3
+long
+__Div (long a, long b) __attribute__ ((__const__));
+
+long
+__Div (long a, long b)
+{
+  long sign;
+  long result;
+
+  /* Do *not* call do_31div since abs (-2147483648) == 2147483648
+     <=> abs (-0x80000000) == 0x80000000
+     which is still 32 bits.  */
+
+  sign = a ^ b;
+  result = __Udiv (abs (a), abs (b));
+
+  return  (sign < 0) ? -result : result;
+}
+#endif /* L_divsi3 */
+#endif /* L_udivsi3 || L_divsi3 */
+
+
+/* Note that unsigned and signed modulus both build when L_modsi3, but
+   then the unsigned variant is inlined, as with do_31div above.  */
+#if defined (L_umodsi3) || defined (L_modsi3)
+#ifndef L_umodsi3
+static __inline__
+#endif
+unsigned long
+__Umod (unsigned long a, unsigned long b) __attribute__ ((__const__));
+
+#ifndef L_umodsi3
+static __inline__
+#endif
+unsigned long
+__Umod (unsigned long a, unsigned long b)
+{
+  /* Adjust operands and result if a and/or b is 32 bits.  */
+  if ((long) b < 0)
+    return a >= b ? a - b : a;
+
+  if ((long) a < 0)
+    {
+      int tmp = 0;
+
+      if (b == 0)
+       return a;
+#ifdef LZ
+      tmp = LZ (b);
+#else
+      for (tmp = 31; (((long) b & (1 << tmp)) == 0); tmp--)
+       ;
+      tmp = 31 - tmp;
+#endif
+
+      if ((b << tmp) > a)
+       {
+         a -= b << (tmp - 1);
+       }
+      else
+       {
+         a -= b << tmp;
+       }
+    }
+
+  return do_31div (a, b).rem;
+}
+
+#ifdef L_modsi3
+long
+__Mod (long a, long b) __attribute__ ((__const__));
+
+long
+__Mod (long a, long b)
+{
+  long result;
+
+  result = __Umod (abs (a), abs (b));
+
+  return (a < 0) ? -result : result;
+}
+#endif /* L_modsi3 */
+#endif /* L_umodsi3 || L_modsi3 */
+#endif /* L_udivsi3 || L_divsi3 || L_umodsi3 || L_modsi3 */
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/gcc/config/cris/cris-protos.h b/gcc/config/cris/cris-protos.h
new file mode 100644 (file)
index 0000000..e13c94f
--- /dev/null
@@ -0,0 +1,75 @@
+/* Definitions for GCC.  Part of the machine description for CRIS.
+   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by Axis Communications.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Prototypes for the CRIS port.  */
+
+#if defined(FILE) || defined(stdin) || defined(stdout) || defined(getc) || defined(putc)
+#define STDIO_INCLUDED
+#endif
+
+extern void cris_conditional_register_usage PARAMS ((void));
+extern int cris_simple_epilogue PARAMS ((void));
+#ifdef RTX_CODE
+extern const char *cris_op_str PARAMS ((rtx));
+extern int cris_eligible_for_epilogue_delay PARAMS ((rtx));
+extern void cris_notice_update_cc PARAMS ((rtx, rtx));
+extern int cris_address_cost PARAMS ((rtx));
+extern void cris_print_operand PARAMS ((FILE *, rtx, int));
+extern void cris_print_operand_address PARAMS ((FILE *, rtx));
+extern int cris_side_effect_mode_ok PARAMS ((enum rtx_code, rtx *, int, int,
+                                             int, int, int));
+extern rtx cris_return_addr_rtx PARAMS ((int, rtx));
+extern rtx cris_split_movdx PARAMS ((rtx *));
+extern int cris_legitimate_pic_operand PARAMS ((rtx));
+extern int cris_gotless_symbol PARAMS ((rtx));
+extern int cris_got_symbol PARAMS ((rtx));
+extern int cris_symbol PARAMS ((rtx));
+extern void cris_output_addr_const PARAMS ((FILE *, rtx));
+extern int cris_cfun_uses_pic_table PARAMS ((void));
+extern void cris_target_asm_named_section
+  PARAMS ((const char *, unsigned int));
+
+# ifdef TREE_CODE
+extern rtx cris_expand_builtin_va_arg PARAMS ((tree, tree));
+extern void cris_encode_section_info PARAMS ((tree));
+# endif
+#endif /* RTX_CODE */
+
+#ifdef STDIO_INCLUDED
+# ifdef TREE_CODE
+extern void cris_asm_output_mi_thunk PARAMS ((FILE *, tree, int, tree));
+# endif
+#endif
+
+#ifdef GCC_C_PRAGMA_H
+extern void cris_pragma_expand_mul PARAMS ((cpp_reader *));
+#endif
+
+/* Need one that returns an int; usable in expressions. */
+extern int cris_fatal PARAMS ((char *));
+
+extern void cris_override_options PARAMS ((void));
+
+extern int cris_initial_elimination_offset PARAMS ((int, int));
+
+extern void cris_init_expanders PARAMS ((void));
+
+extern int cris_delay_slots_for_epilogue PARAMS ((void));
diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c
new file mode 100644 (file)
index 0000000..b87a2ac
--- /dev/null
@@ -0,0 +1,3043 @@
+/* Definitions for GCC.  Part of the machine description for CRIS.
+   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by Axis Communications.  Written by Hans-Peter Nilsson.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "tree.h"
+#include "expr.h"
+#include "except.h"
+#include "function.h"
+#include "toplev.h"
+#include "recog.h"
+#include "tm_p.h"
+#include "debug.h"
+#include "target.h"
+#include "target-def.h"
+
+/* Usable when we have an amount to add or subtract, and want the
+   optimal size of the insn.  */
+#define ADDITIVE_SIZE_MODIFIER(size) \
+ ((size) <= 63 ? "q" : (size) <= 255 ? "u.b" : (size) <= 65535 ? "u.w" : ".d")
+
+#define ASSERT_PLT_UNSPEC(x)                                   \
+  do                                                           \
+    {                                                          \
+      if (XEXP (x, 1) != NULL_RTX                              \
+         || (GET_CODE (XVECEXP (x, 0, 0)) != SYMBOL_REF        \
+             && GET_CODE (XVECEXP (x, 0, 0)) != LABEL_REF))    \
+       abort ();                                               \
+    } while (0)
+
+/* Per-function machine data.  */
+struct machine_function
+ {
+   int needs_return_address_on_stack;
+ };
+
+/* Fix for reg_overlap_mentioned_p.  */
+static int cris_reg_overlap_mentioned_p PARAMS ((rtx, rtx));
+
+/* This little fix suppresses the 'u' or 's' when '%e' in assembly
+   pattern.  */
+static char cris_output_insn_is_bound = 0;
+
+/* This one suppresses printing out the "rPIC+" in
+   "rPIC+sym:GOTOFF+offset" when doing PIC.  For a PLT symbol, it
+   suppresses outputting it as [rPIC+sym:GOTPLT] and outputs similarly
+   just the "sym:GOTOFF" part.  */
+static int cris_pic_sympart_only = 0;
+
+static void
+cris_print_base PARAMS ((rtx, FILE *));
+
+static void
+cris_print_index PARAMS ((rtx, FILE *));
+
+static void
+cris_init_machine_status PARAMS ((struct function *));
+
+static int
+cris_initial_frame_pointer_offset PARAMS ((void));
+
+static int
+saved_regs_mentioned PARAMS ((rtx));
+
+static void cris_target_asm_function_prologue
+  PARAMS ((FILE *, HOST_WIDE_INT));
+static void cris_target_asm_function_epilogue
+  PARAMS ((FILE *, HOST_WIDE_INT));
+
+/* The function cris_target_asm_function_epilogue puts the last insn to
+   output here.  Used in delay_slots_for_epilogue and function_epilogue.  */
+static char save_last[80];
+
+/* This is the argument from the "-max-stack-stackframe=" option.  */
+const char *cris_max_stackframe_str;
+
+/* This is the argument from the "-march=" option.  */
+const char *cris_cpu_str;
+
+/* This is the argument from the "-mtune=" option.  */
+const char *cris_tune_str;
+
+/* This is the argument from the "-melinux-stacksize=" option.  */
+const char *cris_elinux_stacksize_str;
+
+/* This is the parsed result of the "-max-stack-stackframe=" option.  If
+   it (still) is zero, then there was no such option given.  */
+int cris_max_stackframe = 0;
+
+/* This is the parsed result of the "-march=" option, if given.  */
+int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION;
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE cris_target_asm_function_prologue
+
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE cris_target_asm_function_epilogue
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+/* Predicate functions.  */
+
+/* This checks a part of an address, the one that is not a plain register
+   for an addressing mode using BDAP.
+   Allowed operands is either:
+   a) a register
+   b) a CONST operand (but not a symbol when generating PIC)
+   c) a [r] or [r+] in SImode, or sign-extend from HI or QI.  */
+
+int
+cris_bdap_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  register enum rtx_code code = GET_CODE (op);
+
+  if (mode != SImode && (mode != VOIDmode || GET_MODE (op) != VOIDmode))
+    return 0;
+
+  /* Just return whether this is a simple register or constant.  */
+  if (register_operand (op, mode)
+      || (CONSTANT_P (op) && !(flag_pic && cris_symbol (op))))
+    return 1;
+
+  /* Is it a [r] or possibly a [r+]?  */
+  if (code == MEM)
+    {
+      rtx tem = XEXP (op, 0);
+
+      if (mode == SImode
+         && (register_operand (tem, SImode)
+             || (GET_CODE (tem) == POST_INC
+                 && register_operand (XEXP (tem, 0), SImode))))
+       return 1;
+      else
+       return 0;
+    }
+
+  /* Perhaps a sign-extended mem: [r].(b|w) or [r+].(b|w)?  */
+  if (code == SIGN_EXTEND)
+    {
+      rtx tem = XEXP (op, 0);
+
+      if (GET_CODE (tem) != MEM)
+       return 0;
+
+      tem = XEXP (tem, 0);
+      if (mode == SImode
+         && (register_operand (tem, SImode)
+             || (GET_CODE (tem) == POST_INC
+                 && register_operand (XEXP (tem, 0), SImode))))
+       return 1;
+      else
+       return 0;
+    }
+
+  return 0;
+}
+
+/* This is similar to cris_bdap_operand:
+   It checks a part of an address, the one that is not a plain register
+   for an addressing mode using BDAP *or* BIAP.
+   Allowed operands is either:
+   a) a register
+   b) a CONST operand (but not a symbol when generating PIC)
+   c) a mult of (1, 2 or 4) and a register
+   d) a [r] or [r+] in SImode, or sign-extend from HI or QI.  */
+
+int
+cris_bdap_biap_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  register enum rtx_code code = GET_CODE (op);
+  rtx reg;
+  rtx val;
+
+  /* Check for bdap operand.  */
+  if (cris_bdap_operand (op, mode))
+    return 1;
+
+  if (mode != SImode && (mode != VOIDmode || GET_MODE (op) != VOIDmode))
+    return 0;
+
+  /* Check that we're looking at a BIAP operand.  */
+  if (code != MULT)
+    return 0;
+
+  /* Canonicalize register and multiplicand.  */
+  if (GET_CODE (XEXP (op, 0)) == CONST_INT)
+    {
+      val = XEXP (op, 0);
+      reg = XEXP (op, 1);
+    }
+  else
+    {
+      val = XEXP (op, 1);
+      reg = XEXP (op, 0);
+    }
+
+  /* Check that the operands are correct after canonicalization.  */
+  if (! register_operand (reg, SImode) || GET_CODE (val) != CONST_INT)
+    return 0;
+
+  /* Check that the multiplicand has a valid value.  */
+  if ((code == MULT
+       && (INTVAL (val) == 1 || INTVAL (val) == 2 || INTVAL (val) == 4)))
+    return 1;
+
+  return 0;
+}
+
+/* Check if MODE is same as mode for X, and X is PLUS, MINUS, IOR or
+   AND or UMIN.  */
+
+int
+cris_orthogonal_operator (x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+  enum rtx_code code = GET_CODE (x);
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (x);
+
+  return (GET_MODE (x) == mode
+         && (code == PLUS || code == MINUS
+             || code == IOR || code == AND || code == UMIN));
+}
+
+/* Check if MODE is same as mode for X, and X is PLUS, IOR or AND or
+   UMIN.  */
+
+int
+cris_commutative_orth_op (x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+  enum rtx_code code = GET_CODE (x);
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (x);
+
+  return (GET_MODE (x) == mode &&
+         (code == PLUS
+          || code == IOR || code == AND || code == UMIN));
+}
+
+/* Check if MODE is same as mode for X, and X is PLUS or MINUS or UMIN.  */
+
+int
+cris_operand_extend_operator (x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+  enum rtx_code code = GET_CODE (x);
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (x);
+
+  return (GET_MODE (x) == mode
+         && (code == PLUS || code == MINUS || code == UMIN));
+}
+
+/* Check to see if MODE is same as mode for X, and X is SIGN_EXTEND or
+   ZERO_EXTEND.  */
+
+int
+cris_extend_operator (x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+  enum rtx_code code = GET_CODE (x);
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (x);
+
+  return
+    (GET_MODE (x) == mode && (code == SIGN_EXTEND || code == ZERO_EXTEND));
+}
+
+/* Check to see if MODE is same as mode for X, and X is PLUS or BOUND.  */
+
+int
+cris_plus_or_bound_operator (x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+  enum rtx_code code = GET_CODE (x);
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (x);
+
+  return
+    (GET_MODE (x) == mode && (code == UMIN || code == PLUS));
+}
+
+/* Since with -fPIC, not all symbols are valid PIC symbols or indeed
+   general_operands, we have to have a predicate that matches it for the
+   "movsi" expander.  */
+
+int
+cris_general_operand_or_symbol (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return general_operand (op, mode)
+    || (CONSTANT_P (op) && cris_symbol (op));
+}
+
+/* Since a PIC symbol without a GOT entry is not a general_operand, we
+   have to have a predicate that matches it.  We use this in the expanded
+   "movsi" anonymous pattern for PIC symbols.  */
+
+int
+cris_general_operand_or_gotless_symbol (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return general_operand (op, mode)
+    || (CONSTANT_P (op) && cris_gotless_symbol (op));
+}
+
+/* Since a PLT symbol is not a general_operand, we have to have a
+   predicate that matches it when we need it.  We use this in the expanded
+   "call" and "call_value" anonymous patterns.  */
+
+int
+cris_general_operand_or_plt_symbol (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return general_operand (op, mode)
+    || (GET_CODE (op) == CONST
+       && GET_CODE (XEXP (op, 0)) == UNSPEC
+       && !TARGET_AVOID_GOTPLT);
+}
+
+/* This matches a (MEM (general_operand)) or
+   (MEM (cris_general_operand_or_symbol)).  The second one isn't a valid
+   memory_operand, so we need this predicate to recognize call
+   destinations before we change them to a PLT operand (by wrapping in
+   UNSPEC 0).  */
+
+int
+cris_mem_call_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  rtx xmem;
+
+  if (GET_CODE (op) != MEM)
+    return 0;
+
+  if (memory_operand (op, mode))
+    return 1;
+
+  xmem = XEXP (op, 0);
+
+  return cris_general_operand_or_symbol (xmem, GET_MODE (op));
+}
+
+/* The CONDITIONAL_REGISTER_USAGE worker.   */
+
+void
+cris_conditional_register_usage ()
+{
+  /* FIXME: This isn't nice.  We should be able to use that register for
+     something else if the PIC table isn't needed.  */
+  if (flag_pic)
+    fixed_regs[PIC_OFFSET_TABLE_REGNUM]
+      = call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+}
+
+/* Return current_function_uses_pic_offset_table.  For use in cris.md,
+   since some generated files do not include function.h.  */
+
+int
+cris_cfun_uses_pic_table ()
+{
+  return current_function_uses_pic_offset_table;
+}
+
+/* Given an rtx, return the text string corresponding to the CODE of X.
+   Intended for use in the assembly language output section of a
+   define_insn.  */
+
+const char *
+cris_op_str (x)
+     rtx x;
+{
+  cris_output_insn_is_bound = 0;
+  switch (GET_CODE (x))
+    {
+    case PLUS:
+      return "add";
+      break;
+
+    case MINUS:
+      return "sub";
+      break;
+
+    case MULT:
+      return "mul";
+      break;
+
+    case DIV:
+      return "div";
+      break;
+
+    case AND:
+      return "and";
+      break;
+
+    case IOR:
+      return "or";
+      break;
+
+    case XOR:
+      return "xor";
+      break;
+
+    case NOT:
+      return "not";
+      break;
+
+    case ASHIFT:
+      return "lsl";
+      break;
+
+    case LSHIFTRT:
+      return "lsr";
+      break;
+
+    case ASHIFTRT:
+      return "asr";
+      break;
+
+    case UMIN:
+      /* Used to control the sign/zero-extend character for the 'e' modifier.
+        BOUND has none.  */
+      cris_output_insn_is_bound = 1;
+      return "bound";
+      break;
+
+    default:
+      return "Unknown operator";
+      break;
+  }
+}
+
+/* Print an index part of an address to file.  */
+
+static void
+cris_print_index (index, file)
+     rtx index;
+     FILE * file;
+{
+  rtx inner = XEXP (index, 0);
+
+  /* Make the index "additive" unless we'll output a negative number, in
+     which case the sign character is free (as in free beer).  */
+  if (GET_CODE (index) != CONST_INT || INTVAL (index) >= 0)
+    putc ('+', file);
+
+  if (REG_P (index))
+    fprintf (file, "$%s.b", reg_names[REGNO (index)]);
+  else if (CONSTANT_P (index))
+    cris_output_addr_const (file, index);
+  else if (GET_CODE (index) == MULT)
+    {
+      fprintf (file, "$%s.",
+              reg_names[REGNO (XEXP (index, 0))]);
+
+      putc (INTVAL (XEXP (index, 1)) == 2 ? 'w' : 'd', file);
+    }
+  else if (GET_CODE (index) == SIGN_EXTEND &&
+          GET_CODE (inner) == MEM)
+    {
+      rtx inner_inner = XEXP (inner, 0);
+
+      if (GET_CODE (inner_inner) == POST_INC)
+       {
+         fprintf (file, "[$%s+].",
+                  reg_names[REGNO (XEXP (inner_inner, 0))]);
+         putc (GET_MODE (inner) == HImode ? 'w' : 'b', file);
+       }
+      else
+       {
+         fprintf (file, "[$%s].", reg_names[REGNO (inner_inner)]);
+
+         putc (GET_MODE (inner) == HImode ? 'w' : 'b', file);
+       }
+    }
+  else if (GET_CODE (index) == MEM)
+    {
+      if (GET_CODE (inner) == POST_INC)
+       fprintf (file, "[$%s+].d", reg_names[REGNO (XEXP (inner, 0))]);
+      else
+       fprintf (file, "[$%s].d", reg_names[REGNO (inner)]);
+    }
+  else
+    fatal_insn ("Unexpected index-type in cris_print_index", index);
+}
+
+/* Print a base rtx of an address to file.  */
+
+static void
+cris_print_base (base, file)
+     rtx base;
+     FILE *file;
+{
+  if (REG_P (base))
+    fprintf (file, "$%s", reg_names[REGNO (base)]);
+  else if (GET_CODE (base) == POST_INC)
+    fprintf (file, "$%s+", reg_names[REGNO (XEXP (base, 0))]);
+  else
+    fatal_insn ("Unexpected base-type in cris_print_base", base);
+}
+
+/* Usable as a guard in expressions.  */
+
+int
+cris_fatal (arg)
+     char *arg;
+{
+  internal_error (arg);
+
+  /* We'll never get here; this is just to appease compilers.  */
+  return 0;
+}
+
+/* Textual function prologue.  */
+
+static void
+cris_target_asm_function_prologue (file, size)
+     FILE *file;
+     HOST_WIDE_INT size;
+{
+  int regno;
+
+  /* Shorten the used name for readability.  */
+  int cfoa_size = current_function_outgoing_args_size;
+  int last_movem_reg = -1;
+  int doing_dwarf = dwarf2out_do_frame ();
+  int framesize;
+  int faked_args_size = 0;
+  int cfa_write_offset = 0;
+  char *cfa_label = NULL;
+  int return_address_on_stack
+    = regs_ever_live[CRIS_SRP_REGNUM]
+    || cfun->machine->needs_return_address_on_stack != 0;
+
+  /* Don't do anything if no prologues or epilogues are wanted.  */
+  if (!TARGET_PROLOGUE_EPILOGUE)
+    return;
+
+  if (size < 0)
+    abort ();
+
+  /* Align the size to what's best for the CPU model.  */
+  if (TARGET_STACK_ALIGN)
+    size = TARGET_ALIGN_BY_32 ? (size + 3) & ~3 : (size + 1) & ~1;
+
+  if (current_function_pretend_args_size)
+    {
+      int pretend = current_function_pretend_args_size;
+      for (regno = CRIS_FIRST_ARG_REG + CRIS_MAX_ARGS_IN_REGS - 1;
+          pretend > 0;
+          regno--, pretend -= 4)
+       {
+         fprintf (file, "\tpush $%s\n", reg_names[regno]);
+         faked_args_size += 4;
+       }
+    }
+
+  framesize = faked_args_size;
+
+  if (doing_dwarf)
+    {
+      /* FIXME: Slightly redundant calculation, as we do the same in
+        pieces below.  This offset must be the total adjustment of the
+        stack-pointer.  We can then def_cfa call at the end of this
+        function with the current implementation of execute_cfa_insn, but
+        that wouldn't really be clean.  */
+
+      int cfa_offset
+       = faked_args_size
+       + (return_address_on_stack ? 4 : 0)
+       + (frame_pointer_needed ? 4 : 0);
+
+      int cfa_reg;
+
+      if (frame_pointer_needed)
+       cfa_reg = FRAME_POINTER_REGNUM;
+      else
+       {
+         cfa_reg = STACK_POINTER_REGNUM;
+         cfa_offset += cris_initial_frame_pointer_offset ();
+       }
+
+      cfa_label = dwarf2out_cfi_label ();
+      dwarf2out_def_cfa (cfa_label, cfa_reg, cfa_offset);
+
+      cfa_write_offset = - faked_args_size - 4;
+    }
+
+  /* Save SRP if not a leaf function.  */
+  if (return_address_on_stack)
+    {
+      fprintf (file, "\tPush $srp\n");
+      framesize += 4;
+
+      if (doing_dwarf)
+       {
+         dwarf2out_return_save (cfa_label, cfa_write_offset);
+         cfa_write_offset -= 4;
+       }
+    }
+
+  /* Set up frame pointer if needed.  */
+  if (frame_pointer_needed)
+    {
+      fprintf (file, "\tpush $%s\n\tmove.d $sp,$%s\n",
+              reg_names[FRAME_POINTER_REGNUM],
+              reg_names[FRAME_POINTER_REGNUM]);
+      framesize += 4;
+
+      if (doing_dwarf)
+       {
+         dwarf2out_reg_save (cfa_label, FRAME_POINTER_REGNUM,
+                             cfa_write_offset);
+         cfa_write_offset -= 4;
+       }
+    }
+
+  /* Local vars are located above saved regs.  */
+  cfa_write_offset -= size;
+
+  /* Get a contiguous sequence of registers, starting with r0, that need
+     to be saved. */
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    {
+      if ((((regs_ever_live[regno]
+            && !call_used_regs[regno])
+           || (regno == PIC_OFFSET_TABLE_REGNUM
+               && (current_function_uses_pic_offset_table
+                   /* It is saved anyway, if there would be a gap.  */
+                   || (flag_pic
+                       && regs_ever_live[regno + 1]
+                       && !call_used_regs[regno + 1]))))
+          && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed)
+          && regno != CRIS_SRP_REGNUM)
+         || (current_function_calls_eh_return
+             && (regno == EH_RETURN_DATA_REGNO (0)
+                 || regno == EH_RETURN_DATA_REGNO (1)
+                 || regno == EH_RETURN_DATA_REGNO (2)
+                 || regno == EH_RETURN_DATA_REGNO (3))))
+       {
+         /* Check if movem may be used for registers so far.  */
+         if (regno == last_movem_reg + 1)
+           /* Yes, update next expected register.  */
+           last_movem_reg++;
+         else
+           {
+             /* We cannot use movem for all registers.  We have to flush
+                any movem:ed registers we got so far.  */
+             if (last_movem_reg != -1)
+               {
+                 /* It is a win to use a side-effect assignment for
+                    64 <= size <= 128.  But side-effect on movem was
+                    not usable for CRIS v0..3.  Also only do it if
+                    side-effects insns are allowed.  */
+                 if ((last_movem_reg + 1) * 4 + size >= 64
+                     && (last_movem_reg + 1) * 4 + size <= 128
+                     && cris_cpu_version >= CRIS_CPU_SVINTO
+                     && TARGET_SIDE_EFFECT_PREFIXES)
+                   fprintf (file, "\tmovem $%s,[$sp=$sp-%d]\n",
+                            reg_names[last_movem_reg],
+                            (last_movem_reg + 1) * 4 + size);
+                 else
+                   {
+                     /* Avoid printing multiple subsequent sub:s for sp.  */
+                     fprintf (file, "\tsub%s %d,$sp\n",
+                              ADDITIVE_SIZE_MODIFIER ((last_movem_reg + 1)
+                                                      * 4 + size),
+                              (last_movem_reg + 1) * 4 + size);
+
+                     fprintf (file, "\tmovem $%s,[$sp]\n",
+                              reg_names[last_movem_reg]);
+                   }
+
+                 framesize += (last_movem_reg + 1) * 4 + size;
+
+                 if (TARGET_PDEBUG)
+                   fprintf (file, "; frame %d, #regs %d, bytes %d args %d\n",
+                            size,
+                            last_movem_reg + 1,
+                            (last_movem_reg + 1) * 4,
+                            current_function_args_size);
+
+                 last_movem_reg = -1;
+                 size = 0;
+               }
+             else if (size > 0)
+               {
+                 /* Local vars on stack, but there are no movem:s.
+                    Just allocate space.  */
+                 fprintf (file, "\tSub%s %d,$sp\n",
+                          ADDITIVE_SIZE_MODIFIER (size),
+                          size);
+                 framesize += size;
+                 size = 0;
+               }
+
+             fprintf (file, "\tPush $%s\n", reg_names[regno]);
+             framesize += 4;
+           }
+
+         if (doing_dwarf)
+           {
+             /* Registers are stored lowest numbered at highest address,
+                which matches the loop order; we just need to update the
+                write-offset.  */
+             dwarf2out_reg_save (cfa_label, regno, cfa_write_offset);
+             cfa_write_offset -= 4;
+           }
+       }
+    }
+
+  /* Check after, if we can movem all registers.  This is the normal
+     case.  */
+  if (last_movem_reg != -1)
+    {
+      /* Side-effect assignment on movem was not supported for CRIS v0..3,
+        and don't do it if we're asked not to.
+
+        The movem is already accounted for, for unwind.  */
+
+      if ((last_movem_reg + 1) * 4 + size >= 64
+         && (last_movem_reg + 1) * 4 + size <= 128
+         && cris_cpu_version >= CRIS_CPU_SVINTO
+         && TARGET_SIDE_EFFECT_PREFIXES)
+       fprintf (file, "\tmovem $%s,[$sp=$sp-%d]\n",
+                reg_names[last_movem_reg],
+                (last_movem_reg+1) * 4 + size);
+      else
+       {
+         /* Avoid printing multiple subsequent sub:s for sp.  FIXME:
+            Clean up the conditional expression. */
+         fprintf (file, "\tsub%s %d,$sp\n",
+                  ADDITIVE_SIZE_MODIFIER ((last_movem_reg + 1) * 4 + size),
+                  (last_movem_reg + 1) * 4 + size);
+         /* To be compatible with v0..v3 means we do not use an assignment
+            addressing mode with movem.  We normally don't need that
+            anyway.  It would only be slightly more efficient for 64..128
+            bytes frame size.  */
+         fprintf (file, "\tmovem $%s,[$sp]\n", reg_names[last_movem_reg]);
+       }
+
+      framesize += (last_movem_reg + 1) * 4 + size;
+
+      if (TARGET_PDEBUG)
+       fprintf (file, "; frame %d, #regs %d, bytes %d args %d\n",
+                size,
+                last_movem_reg + 1,
+                (last_movem_reg + 1) * 4,
+                current_function_args_size);
+
+      /* We have to put outgoing argument space after regs.  */
+      if (cfoa_size)
+       {
+         /* This does not need to be accounted for, for unwind.  */
+
+         fprintf (file, "\tSub%s %d,$sp\n",
+                  ADDITIVE_SIZE_MODIFIER (cfoa_size),
+                  cfoa_size);
+         framesize += cfoa_size;
+       }
+    }
+  else if ((size + cfoa_size) > 0)
+    {
+      /* This does not need to be accounted for, for unwind.  */
+
+      /* Local vars on stack, and we could not use movem.  Add a sub here.  */
+      fprintf (file, "\tSub%s %d,$sp\n",
+              ADDITIVE_SIZE_MODIFIER (size + cfoa_size),
+              cfoa_size + size);
+      framesize += size + cfoa_size;
+    }
+
+  /* Set up the PIC register.  */
+  if (current_function_uses_pic_offset_table)
+    asm_fprintf (file, "\tmove.d $pc,$%s\n\tsub.d .:GOTOFF,$%s\n",
+                reg_names[PIC_OFFSET_TABLE_REGNUM],
+                reg_names[PIC_OFFSET_TABLE_REGNUM]);
+
+  if (TARGET_PDEBUG)
+    fprintf (file,
+            "; parm #%d @ %d; frame %d, FP-SP is %d; leaf: %s%s; fp %s, outg: %d arg %d\n",
+            CRIS_MAX_ARGS_IN_REGS + 1, FIRST_PARM_OFFSET (0),
+            get_frame_size (),
+            cris_initial_frame_pointer_offset (),
+            leaf_function_p () ? "yes" : "no",
+            return_address_on_stack ? "no" :"yes",
+            frame_pointer_needed ? "yes" : "no",
+            cfoa_size, current_function_args_size);
+
+  if (cris_max_stackframe && framesize > cris_max_stackframe)
+    warning ("Stackframe too big: %d bytes", framesize);
+}
+
+/* Return nonzero if there are regs mentioned in the insn that are not all
+   in the call_used regs.  This is part of the decision whether an insn
+   can be put in the epilogue.  */
+
+static int
+saved_regs_mentioned (x)
+     rtx x;
+{
+  int i;
+  const char *fmt;
+  RTX_CODE code;
+
+  /* Mainly stolen from refers_to_regno_p in rtlanal.c. */
+
+  code = GET_CODE (x);
+
+  switch (code)
+    {
+    case REG:
+      i = REGNO (x);
+      return !call_used_regs[i];
+
+    case SUBREG:
+      /* If this is a SUBREG of a hard reg, we can see exactly which
+        registers are being modified.  Otherwise, handle normally.  */
+      i = REGNO (SUBREG_REG (x));
+      return !call_used_regs[i];
+
+    default:
+      ;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       {
+         if (saved_regs_mentioned (XEXP (x, i)))
+           return 1;
+       }
+      else if (fmt[i] == 'E')
+       {
+         int j;
+         for (j = XVECLEN (x, i) - 1; j >=0; j--)
+           if (saved_regs_mentioned (XEXP (x, i)))
+             return 1;
+       }
+    }
+
+  return 0;
+}
+
+/* Figure out if the insn may be put in the epilogue.  */
+
+int
+cris_eligible_for_epilogue_delay (insn)
+     rtx insn;
+{
+  /* First of all, it must be as slottable as for a delayed branch insn.  */
+  if (get_attr_slottable (insn) != SLOTTABLE_YES)
+    return 0;
+
+  /* It must not refer to the stack pointer (may be valid for some cases
+     that I can't think of).  */
+  if (reg_mentioned_p (stack_pointer_rtx, PATTERN (insn)))
+    return 0;
+
+  /* The frame pointer will be restored in the epilogue, before the
+     "ret", so it can't be referred to.  */
+  if (frame_pointer_needed
+      && reg_mentioned_p (frame_pointer_rtx, PATTERN (insn)))
+    return 0;
+
+  /* All saved regs are restored before the delayed insn.
+     This means that we cannot have any instructions that mention the
+     registers that are restored by the epilogue.  */
+  if (saved_regs_mentioned (PATTERN (insn)))
+    return 0;
+
+  /* It seems to be ok.  */
+  return 1;
+}
+
+/* Return the number of delay-slots in the epilogue: return 1 if it
+   contains "ret", else 0.  */
+
+int
+cris_delay_slots_for_epilogue ()
+{
+  /* Check if we use a return insn, which we only do for leaf functions.
+     Else there is no slot to fill.  */
+  if (regs_ever_live[CRIS_SRP_REGNUM]
+      || cfun->machine->needs_return_address_on_stack != 0)
+    return 0;
+
+  /* By calling function_epilogue with the same parameters as from gcc
+     we can get info about if the epilogue can fill the delay-slot by itself.
+     If it is filled from the epilogue, then the corresponding string
+     is in save_last.
+      This depends on that the "size" argument to function_epilogue
+     always is get_frame_size.
+     FIXME:  Kludgy.  At least make it a separate function that is not
+     misnamed or abuses the stream parameter.  */
+  cris_target_asm_function_epilogue (NULL, get_frame_size ());
+
+  if (*save_last)
+    return 1;
+  return 0;
+}
+
+/* Textual function epilogue.  When file is NULL, it serves doubly as
+   a test for whether the epilogue can fill any "ret" delay-slots by
+   itself by storing the delay insn in save_last.  */
+
+static void
+cris_target_asm_function_epilogue (file, size)
+     FILE *file;
+     HOST_WIDE_INT size;
+{
+  int regno;
+  int last_movem_reg = -1;
+  rtx insn = get_last_insn ();
+  int argspace_offset = current_function_outgoing_args_size;
+  int pretend =         current_function_pretend_args_size;
+  int return_address_on_stack
+    = regs_ever_live[CRIS_SRP_REGNUM]
+    || cfun->machine->needs_return_address_on_stack != 0;
+
+  save_last[0] = 0;
+
+  if (file && !TARGET_PROLOGUE_EPILOGUE)
+    return;
+
+  if (TARGET_PDEBUG && file)
+    fprintf (file, ";;\n");
+
+  /* Align byte count of stack frame.  */
+  if (TARGET_STACK_ALIGN)
+    size = TARGET_ALIGN_BY_32 ? (size + 3) & ~3 : (size + 1) & ~1;
+
+  /* If the last insn was a BARRIER, we don't have to write any code,
+     then all returns were covered by "return" insns.  */
+  if (GET_CODE (insn) == NOTE)
+    insn = prev_nonnote_insn (insn);
+  if (insn
+      && (GET_CODE (insn) == BARRIER
+         /* We must make sure that the insn really is a "return" and
+            not a conditional branch.  Try to match the return exactly,
+            and if it doesn't match, assume it is a conditional branch
+            (and output an epilogue).  */
+         || (GET_CODE (insn) == JUMP_INSN
+             && GET_CODE (PATTERN (insn)) == RETURN)))
+    {
+      if (TARGET_PDEBUG && file)
+       fprintf (file, ";;;;;\n");
+      return;
+    }
+
+  /* Check how many saved regs we can movem.  They start at r0 and must
+     be contiguous.  */
+  for (regno = 0;
+       regno < FIRST_PSEUDO_REGISTER;
+       regno++)
+    if ((((regs_ever_live[regno]
+          && !call_used_regs[regno])
+         || (regno == PIC_OFFSET_TABLE_REGNUM
+             && (current_function_uses_pic_offset_table
+                 /* It is saved anyway, if there would be a gap.  */
+                 || (flag_pic
+                     && regs_ever_live[regno + 1]
+                     && !call_used_regs[regno + 1]))))
+        && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed)
+        && regno != CRIS_SRP_REGNUM)
+       || (current_function_calls_eh_return
+           && (regno == EH_RETURN_DATA_REGNO (0)
+               || regno == EH_RETURN_DATA_REGNO (1)
+               || regno == EH_RETURN_DATA_REGNO (2)
+               || regno == EH_RETURN_DATA_REGNO (3))))
+
+      {
+       if (regno == last_movem_reg + 1)
+         last_movem_reg++;
+       else
+         break;
+      }
+
+  for (regno = FIRST_PSEUDO_REGISTER - 1;
+       regno > last_movem_reg;
+       regno--)
+    if ((((regs_ever_live[regno]
+          && !call_used_regs[regno])
+         || (regno == PIC_OFFSET_TABLE_REGNUM
+             && (current_function_uses_pic_offset_table
+                 /* It is saved anyway, if there would be a gap.  */
+                 || (flag_pic
+                     && regs_ever_live[regno + 1]
+                     && !call_used_regs[regno + 1]))))
+        && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed)
+        && regno != CRIS_SRP_REGNUM)
+       || (current_function_calls_eh_return
+           && (regno == EH_RETURN_DATA_REGNO (0)
+               || regno == EH_RETURN_DATA_REGNO (1)
+               || regno == EH_RETURN_DATA_REGNO (2)
+               || regno == EH_RETURN_DATA_REGNO (3))))
+      {
+       if (argspace_offset)
+         {
+           /* There is an area for outgoing parameters located before
+              the saved registers.  We have to adjust for that.  */
+           if (file)
+             fprintf (file, "\tAdd%s %d,$sp\n",
+                      ADDITIVE_SIZE_MODIFIER (argspace_offset),
+                      argspace_offset);
+
+           /* Make sure we only do this once.  */
+           argspace_offset = 0;
+         }
+
+       /* Flush previous non-movem:ed registers.  */
+       if (*save_last && file)
+         fprintf (file, save_last);
+       sprintf (save_last, "\tPop $%s\n");
+      }
+
+  if (last_movem_reg != -1)
+    {
+      if (argspace_offset)
+       {
+         /* Adjust for the outgoing parameters area, if that's not
+            handled yet.  */
+         if (*save_last && file)
+           {
+             fprintf (file, save_last);
+             *save_last = 0;
+           }
+       
+         if (file)
+           fprintf (file, "\tAdd%s %d,$sp\n",
+                    ADDITIVE_SIZE_MODIFIER (argspace_offset),
+                    argspace_offset);
+         argspace_offset = 0;
+       }
+      /* Flush previous non-movem:ed registers.  */
+      else if (*save_last && file)
+       fprintf (file, save_last);
+      sprintf (save_last, "\tmovem [$sp+],$%s\n", reg_names[last_movem_reg]);
+    }
+
+  /* Restore frame pointer if necessary.  */
+  if (frame_pointer_needed)
+    {
+      if (*save_last && file)
+       fprintf (file, save_last);
+
+      if (file)
+       fprintf (file, "\tmove.d $%s,$sp\n",
+                reg_names[FRAME_POINTER_REGNUM]);
+      sprintf (save_last, "\tPop $%s\n",
+              reg_names[FRAME_POINTER_REGNUM]);
+    }
+  else
+    {
+      /* If there was no frame-pointer to restore sp from, we must
+        explicitly deallocate local variables.  */
+
+      /* Handle space for outgoing parameters that hasn't been handled
+        yet.  */
+      size += argspace_offset;
+
+      if (size)
+       {
+         if (*save_last && file)
+           fprintf (file, save_last);
+
+         sprintf (save_last, "\tadd%s %d,$sp\n",
+                  ADDITIVE_SIZE_MODIFIER (size), size);
+       }
+
+      /* If the size was not in the range for a "quick", we must flush
+        it here.  */
+      if (size > 63)
+       {
+         if (file)
+           fprintf (file, save_last);
+         *save_last = 0;
+       }
+    }
+
+  /* If this function has no pushed register parameters
+     (stdargs/varargs), and if it is not a leaf function, then we can
+     just jump-return here.  */
+  if (return_address_on_stack && pretend == 0)
+    {
+      if (*save_last && file)
+       fprintf (file, save_last);
+      *save_last = 0;
+
+      if (file)
+       {
+         if (current_function_calls_eh_return)
+           {
+             /* The installed EH-return address is in *this* frame, so we
+                need to pop it before we return.  */
+             fprintf (file, "\tpop $srp\n", reg_names[CRIS_STACKADJ_REG]);
+             fprintf (file, "\tret\n");
+             fprintf (file, "\tadd.d $%s,$sp\n", reg_names[CRIS_STACKADJ_REG]);
+           }
+         else
+           fprintf (file, "\tJump [$sp+]\n");
+
+         /* Do a sanity check to avoid generating invalid code.  */
+         if (current_function_epilogue_delay_list)
+           internal_error ("Allocated but unused delay list in epilogue");
+       }
+      return;
+    }
+
+  /* Rather than add current_function_calls_eh_return conditions
+     everywhere in the following code (and not be able to test it
+     thoroughly), assert the assumption that all usage of
+     __builtin_eh_return are handled above.  */
+  if (current_function_calls_eh_return)
+    internal_error ("Unexpected function type needing stack adjustment for\
+ __builtin_eh_return");
+
+  /* If we pushed some register parameters, then adjust the stack for
+     them.  */
+  if (pretend)
+    {
+      /* Since srp is stored on the way, we need to restore it first. */
+      if (return_address_on_stack)
+       {
+         if (*save_last && file)
+           fprintf (file, save_last);
+         *save_last = 0;
+
+         if (file)
+           fprintf (file, "\tpop $srp\n");
+       }
+
+      if (*save_last && file)
+       fprintf (file, save_last);
+
+      sprintf (save_last, "\tadd%s %d,$sp\n",
+              ADDITIVE_SIZE_MODIFIER (pretend), pretend);
+    }
+
+  /* Here's where we have a delay-slot we need to fill. */
+  if (file && current_function_epilogue_delay_list)
+    {
+      /* If gcc has allocated an insn for the epilogue delay slot, but
+        things were arranged so we now thought we could do it
+        ourselves, don't forget to flush that insn.  */
+      if (*save_last)
+       fprintf (file, save_last);
+
+      fprintf (file, "\tRet\n");
+
+      /* Output the delay-slot-insn the mandated way.  */
+      final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
+                      file, 1, -2, 1);
+    }
+  else if (file)
+    {
+      fprintf (file, "\tRet\n");
+
+      /* If the GCC did not do it, we have to use whatever insn we have,
+        or a nop.  */
+      if (*save_last)
+       fprintf (file, save_last);
+      else
+       fprintf (file, "\tnOp\n");
+    }
+}
+
+/* The PRINT_OPERAND worker.  */
+
+void
+cris_print_operand (file, x, code)
+     FILE *file;
+     rtx x;
+     int code;
+{
+  rtx operand = x;
+
+  /* Size-strings corresponding to MULT expressions.  */
+  static const char *mults[] = { "BAD:0", ".b", ".w", "BAD:3", ".d" };
+
+  /* New code entries should just be added to the switch below.  If
+     handling is finished, just return.  If handling was just a
+     modification of the operand, the modified operand should be put in
+     "operand", and then do a break to let default handling
+     (zero-modifier) output the operand.  */
+
+  switch (code)
+    {
+    case 'b':
+      /* Print the unsigned supplied integer as if it was signed
+        and < 0, i.e print 255 or 65535 as -1, 254, 65534 as -2, etc.  */
+      if (GET_CODE (x) != CONST_INT
+         || ! CONST_OK_FOR_LETTER_P (INTVAL (x), 'O'))
+       fatal_insn ("Internal: Invalid operand with 'b'", x);
+      fprintf (file, "%d", INTVAL (x)| (INTVAL (x) <= 255 ? ~255 : ~65535));
+      return;
+
+    case 'x':
+      /* Print assembler code for operator.  */
+      fprintf (file, "%s", cris_op_str (operand));
+      return;
+
+    case 'v':
+      /* Print the operand without the PIC register.  */
+      if (! flag_pic || ! cris_gotless_symbol (x))
+       fatal_insn ("Internal: Invalid operand with 'v'", x);
+      cris_pic_sympart_only++;
+      cris_output_addr_const (file, x);
+      cris_pic_sympart_only--;
+      return;
+
+    case 'P':
+      /* Print the PIC register.  Applied to a GOT-less PIC symbol for
+         sanity.  */
+      if (! flag_pic || ! cris_gotless_symbol (x))
+       fatal_insn ("Internal: Invalid operand with 'P'", x);
+      fprintf (file, "$%s", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+      return;
+
+    case 'p':
+      /* Adjust a power of two to its log2.  */
+      if (GET_CODE (x) != CONST_INT || exact_log2 (INTVAL (x)) < 0 )
+       fatal_insn ("Internal: Invalid operand with 'p'", x);
+      fprintf (file, "%d", exact_log2 (INTVAL (x)));
+      return;
+
+    case 's':
+      /* For an integer, print 'b' or 'w' if <= 255 or <= 65535
+        respectively.  This modifier also terminates the inhibiting
+         effects of the 'x' modifier.  */
+      cris_output_insn_is_bound = 0;
+      if (GET_MODE (x) == VOIDmode && GET_CODE (x) == CONST_INT)
+       {
+         if (INTVAL (x) >= 0)
+           {
+             if (INTVAL (x) <= 255)
+               putc ('b', file);
+             else if (INTVAL (x) <= 65535)
+               putc ('w', file);
+             else
+               putc ('d', file);
+           }
+         else
+           putc ('d', file);
+         return;
+       }
+
+      /* For a non-integer, print the size of the operand.  */
+      putc ((GET_MODE (x) == SImode || GET_MODE (x) == SFmode)
+           ? 'd' : GET_MODE (x) == HImode ? 'w'
+           : GET_MODE (x) == QImode ? 'b'
+           /* If none of the above, emit an erroneous size letter.  */
+           : 'X',
+           file);
+      return;
+
+    case 'z':
+      /* Const_int: print b for -127 <= x <= 255,
+        w for -32768 <= x <= 65535, else abort.  */
+      if (GET_CODE (x) != CONST_INT
+         || INTVAL (x) < -32768 || INTVAL (x) > 65535)
+       fatal_insn ("Internal: Invalid operand with 'z'", x);
+      putc (INTVAL (x) >= -128 && INTVAL (x) <= 255 ? 'b' : 'w', file);
+      return;
+
+    case '#':
+      /* Output a 'nop' if there's nothing for the delay slot.
+        This method stolen from the sparc files.  */
+      if (dbr_sequence_length () == 0)
+       fputs ("\n\tnop", file);
+      return;
+
+    case 'H':
+      /* Print high (most significant) part of something.  */
+      switch (GET_CODE (operand))
+       {
+       case CONST_INT:
+         /* Sign-extension from a normal int to a long long.  */
+         fprintf (file, INTVAL (operand) < 0 ? "-1" : "0");
+         return;
+
+       case CONST_DOUBLE:
+         /* High part of a long long constant.  */
+         if (GET_MODE (operand) == VOIDmode)
+           {
+             fprintf (file, "0x%x", CONST_DOUBLE_HIGH (x));
+             return;
+           }
+         else
+           fatal_insn ("Internal: Invalid operand with 'H'", x);
+
+       case REG:
+         /* Print reg + 1.  Check that there's not an attempt to print
+            high-parts of registers like stack-pointer or higher.  */
+         if (REGNO (operand) > STACK_POINTER_REGNUM - 2)
+           internal_error ("Internal: Bad register: %d", REGNO (operand));
+         fprintf (file, "$%s", reg_names[REGNO (operand) + 1]);
+         return;
+
+       case MEM:
+         /* Adjust memory address to high part.  */
+         {
+           rtx adj_mem = operand;
+           int size
+             = GET_MODE_BITSIZE (GET_MODE (operand)) / BITS_PER_UNIT;
+
+           /* Adjust so we can use two SImode in DImode.
+              Calling adj_offsettable_operand will make sure it is an
+              offsettable address.  Don't do this for a postincrement
+              though; it should remain as it was.  */
+           if (GET_CODE (XEXP (adj_mem, 0)) != POST_INC)
+             adj_mem
+               = adjust_address (adj_mem, GET_MODE (adj_mem), size / 2);
+
+           output_address (XEXP (adj_mem, 0));
+           return;
+         }
+
+       default:
+         fatal_insn ("Internal: Invalid operand for 'H'", x);
+       }
+
+    case 'L':
+      /* Strip the MEM expression.  */
+      operand = XEXP (operand, 0);
+      break;
+
+    case 'e':
+      /* Print 's' if operand is SIGN_EXTEND or 'u' if ZERO_EXTEND unless
+        cris_output_insn_is_bound is nonzero.  */
+      if (GET_CODE (operand) != SIGN_EXTEND
+         && GET_CODE (operand) != ZERO_EXTEND
+         && GET_CODE (operand) != CONST_INT)
+       fatal_insn ("Internal: Invalid operand with 'e'", x);
+
+      if (cris_output_insn_is_bound)
+       {
+         cris_output_insn_is_bound = 0;
+         return;
+       }
+
+      putc (GET_CODE (operand) == SIGN_EXTEND
+           || (GET_CODE (operand) == CONST_INT && INTVAL (operand) < 0)
+           ? 's' : 'u', file);
+      return;
+
+    case 'm':
+      /* Print the size letter of the inner element.  We can do it by
+        calling ourselves with the 's' modifier.  */
+      if (GET_CODE (operand) != SIGN_EXTEND && GET_CODE (operand) != ZERO_EXTEND)
+       fatal_insn ("Internal: Invalid operand with 'm'", x);
+      cris_print_operand (file, XEXP (operand, 0), 's');
+      return;
+
+    case 'M':
+      /* Print the least significant part of operand.  */
+      if (GET_CODE (operand) == CONST_DOUBLE)
+       {
+         fprintf (file, "0x%x", CONST_DOUBLE_LOW (x));
+         return;
+       }
+      /* If not a CONST_DOUBLE, the least significant part equals the
+        normal part, so handle it normally.  */
+      break;
+
+    case 'A':
+      /* When emitting an add for the high part of a DImode constant, we
+        want to use addq for 0 and adds.w for -1.  */
+      if (GET_CODE (operand) != CONST_INT)
+       fatal_insn ("Internal: Invalid operand with 'A' output modifier", x);
+      fprintf (file, INTVAL (operand) < 0 ? "adds.w" : "addq");
+      return;
+
+    case 'D':
+      /* When emitting an sub for the high part of a DImode constant, we
+        want to use subq for 0 and subs.w for -1.  */
+      if (GET_CODE (operand) != CONST_INT)
+       fatal_insn ("Internal: Invalid operand with 'D' output modifier", x);
+      fprintf (file, INTVAL (operand) < 0 ? "subs.w" : "subq");
+      return;
+
+    case 'S':
+      /* Print the operand as the index-part of an address.
+        Easiest way out is to use cris_print_index.  */
+      cris_print_index (operand, file);
+      return;
+
+    case 'T':
+      /* Print the size letter for an operand to a MULT, which must be a
+        const_int with a suitable value.  */
+      if (GET_CODE (operand) != CONST_INT || INTVAL (operand) > 4)
+       fatal_insn ("Internal: Invalid operand with 'T'", x);
+
+      fprintf (file, "%s", mults[INTVAL (operand)]);
+      return;
+
+    case 0:
+      /* No code, print as usual. */
+      break;
+
+    default:
+      {
+#define BADFORMAT "Internal: Invalid operand for '%c'"
+       char s[sizeof BADFORMAT];
+       sprintf (s, BADFORMAT, code);
+       fatal_insn (s, x);
+      }
+    }
+
+  /* Print an operand as without a modifier letter. */
+  switch (GET_CODE (operand))
+    {
+    case REG:
+      if (REGNO (operand) > 15)
+       internal_error ("Internal: Bad register: %d", REGNO (operand));
+      fprintf (file, "$%s", reg_names[REGNO (operand)]);
+      return;
+
+    case MEM:
+      output_address (XEXP (operand, 0));
+      return;
+
+    case CONST_DOUBLE:
+      if (GET_MODE (operand) == VOIDmode)
+       /* A long long constant.  */
+       output_addr_const (file, operand);
+      else
+       {
+         /* Only single precision is allowed as plain operands the
+            moment.  FIXME:  REAL_VALUE_FROM_CONST_DOUBLE isn't
+            documented.  */
+         REAL_VALUE_TYPE r;
+         long l;
+
+         /* FIXME:  Perhaps check overflow of the "single".  */
+         REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
+         REAL_VALUE_TO_TARGET_SINGLE (r, l);
+
+         fprintf (file, "0x%lx", l);
+       }
+      return;
+
+    case UNSPEC:
+      ASSERT_PLT_UNSPEC (operand);
+      /* Fall through.  */
+
+    case CONST:
+      cris_output_addr_const (file, operand);
+      return;
+
+    case MULT:
+    case ASHIFT:
+      {
+       /* For a (MULT (reg X) const_int) we output "rX.S".  */
+       int i = GET_CODE (XEXP (operand, 1)) == CONST_INT
+         ? INTVAL (XEXP (operand, 1)) : INTVAL (XEXP (operand, 0));
+       rtx reg = GET_CODE (XEXP (operand, 1)) == CONST_INT
+         ? XEXP (operand, 0) : XEXP (operand, 1);
+
+       if (GET_CODE (reg) != REG
+           || (GET_CODE (XEXP (operand, 0)) != CONST_INT
+               && GET_CODE (XEXP (operand, 1)) != CONST_INT))
+         fatal_insn ("Can't print operand", x);
+
+       cris_print_base (reg, file);
+       fprintf (file, ".%c",
+                i == 0 || (i == 1 && GET_CODE (operand) == MULT) ? 'b'
+                : i == 4 ? 'd'
+                : (i == 2 && GET_CODE (operand) == MULT) || i == 1 ? 'w'
+                : 'd');
+       return;
+      }
+
+    default:
+      /* No need to handle all strange variants, let output_addr_const
+        do it for us.  */
+      if (CONSTANT_P (operand))
+       {
+         cris_output_addr_const (file, operand);
+         return;
+       }
+
+      fatal_insn ("Internal: Cannot decode operand", x);
+    }
+}
+
+/* The PRINT_OPERAND_ADDRESS worker.  */
+
+void
+cris_print_operand_address (file, x)
+     FILE *file;
+     rtx x;
+{
+  /* All these were inside MEM:s so output indirection characters.  */
+  putc ('[', file);
+
+  if (CONSTANT_ADDRESS_P (x))
+    cris_output_addr_const (file, x);
+  else if (BASE_OR_AUTOINCR_P (x))
+    cris_print_base (x, file);
+  else if (GET_CODE (x) == PLUS)
+    {
+      rtx x1, x2;
+
+      x1 = XEXP (x, 0);
+      x2 = XEXP (x, 1);
+      if (BASE_P (x1))
+       {
+         cris_print_base (x1, file);
+         cris_print_index (x2, file);
+       }
+      else if (BASE_P (x2))
+       {
+         cris_print_base (x2, file);
+         cris_print_index (x1, file);
+       }
+      else
+       fatal_insn ("Internal: This is not a recognized address", x);
+    }
+  else if (GET_CODE (x) == MEM)
+    {
+      /* A DIP.  Output more indirection characters.  */
+      putc ('[', file);
+      cris_print_base (XEXP (x, 0), file);
+      putc (']', file);
+    }
+  else
+    fatal_insn ("Internal: This is not a recognized address", x);
+
+  putc (']', file);
+}
+
+/* The RETURN_ADDR_RTX worker.
+   We mark that the return address is used, either by EH or
+   __builtin_return_address, for use by the function prologue and
+   epilogue.  FIXME: This isn't optimal; we just use the mark in the
+   prologue and epilogue to say that the return address is to be stored
+   in the stack frame.  We could return SRP for leaf-functions and use the
+   initial-value machinery.  */
+
+rtx
+cris_return_addr_rtx (count, frameaddr)
+     int count;
+     rtx frameaddr ATTRIBUTE_UNUSED;
+{
+  cfun->machine->needs_return_address_on_stack = 1;
+
+  /* The return-address is stored just above the saved frame-pointer (if
+     present).  Apparently we can't eliminate from the frame-pointer in
+     that direction, so use the incoming args (maybe pretended) pointer.  */
+  return count == 0
+    ? gen_rtx_MEM (Pmode, plus_constant (virtual_incoming_args_rtx, -4))
+    : NULL_RTX;
+}
+
+/* This used to be the INITIAL_FRAME_POINTER_OFFSET worker; now only
+   handles FP -> SP elimination offset.  */
+
+static int
+cris_initial_frame_pointer_offset ()
+{
+  int regno;
+
+  /* Initial offset is 0 if we dont have a frame pointer.  */
+  int offs = 0;
+
+  /* And 4 for each register pushed.  */
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if ((((regs_ever_live[regno]
+          && !call_used_regs[regno])
+         || (regno == PIC_OFFSET_TABLE_REGNUM
+             && (current_function_uses_pic_offset_table
+                 /* It is saved anyway, if there would be a gap.  */
+                 || (flag_pic
+                     && regs_ever_live[regno + 1]
+                     && !call_used_regs[regno + 1]))))
+        && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed)
+        && regno != CRIS_SRP_REGNUM)
+       || (current_function_calls_eh_return
+           && (regno == EH_RETURN_DATA_REGNO (0)
+               || regno == EH_RETURN_DATA_REGNO (1)
+               || regno == EH_RETURN_DATA_REGNO (2)
+               || regno == EH_RETURN_DATA_REGNO (3))))
+      offs += 4;
+
+  /* And then, last, we add the locals allocated.  */
+  offs += get_frame_size ();
+
+  /* And more; the accumulated args size.  */
+  offs += current_function_outgoing_args_size;
+
+  /* Then round it off, in case we use aligned stack.  */
+  if (TARGET_STACK_ALIGN)
+    offs = TARGET_ALIGN_BY_32 ? (offs + 3) & ~3 : (offs + 1) & ~1;
+
+  return offs;
+}
+
+/* The INITIAL_ELIMINATION_OFFSET worker.
+   Calculate the difference between imaginary registers such as frame
+   pointer and the stack pointer.  Used to eliminate the frame pointer
+   and imaginary arg pointer.  */
+
+int
+cris_initial_elimination_offset (fromreg, toreg)
+     int fromreg;
+     int toreg;
+{
+  int fp_sp_offset
+    = cris_initial_frame_pointer_offset ();
+
+  /* We should be able to use regs_ever_live and related prologue
+     information here, or alpha should not as well.  */
+  int return_address_on_stack
+    = regs_ever_live[CRIS_SRP_REGNUM]
+    || cfun->machine->needs_return_address_on_stack != 0;
+
+  /* Here we act as if the frame-pointer is needed.  */
+  int ap_fp_offset = 4 + (return_address_on_stack ? 4 : 0);
+
+  if (fromreg == ARG_POINTER_REGNUM
+      && toreg == FRAME_POINTER_REGNUM)
+    return ap_fp_offset;
+
+  /* Between the frame pointer and the stack are only "normal" stack
+     variables and saved registers.  */
+  if (fromreg == FRAME_POINTER_REGNUM
+      && toreg == STACK_POINTER_REGNUM)
+    return fp_sp_offset;
+
+  /* We need to balance out the frame pointer here. */
+  if (fromreg == ARG_POINTER_REGNUM
+      && toreg == STACK_POINTER_REGNUM)
+    return ap_fp_offset + fp_sp_offset - 4;
+
+  abort ();
+}
+
+/*  This function looks into the pattern to see how this insn affects
+    condition codes.
+
+    Used when to eliminate test insns before a condition-code user,
+    such as a "scc" insn or a conditional branch.  This includes
+    checking if the entities that cc was updated by, are changed by the
+    operation.
+
+    Currently a jumble of the old peek-inside-the-insn and the newer
+    check-cc-attribute methods.  */
+
+void
+cris_notice_update_cc (exp, insn)
+     rtx exp;
+     rtx insn;
+{
+  /* Check if user specified "-mcc-init" as a bug-workaround.  FIXME:
+     TARGET_CCINIT does not work; we must set CC_REVERSED as below.
+     Several test-cases will otherwise fail, for example
+     gcc.c-torture/execute/20000217-1.c -O0 and -O1.  */
+  if (TARGET_CCINIT)
+    {
+      CC_STATUS_INIT;
+      return;
+    }
+
+  /* Slowly, we're converting to using attributes to control the setting
+     of condition-code status.  */
+  switch (get_attr_cc (insn))
+    {
+    case CC_NONE:
+      /* Even if it is "none", a setting may clobber a previous
+        cc-value, so check.  */
+      if (GET_CODE (exp) == SET)
+       {
+         if (cc_status.value1
+             && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+                                            cc_status.value1))
+           cc_status.value1 = 0;
+
+         if (cc_status.value2
+             && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+                                            cc_status.value2))
+           cc_status.value2 = 0;
+       }
+      return;
+
+    case CC_CLOBBER:
+      CC_STATUS_INIT;
+      break;
+
+    case CC_NORMAL:
+      /* Which means, for:
+        (set (cc0) (...)):
+        CC is (...).
+
+        (set (reg) (...)):
+        CC is (reg) and (...) - unless (...) is 0, then CC does not change.
+        CC_NO_OVERFLOW unless (...) is reg or mem.
+
+        (set (mem) (...)):
+        CC does not change.
+
+        (set (pc) (...)):
+        CC does not change.
+
+        (parallel
+         (set (reg1) (mem (bdap/biap)))
+         (set (reg2) (bdap/biap))):
+        CC is (reg1) and (mem (reg2))
+
+        (parallel
+         (set (mem (bdap/biap)) (reg1)) [or 0]
+         (set (reg2) (bdap/biap))):
+        CC does not change.
+
+        (where reg and mem includes strict_low_parts variants thereof)
+
+        For all others, assume CC is clobbered.
+        Note that we do not have to care about setting CC_NO_OVERFLOW,
+        since the overflow flag is set to 0 (i.e. right) for
+        instructions where it does not have any sane sense, but where
+        other flags have meanings.  (This includes shifts; the carry is
+        not set by them).
+
+        Note that there are other parallel constructs we could match,
+        but we don't do that yet.  */
+
+      if (GET_CODE (exp) == SET)
+       {
+         /* FIXME: Check when this happens.  It looks like we should
+            actually do a CC_STATUS_INIT here to be safe.  */
+         if (SET_DEST (exp) == pc_rtx)
+           return;
+
+         /* Record CC0 changes, so we do not have to output multiple
+            test insns. */
+         if (SET_DEST (exp) == cc0_rtx)
+           {
+             cc_status.value1 = SET_SRC (exp);
+             cc_status.value2 = 0;
+
+             /* Handle flags for the special btstq on one bit. */
+             if (GET_CODE (SET_SRC (exp)) == ZERO_EXTRACT
+                 && XEXP (SET_SRC (exp), 1) == const1_rtx)
+               {
+                 if (GET_CODE (XEXP (SET_SRC (exp), 0)) == CONST_INT)
+                   /* Using cmpq.  */
+                   cc_status.flags = CC_INVERTED;
+                 else
+                   /* A one-bit btstq.  */
+                   cc_status.flags = CC_Z_IN_NOT_N;
+               }
+             else
+               cc_status.flags = 0;
+
+             if (GET_CODE (SET_SRC (exp)) == COMPARE)
+               {
+                 if (!REG_P (XEXP (SET_SRC (exp), 0))
+                     && XEXP (SET_SRC (exp), 1) != const0_rtx)
+                   /* For some reason gcc will not canonicalize compare
+                      operations, reversing the sign by itself if
+                      operands are in wrong order. */
+                   /* (But NOT inverted; eq is still eq.) */
+                   cc_status.flags = CC_REVERSED;
+
+                 /* This seems to be overlooked by gcc.  FIXME: Check again.
+                    FIXME:  Is it really safe?  */
+                 cc_status.value2
+                   = gen_rtx_MINUS (GET_MODE (SET_SRC (exp)),
+                                    XEXP (SET_SRC (exp), 0),
+                                    XEXP (SET_SRC (exp), 1));
+               }
+             return;
+           }
+         else if (REG_P (SET_DEST (exp))
+                  || (GET_CODE (SET_DEST (exp)) == STRICT_LOW_PART
+                      && REG_P (XEXP (SET_DEST (exp), 0))))
+           {
+             /* A register is set; normally CC is set to show that no
+                test insn is needed.  Catch the exceptions. */
+
+             /* If not to cc0, then no "set"s in non-natural mode give
+                ok cc0...  */
+             if (GET_MODE_SIZE (GET_MODE (SET_DEST (exp))) > UNITS_PER_WORD
+                 || GET_MODE_CLASS (GET_MODE (SET_DEST (exp))) == MODE_FLOAT)
+               {
+                 /* ... except add:s and sub:s in DImode. */
+                 if (GET_MODE (SET_DEST (exp)) == DImode
+                     && (GET_CODE (SET_SRC (exp)) == PLUS
+                         || GET_CODE (SET_SRC (exp)) == MINUS))
+                   {
+                     cc_status.flags = 0;
+                     cc_status.value1 = SET_DEST (exp);
+                     cc_status.value2 = SET_SRC (exp);
+
+                     if (cris_reg_overlap_mentioned_p (cc_status.value1,
+                                                       cc_status.value2))
+                       cc_status.value2 = 0;
+
+                     /* Add and sub may set V, which gets us
+                        unoptimizable results in "gt" and "le" condition
+                        codes.  */
+                     cc_status.flags |= CC_NO_OVERFLOW;
+
+                     return;
+                   }
+               }
+             else if (SET_SRC (exp) == const0_rtx)
+               {
+                 /* There's no CC0 change when clearing a register or
+                    memory.  Just check for overlap.  */
+                 if ((cc_status.value1
+                      && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+                                                       cc_status.value1)))
+                   cc_status.value1 = 0;
+
+                 if ((cc_status.value2
+                      && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+                                                       cc_status.value2)))
+                   cc_status.value2 = 0;
+
+                 return;
+               }
+             else
+               {
+                 cc_status.flags = 0;
+                 cc_status.value1 = SET_DEST (exp);
+                 cc_status.value2 = SET_SRC (exp);
+
+                 if (cris_reg_overlap_mentioned_p (cc_status.value1,
+                                                   cc_status.value2))
+                   cc_status.value2 = 0;
+
+                 /* Some operations may set V, which gets us
+                    unoptimizable results in "gt" and "le" condition
+                    codes.  */
+                 if (GET_CODE (SET_SRC (exp)) == PLUS
+                     || GET_CODE (SET_SRC (exp)) == MINUS
+                     || GET_CODE (SET_SRC (exp)) == NEG)
+                   cc_status.flags |= CC_NO_OVERFLOW;
+
+                 return;
+               }
+           }
+         else if (GET_CODE (SET_DEST (exp)) == MEM
+                  || (GET_CODE (SET_DEST (exp)) == STRICT_LOW_PART
+                      && GET_CODE (XEXP (SET_DEST (exp), 0)) == MEM))
+           {
+             /* When SET to MEM, then CC is not changed (except for
+                overlap).  */
+             if ((cc_status.value1
+                  && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+                                                   cc_status.value1)))
+               cc_status.value1 = 0;
+
+             if ((cc_status.value2
+                  && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+                                                   cc_status.value2)))
+               cc_status.value2 = 0;
+
+             return;
+           }
+       }
+      else if (GET_CODE (exp) == PARALLEL)
+       {
+         if (GET_CODE (XVECEXP (exp, 0, 0)) == SET
+             && GET_CODE (XVECEXP (exp, 0, 1)) == SET
+             && REG_P (XEXP (XVECEXP (exp, 0, 1), 0)))
+           {
+             if (REG_P (XEXP (XVECEXP (exp, 0, 0), 0))
+                 && GET_CODE (XEXP (XVECEXP (exp, 0, 0), 1)) == MEM)
+               {
+                 /* For "move.S [rx=ry+o],rz", say CC reflects
+                    value1=rz and value2=[rx] */
+                 cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0);
+                 cc_status.value2
+                   = gen_rtx_MEM (GET_MODE (XEXP (XVECEXP (exp, 0, 0), 0)),
+                                  XEXP (XVECEXP (exp, 0, 1), 0));
+                 cc_status.flags = 0;
+
+                 /* Huh?  A side-effect cannot change the destination
+                    register.  */
+                 if (cris_reg_overlap_mentioned_p (cc_status.value1,
+                                                   cc_status.value2))
+                   internal_error ("Internal: sideeffect-insn affecting main effect");
+                 return;
+               }
+             else if ((REG_P (XEXP (XVECEXP (exp, 0, 0), 1))
+                       || XEXP (XVECEXP (exp, 0, 0), 1) == const0_rtx)
+                      && GET_CODE (XEXP (XVECEXP (exp, 0, 0), 0)) == MEM)
+               {
+                 /* For "move.S rz,[rx=ry+o]" and "clear.S [rx=ry+o]",
+                    say flags are not changed, except for overlap.  */
+                 if ((cc_status.value1
+                      && cris_reg_overlap_mentioned_p (XEXP
+                                                       (XVECEXP
+                                                        (exp, 0, 0), 0),
+                                                       cc_status.value1))
+                     || (cc_status.value2
+                         && cris_reg_overlap_mentioned_p (XEXP
+                                                          (XVECEXP
+                                                           (exp, 0, 1), 0),
+                                                          cc_status.value2)))
+                   CC_STATUS_INIT;
+                 return;
+               }
+           }
+       }
+      break;
+
+    default:
+      /* Unknown cc_attr value.  */
+      abort ();
+    }
+
+  CC_STATUS_INIT;
+}
+
+/* Return != 0 if the return sequence for the current function is short,
+   like "ret" or "jump [sp+]".  Prior to reloading, we can't tell how
+   many registers must be saved, so return 0 then.  */
+
+int
+cris_simple_epilogue ()
+{
+  int regno;
+  int reglimit = STACK_POINTER_REGNUM;
+  int lastreg = -1;
+
+  if (! reload_completed
+      || frame_pointer_needed
+      || get_frame_size () != 0
+      || current_function_pretend_args_size
+      || current_function_args_size
+      || current_function_outgoing_args_size
+      || current_function_calls_eh_return
+
+      /* If we're not supposed to emit prologue and epilogue, we must
+        not emit return-type instructions.  */
+      || !TARGET_PROLOGUE_EPILOGUE)
+    return 0;
+
+  /* We allow a "movem [sp+],rN" to sit in front if the "jump [sp+]" or
+     in the delay-slot of the "ret".  */
+  for (regno = 0; regno < reglimit; regno++)
+    if ((regs_ever_live[regno] && ! call_used_regs[regno])
+       || (regno == PIC_OFFSET_TABLE_REGNUM
+           && (current_function_uses_pic_offset_table
+               /* It is saved anyway, if there would be a gap.  */
+               || (flag_pic
+                   && regs_ever_live[regno + 1]
+                   && !call_used_regs[regno + 1]))))
+      {
+       if (lastreg != regno - 1)
+         return 0;
+       lastreg = regno;
+      }
+
+  return 1;
+}
+
+/* The ADDRESS_COST worker.  */
+
+int
+cris_address_cost (x)
+     rtx x;
+{
+  /* The metric to use for the cost-macros is unclear.
+     The metric used here is (the number of cycles needed) / 2,
+     where we consider equal a cycle for a word of code and a cycle to
+     read memory.  */
+
+  /* The cheapest addressing modes get 0, since nothing extra is needed.  */
+  if (BASE_OR_AUTOINCR_P (x))
+    return 0;
+
+  /* An indirect mem must be a DIP.  This means two bytes extra for code,
+     and 4 bytes extra for memory read, i.e.  (2 + 4) / 2.  */
+  if (GET_CODE (x) == MEM)
+    return (2 + 4) / 2;
+
+  /* Assume (2 + 4) / 2 for a single constant; a dword, since it needs
+     an extra DIP prefix and 4 bytes of constant in most cases.
+     For PIC and a symbol with a GOT entry, we double the cost since we
+     add a [rPIC+...] offset.  A GOT-less symbol uses a BDAP prefix
+     equivalent to the DIP prefix for non-PIC, hence the same cost.  */
+  if (CONSTANT_P (x))
+    return flag_pic && cris_got_symbol (x) ? 2 * (2 + 4) / 2 : (2 + 4) / 2;
+
+  /* Handle BIAP and BDAP prefixes.  */
+  if (GET_CODE (x) == PLUS)
+    {
+      rtx tem1 = XEXP (x, 0);
+      rtx tem2 = XEXP (x, 1);
+
+    /* A BIAP is 2 extra bytes for the prefix insn, nothing more.  We
+       recognize the typical MULT which is always in tem1 because of
+       insn canonicalization.  */
+    if ((GET_CODE (tem1) == MULT && BIAP_INDEX_P (tem1))
+       || REG_P (tem1))
+      return 2 / 2;
+
+    /* A BDAP (quick) is 2 extra bytes.  Any constant operand to the
+       PLUS is always found in tem2.  */
+    if (GET_CODE (tem2) == CONST_INT
+       && INTVAL (tem2) < 128 && INTVAL (tem2) >= -128)
+      return 2 / 2;
+
+    /* A BDAP -32768 .. 32767 is like BDAP quick, but with 2 extra
+       bytes.  */
+    if (GET_CODE (tem2) == CONST_INT
+       && CONST_OK_FOR_LETTER_P (INTVAL (tem2), 'L'))
+      return (2 + 2) / 2;
+
+    /* A BDAP with some other constant is 2 bytes extra.  */
+    if (CONSTANT_P (tem2))
+      return (2 + 2 + 2) / 2;
+
+    /* BDAP with something indirect should have a higher cost than
+       BIAP with register.   FIXME: Should it cost like a MEM or more?  */
+    /* Don't need to check it, it's the only one left.
+       FIXME:  There was a REG test missing, perhaps there are others.
+       Think more.  */
+    return (2 + 2 + 2) / 2;
+  }
+
+  /* What else?  Return a high cost.  It matters only for valid
+     addressing modes.  */
+  return 10;
+}
+
+/* Check various objections to the side-effect.  Used in the test-part
+   of an anonymous insn describing an insn with a possible side-effect.
+   Returns nonzero if the implied side-effect is ok.
+
+   code     : PLUS or MULT
+   ops     : An array of rtx:es. lreg, rreg, rval,
+             The variables multop and other_op are indexes into this,
+             or -1 if they are not applicable.
+   lreg     : The register that gets assigned in the side-effect.
+   rreg     : One register in the side-effect expression
+   rval     : The other register, or an int.
+   multop   : An integer to multiply rval with.
+   other_op : One of the entities of the main effect,
+             whose mode we must consider.  */
+
+int
+cris_side_effect_mode_ok (code, ops, lreg, rreg, rval, multop, other_op)
+     enum rtx_code code;
+     rtx *ops;
+     int lreg, rreg, rval, multop, other_op;
+{
+  /* Find what value to multiply with, for rx =ry + rz * n.  */
+  int mult = multop < 0 ? 1 : INTVAL (ops[multop]);
+
+  rtx reg_rtx = ops[rreg];
+  rtx val_rtx = ops[rval];
+
+  /* The operands may be swapped.  Canonicalize them in reg_rtx and
+     val_rtx, where reg_rtx always is a reg (for this constraint to
+     match).  */
+  if (! BASE_P (reg_rtx))
+    reg_rtx = val_rtx, val_rtx = ops[rreg];
+
+  /* Don't forget to check that reg_rtx really is a reg.  If it isn't,
+     we have no business.  */
+  if (! BASE_P (reg_rtx))
+    return 0;
+
+  /* Don't do this when -mno-split.  */
+  if (!TARGET_SIDE_EFFECT_PREFIXES)
+    return 0;
+
+  /* The mult expression may be hidden in lreg.  FIXME:  Add more
+     commentary about that.  */
+  if (GET_CODE (val_rtx) == MULT)
+    {
+      mult = INTVAL (XEXP (val_rtx, 1));
+      val_rtx = XEXP (val_rtx, 0);
+      code = MULT;
+    }
+
+  /* First check the "other operand".  */
+  if (other_op >= 0)
+    {
+      if (GET_MODE_SIZE (GET_MODE (ops[other_op])) > UNITS_PER_WORD)
+       return 0;
+
+      /* Check if the lvalue register is the same as the "other
+        operand".  If so, the result is undefined and we shouldn't do
+        this.  FIXME:  Check again.  */
+      if ((BASE_P (ops[lreg])
+          && BASE_P (ops[other_op])
+          && REGNO (ops[lreg]) == REGNO (ops[other_op]))
+         || rtx_equal_p (ops[other_op], ops[lreg]))
+      return 0;
+    }
+
+  /* Do not accept frame_pointer_rtx as any operand.  */
+  if (ops[lreg] == frame_pointer_rtx || ops[rreg] == frame_pointer_rtx
+      || ops[rval] == frame_pointer_rtx
+      || (other_op >= 0 && ops[other_op] == frame_pointer_rtx))
+    return 0;
+
+  if (code == PLUS
+      && ! BASE_P (val_rtx))
+    {
+
+      /* Do not allow rx = rx + n if a normal add or sub with same size
+        would do.  */
+      if (rtx_equal_p (ops[lreg], reg_rtx)
+         && GET_CODE (val_rtx) == CONST_INT
+         && (INTVAL (val_rtx) <= 63 && INTVAL (val_rtx) >= -63))
+       return 0;
+
+      /* Check allowed cases, like [r(+)?].[bwd] and const.
+        A symbol is not allowed with PIC.  */
+      if (CONSTANT_P (val_rtx))
+       return flag_pic == 0 || cris_symbol (val_rtx) == 0;
+
+      if (GET_CODE (val_rtx) == MEM
+         && BASE_OR_AUTOINCR_P (XEXP (val_rtx, 0)))
+       return 1;
+
+      if (GET_CODE (val_rtx) == SIGN_EXTEND
+         && GET_CODE (XEXP (val_rtx, 0)) == MEM
+         && BASE_OR_AUTOINCR_P (XEXP (XEXP (val_rtx, 0), 0)))
+       return 1;
+
+      /* If we got here, it's not a valid addressing mode.  */
+      return 0;
+    }
+  else if (code == MULT
+          || (code == PLUS && BASE_P (val_rtx)))
+    {
+      /* Do not allow rx = rx + ry.S, since it doesn't give better code.  */
+      if (rtx_equal_p (ops[lreg], reg_rtx)
+         || (mult == 1 && rtx_equal_p (ops[lreg], val_rtx)))
+       return 0;
+
+      /* Do not allow bad multiply-values.  */
+      if (mult != 1 && mult != 2 && mult != 4)
+       return 0;
+
+      /* Only allow  r + ...  */
+      if (! BASE_P (reg_rtx))
+       return 0;
+
+      /* If we got here, all seems ok.
+        (All checks need to be done above).  */
+      return 1;
+    }
+
+  /* If we get here, the caller got its initial tests wrong.  */
+  internal_error ("Internal: cris_side_effect_mode_ok with bad operands");
+}
+
+/* The function reg_overlap_mentioned_p in CVS (still as of 2001-05-16)
+   does not handle the case where the IN operand is strict_low_part; it
+   does handle it for X.  Test-case in Axis-20010516.  This function takes
+   care of that for THIS port.  FIXME: strict_low_part is going away
+   anyway.  */
+
+static int
+cris_reg_overlap_mentioned_p (x, in)
+     rtx x, in;
+{
+  /* The function reg_overlap_mentioned now handles when X is
+     strict_low_part, but not when IN is a STRICT_LOW_PART.  */
+  if (GET_CODE (in) == STRICT_LOW_PART)
+    in = XEXP (in, 0);
+
+  return reg_overlap_mentioned_p (x, in);
+}
+
+/* The TARGET_ASM_NAMED_SECTION worker.
+   We just dispatch to the functions for ELF and a.out.  */
+
+void
+cris_target_asm_named_section (name, flags)
+     const char *name;
+     unsigned int flags;
+{
+  if (! TARGET_ELF)
+    default_no_named_section (name, flags);
+  else
+    default_elf_asm_named_section (name, flags);
+}
+
+/* The LEGITIMATE_PIC_OPERAND_P worker.  */
+
+int
+cris_legitimate_pic_operand (x)
+     rtx x;
+{
+  /* The PIC representation of a symbol with a GOT entry will be (for
+     example; relocations differ):
+      sym => [rPIC+sym:GOT]
+     and for a GOT-less symbol it will be (for example, relocation differ):
+      sym => rPIC+sym:GOTOFF
+     so only a symbol with a GOT is by itself a valid operand, and it
+     can't be a sum of a symbol and an offset.  */
+  return ! cris_symbol (x) || cris_got_symbol (x);
+}
+
+/* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+   CONSTANT_P.  */
+
+int
+cris_symbol (x)
+     rtx x;
+{
+  switch (GET_CODE (x))
+    {
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return 1;
+
+    case UNSPEC:
+      /* A PLT reference.  */
+      ASSERT_PLT_UNSPEC (x);
+      return 1;
+
+    case CONST:
+      return cris_symbol (XEXP (x, 0));
+
+    case PLUS:
+    case MINUS:
+      return cris_symbol (XEXP (x, 0)) || cris_symbol (XEXP (x, 1));
+
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONSTANT_P_RTX:
+      return 0;
+
+    default:
+      fatal_insn ("Unrecognized supposed constant", x);
+    }
+
+  return 1;
+}
+
+/* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+   CONSTANT_P, and the symbol does not need a GOT entry.  Also set
+   current_function_uses_pic_offset_table if we're generating PIC and ever
+   see something that would need one.  */
+
+int
+cris_gotless_symbol (x)
+     rtx x;
+{
+  switch (GET_CODE (x))
+    {
+    case UNSPEC:
+      ASSERT_PLT_UNSPEC (x);
+      return 1;
+
+    case SYMBOL_REF:
+      if (flag_pic && cfun != NULL)
+       current_function_uses_pic_offset_table = 1;
+      return SYMBOL_REF_FLAG (x);
+
+    case LABEL_REF:
+      /* We don't set current_function_uses_pic_offset_table for
+        LABEL_REF:s in here, since they are almost always originating
+        from some branch.  The only time it does not come from a label is
+        when GCC does something like __builtin_setjmp.  Then we get the
+        LABEL_REF from the movsi expander, so we mark it there as a
+        special case.  */
+      return 1;
+
+    case CONST:
+      return cris_gotless_symbol (XEXP (x, 0));
+
+    case PLUS:
+    case MINUS:
+      {
+       int x0 = cris_gotless_symbol (XEXP (x, 0)) != 0;
+       int x1 = cris_gotless_symbol (XEXP (x, 1)) != 0;
+
+       /* One and only one of them must be a local symbol.  Neither must
+          be some other, more general kind of symbol.  */
+       return
+         (x0 ^ x1)
+         && ! (x0 == 0 && cris_symbol (XEXP (x, 0)))
+         && ! (x1 == 0 && cris_symbol (XEXP (x, 1)));
+      }
+
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONSTANT_P_RTX:
+      return 0;
+
+    default:
+      fatal_insn ("Unrecognized supposed constant", x);
+    }
+
+  return 1;
+}
+
+/* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+   CONSTANT_P, and the symbol needs a GOT entry.  */
+
+int
+cris_got_symbol (x)
+     rtx x;
+{
+  switch (GET_CODE (x))
+    {
+    case UNSPEC:
+      ASSERT_PLT_UNSPEC (x);
+      return 0;
+
+    case SYMBOL_REF:
+      if (flag_pic && cfun != NULL)
+       current_function_uses_pic_offset_table = 1;
+      return ! SYMBOL_REF_FLAG (x);
+
+    case CONST:
+      return cris_got_symbol (XEXP (x, 0));
+
+    case LABEL_REF:
+      /* A LABEL_REF is never visible as a symbol outside the local
+         function.  */
+    case PLUS:
+    case MINUS:
+      /* Nope, can't access the GOT for "symbol + offset".  */
+      return 0;
+
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONSTANT_P_RTX:
+      return 0;
+
+    default:
+      fatal_insn ("Unrecognized supposed constant in cris_global_pic_symbol",
+                 x);
+    }
+
+  return 1;
+}
+
+/* The OVERRIDE_OPTIONS worker.
+   As is the norm, this also parses -mfoo=bar type parameters.  */
+
+void
+cris_override_options ()
+{
+  if (cris_max_stackframe_str)
+    {
+      cris_max_stackframe = atoi (cris_max_stackframe_str);
+
+      /* Do some sanity checking.  */
+      if (cris_max_stackframe < 0 || cris_max_stackframe > 0x20000000)
+       internal_error ("-max-stackframe=%d is not usable, not between 0 and %d",
+                       cris_max_stackframe, 0x20000000);
+    }
+
+  /* Let "-metrax4" and "-metrax100" change the cpu version.  */
+  if (TARGET_SVINTO && cris_cpu_version < CRIS_CPU_SVINTO)
+    cris_cpu_version = CRIS_CPU_SVINTO;
+  else if (TARGET_ETRAX4_ADD && cris_cpu_version < CRIS_CPU_ETRAX4)
+    cris_cpu_version = CRIS_CPU_ETRAX4;
+
+  /* Parse -march=... and its synonym, the deprecated -mcpu=...  */
+  if (cris_cpu_str)
+    {
+      cris_cpu_version
+       = (*cris_cpu_str == 'v' ? atoi (cris_cpu_str + 1) : -1);
+
+      if (strcmp ("etrax4", cris_cpu_str) == 0)
+       cris_cpu_version = 3;
+
+      if (strcmp ("svinto", cris_cpu_str) == 0
+         || strcmp ("etrax100", cris_cpu_str) == 0)
+       cris_cpu_version = 8;
+
+      if (strcmp ("ng", cris_cpu_str) == 0
+         || strcmp ("etrax100lx", cris_cpu_str) == 0)
+       cris_cpu_version = 10;
+
+      if (cris_cpu_version < 0 || cris_cpu_version > 10)
+       error ("Unknown CRIS version specification in -march= or -mcpu= : %s",
+              cris_cpu_str);
+
+      /* Set the target flags.  */
+      if (cris_cpu_version >= CRIS_CPU_ETRAX4)
+       target_flags |= TARGET_MASK_ETRAX4_ADD;
+
+      /* If this is Svinto or higher, align for 32 bit accesses.  */
+      if (cris_cpu_version >= CRIS_CPU_SVINTO)
+       target_flags
+         |= (TARGET_MASK_SVINTO | TARGET_MASK_ALIGN_BY_32
+             | TARGET_MASK_STACK_ALIGN | TARGET_MASK_CONST_ALIGN
+             | TARGET_MASK_DATA_ALIGN);
+
+      /* Note that we do not add new flags when it can be completely
+        described with a macro that uses -mcpu=X.  So
+        TARGET_HAS_MUL_INSNS is (cris_cpu_version >= CRIS_CPU_NG).  */
+    }
+
+  if (cris_tune_str)
+    {
+      int cris_tune
+       = (*cris_tune_str == 'v' ? atoi (cris_tune_str + 1) : -1);
+
+      if (strcmp ("etrax4", cris_tune_str) == 0)
+       cris_tune = 3;
+
+      if (strcmp ("svinto", cris_tune_str) == 0
+         || strcmp ("etrax100", cris_tune_str) == 0)
+       cris_tune = 8;
+
+      if (strcmp ("ng", cris_tune_str) == 0
+         || strcmp ("etrax100lx", cris_tune_str) == 0)
+       cris_tune = 10;
+
+      if (cris_tune < 0 || cris_tune > 10)
+       error ("Unknown CRIS cpu version specification in -mtune= : %s",
+              cris_tune_str);
+
+      if (cris_tune >= CRIS_CPU_SVINTO)
+       /* We have currently nothing more to tune than alignment for
+          memory accesses.  */
+       target_flags
+         |= (TARGET_MASK_STACK_ALIGN | TARGET_MASK_CONST_ALIGN
+             | TARGET_MASK_DATA_ALIGN | TARGET_MASK_ALIGN_BY_32);
+    }
+
+  if (flag_pic)
+    {
+      /* Use error rather than warning, so invalid use is easily
+        detectable.  Still change to the values we expect, to avoid
+        further errors.  */
+      if (! TARGET_LINUX)
+       {
+         error ("-fPIC not supported in this configuration");
+         flag_pic = 0;
+       }
+
+      /* Turn off function CSE.  We need to have the addresses reach the
+        call expanders to get PLT-marked, as they could otherwise be
+        compared against zero directly or indirectly.  After visiting the
+        call expanders they will then be cse:ed, as the call expanders
+        force_reg the addresses, effectively forcing flag_no_function_cse
+        to 0.  */
+      flag_no_function_cse = 1;
+    }
+
+  if ((write_symbols == DWARF_DEBUG
+       || write_symbols == DWARF2_DEBUG) && ! TARGET_ELF)
+    {
+      warning ("Specified -g option is invalid with -maout and -melinux");
+      write_symbols = DBX_DEBUG;
+    }
+
+  /* Set the per-function-data initializer.  */
+  init_machine_status = cris_init_machine_status;
+}
+
+/* The ASM_OUTPUT_MI_THUNK worker.  */
+
+void
+cris_asm_output_mi_thunk (stream, thunkdecl, delta, funcdecl)
+     FILE *stream;
+     tree thunkdecl ATTRIBUTE_UNUSED;
+     int delta;
+     tree funcdecl;
+{
+  if (delta > 0)
+    asm_fprintf (stream, "\tadd%s %d,$%s\n",
+                ADDITIVE_SIZE_MODIFIER (delta), delta,
+                reg_names[CRIS_FIRST_ARG_REG]);
+  else if (delta < 0)
+    asm_fprintf (stream, "\tsub%s %d,$%s\n",
+                ADDITIVE_SIZE_MODIFIER (-delta), -delta,
+                reg_names[CRIS_FIRST_ARG_REG]);
+
+  if (flag_pic)
+    {
+      const char *name = XSTR (XEXP (DECL_RTL (funcdecl), 0), 0);
+
+      STRIP_NAME_ENCODING (name, name);
+      fprintf (stream, "add.d ");
+      assemble_name (stream, name);
+      fprintf (stream, "%s,$pc\n", CRIS_PLT_PCOFFSET_SUFFIX);
+    }
+  else
+    {
+      fprintf (stream, "jump ");
+      assemble_name (stream, XSTR (XEXP (DECL_RTL (funcdecl), 0), 0));
+      fprintf (stream, "\n");
+    }
+}
+
+/* The EXPAND_BUILTIN_VA_ARG worker.  This is modified from the
+   "standard" implementation of va_arg: read the value from the current
+   address and increment by the size of one or two registers.  The
+   important difference for CRIS is that if the type is
+   pass-by-reference, then perform an indirection.  */
+
+rtx
+cris_expand_builtin_va_arg (valist, type)
+     tree valist;
+     tree type;
+{
+  tree addr_tree, t;
+  rtx addr;
+  enum machine_mode mode = TYPE_MODE (type);
+  int passed_size;
+
+  /* Get AP.  */
+  addr_tree = valist;
+
+  /* Check if the type is passed by value or by reference.  */
+  if (MUST_PASS_IN_STACK (mode, type)
+      || CRIS_FUNCTION_ARG_SIZE (mode, type) > 8)
+    {
+      tree type_ptr = build_pointer_type (type);
+      addr_tree = build1 (INDIRECT_REF, type_ptr, addr_tree);
+      passed_size = 4;
+    }
+  else
+    passed_size = (CRIS_FUNCTION_ARG_SIZE (mode, type) > 4) ? 8 : 4;
+
+  addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
+  addr = copy_to_reg (addr);
+
+  /* Compute new value for AP.  */
+  t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+            build (PLUS_EXPR, TREE_TYPE (valist), valist,
+                   build_int_2 (passed_size, 0)));
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  return addr;
+}
+
+/* The INIT_EXPANDERS worker sets the per-function-data initializer and
+   mark functions.  */
+
+void
+cris_init_expanders ()
+{
+  /* Nothing here at the moment.  */
+}
+
+/* Zero initialization is OK for all current fields.  */
+
+static void
+cris_init_machine_status (p)
+     struct function *p;
+{
+  p->machine = xcalloc (1, sizeof (struct machine_function));
+}
+
+/* Split a 2 word move (DI or presumably DF) into component parts.
+   Originally a copy of gen_split_move_double in m32r.c.  */
+
+rtx
+cris_split_movdx (operands)
+     rtx *operands;
+{
+  enum machine_mode mode = GET_MODE (operands[0]);
+  rtx dest = operands[0];
+  rtx src  = operands[1];
+  rtx val;
+
+  /* We might have (SUBREG (MEM)) here, so just get rid of the
+     subregs to make this code simpler.  It is safe to call
+     alter_subreg any time after reload.  */
+  if (GET_CODE (dest) == SUBREG)
+    dest = alter_subreg (dest);
+  if (GET_CODE (src) == SUBREG)
+    src = alter_subreg (src);
+
+  start_sequence ();
+  if (GET_CODE (dest) == REG)
+    {
+      int dregno = REGNO (dest);
+
+      /* Reg-to-reg copy.  */
+      if (GET_CODE (src) == REG)
+       {
+         int sregno = REGNO (src);
+
+         int reverse = (dregno == sregno + 1);
+
+         /* We normally copy the low-numbered register first.  However, if
+            the first register operand 0 is the same as the second register of
+            operand 1, we must copy in the opposite order.  */
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 operand_subword (dest, reverse, TRUE, mode),
+                                 operand_subword (src, reverse, TRUE, mode)));
+
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 operand_subword (dest, !reverse, TRUE, mode),
+                                 operand_subword (src, !reverse, TRUE, mode)));
+       }
+      /* Constant-to-reg copy.  */
+      else if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
+       {
+         rtx words[2];
+         split_double (src, &words[0], &words[1]);
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 operand_subword (dest, 0, TRUE, mode),
+                                 words[0]));
+
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 operand_subword (dest, 1, TRUE, mode),
+                                 words[1]));
+       }
+      /* Mem-to-reg copy.  */
+      else if (GET_CODE (src) == MEM)
+       {
+         /* If the high-address word is used in the address, we must load it
+            last.  Otherwise, load it first.  */
+         rtx addr = XEXP (src, 0);
+         int reverse
+           = (refers_to_regno_p (dregno, dregno + 1, addr, NULL) != 0);
+
+         /* The original code imples that we can't do
+            move.x [rN+],rM  move.x [rN],rM+1
+            when rN is dead, because of REG_NOTES damage.  That is
+            consistent with what I've seen, so don't try it.
+
+             We have two different cases here; if the addr is POST_INC,
+             just pass it through, otherwise add constants.  */
+
+          if (GET_CODE (addr) == POST_INC)
+           {
+             emit_insn (gen_rtx_SET (VOIDmode, 
+                                     operand_subword (dest, 0, TRUE, mode),
+                                     change_address (src, SImode, addr)));
+             emit_insn (gen_rtx_SET (VOIDmode,
+                                     operand_subword (dest, 1, TRUE, mode), 
+                                     change_address (src, SImode, addr)));
+           }
+         else
+           {
+             /* Make sure we don't get any other addresses with
+                embedded postincrements.  They should be stopped in
+                GO_IF_LEGITIMATE_ADDRESS, but we're here for your
+                safety.  */
+             if (side_effects_p (addr))
+               fatal_insn ("Unexpected side-effects in address", addr);
+
+             emit_insn (gen_rtx_SET
+                        (VOIDmode,
+                         operand_subword (dest, reverse, TRUE, mode),
+                         change_address
+                         (src, SImode,
+                          plus_constant (addr,
+                                         reverse * UNITS_PER_WORD))));
+             emit_insn (gen_rtx_SET
+                        (VOIDmode,
+                         operand_subword (dest, ! reverse, TRUE, mode),
+                         change_address
+                         (src, SImode,
+                          plus_constant (addr,
+                                         (! reverse) *
+                                         UNITS_PER_WORD))));
+           }
+       }
+      else
+       abort ();
+    }
+  /* Reg-to-mem copy or clear mem.  */
+  else if (GET_CODE (dest) == MEM
+          && (GET_CODE (src) == REG
+              || src == const0_rtx
+              || src == CONST0_RTX (DFmode)))
+    {
+      rtx addr = XEXP (dest, 0);
+
+      if (GET_CODE (addr) == POST_INC)
+       {
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 change_address (dest, SImode, addr),
+                                 operand_subword (src, 0, TRUE, mode)));
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 change_address (dest, SImode, addr),
+                                 operand_subword (src, 1, TRUE, mode)));
+       }
+      else
+       {
+         /* Make sure we don't get any other addresses with embedded
+            postincrements.  They should be stopped in
+            GO_IF_LEGITIMATE_ADDRESS, but we're here for your safety.  */
+         if (side_effects_p (addr))
+           fatal_insn ("Unexpected side-effects in address", addr);
+
+         emit_insn (gen_rtx_SET
+                    (VOIDmode,
+                     change_address (dest, SImode, addr),
+                     operand_subword (src, 0, TRUE, mode)));
+
+         emit_insn (gen_rtx_SET
+                    (VOIDmode,
+                     change_address (dest, SImode,
+                                     plus_constant (addr,
+                                                    UNITS_PER_WORD)),
+                     operand_subword (src, 1, TRUE, mode)));
+       }
+    }
+
+  else
+    abort ();
+
+  val = gen_sequence ();
+  end_sequence ();
+  return val;
+}
+
+/* This is in essence a copy of output_addr_const altered to output
+   symbolic operands as PIC.
+
+   FIXME: Add hooks similar to ASM_OUTPUT_SYMBOL_REF to get this effect in
+   the "real" output_addr_const.  All we need is one for LABEL_REF (and
+   one for CODE_LABEL?).  */
+
+void
+cris_output_addr_const (file, x)
+     FILE *file;
+     rtx x;
+{
+  int is_plt = 0;
+
+restart:
+  switch (GET_CODE (x))
+    {
+    case UNSPEC:
+      ASSERT_PLT_UNSPEC (x);
+      x = XVECEXP (x, 0, 0);
+      is_plt = 1;
+
+      /* Fall through.  */
+    case SYMBOL_REF:
+      if (flag_pic)
+       {
+         const char *origstr = XSTR (x, 0);
+         const char *str;
+
+         STRIP_NAME_ENCODING (str, origstr);
+
+         if (is_plt)
+           {
+             if (cris_pic_sympart_only)
+               {
+                 assemble_name (file, str);
+                 fprintf (file, ":PLTG");
+               }
+             else
+               {
+                 if (TARGET_AVOID_GOTPLT)
+                   /* We shouldn't get here.  */
+                   abort ();
+
+                 fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+                 assemble_name (file, XSTR (x, 0));
+
+                 if (flag_pic == 1)
+                   fprintf (file, ":GOTPLT16]");
+                 else
+                   fprintf (file, ":GOTPLT]");
+               }
+           }
+         else if (cris_gotless_symbol (x))
+           {
+             if (! cris_pic_sympart_only)
+               fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+             assemble_name (file, str);
+             fprintf (file, ":GOTOFF");
+           }
+         else if (cris_got_symbol (x))
+           {
+             if (cris_pic_sympart_only)
+               abort ();
+             fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+             assemble_name (file, XSTR (x, 0));
+
+             if (flag_pic == 1)
+               fprintf (file, ":GOT16]");
+             else
+               fprintf (file, ":GOT]");
+           }
+         else
+           fatal_insn ("Unexpected PIC symbol", x);
+
+         /* Sanity check.  */
+         if (! current_function_uses_pic_offset_table)
+           internal_error ("Emitting PIC operand, but PIC register isn't set up");
+       }
+      else
+       assemble_name (file, XSTR (x, 0));
+      break;
+
+    case LABEL_REF:
+      /* If we get one of those here, it should be dressed as PIC.  Branch
+        labels are normally output with the 'l' specifier, which means it
+        will go directly to output_asm_label and not end up here.  */
+      if (GET_CODE (XEXP (x, 0)) != CODE_LABEL
+         && (GET_CODE (XEXP (x, 0)) != NOTE
+             || NOTE_LINE_NUMBER (XEXP (x, 0)) != NOTE_INSN_DELETED_LABEL))
+       fatal_insn ("Unexpected address expression", x);
+
+      if (flag_pic)
+       {
+         if (cris_gotless_symbol (x))
+           {
+             if (! cris_pic_sympart_only)
+               fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+             cris_output_addr_const (file, XEXP (x, 0));
+
+             fprintf (file, ":GOTOFF");
+           }
+         else
+           /* Labels are never marked as global symbols.  */
+           fatal_insn ("Unexpected PIC symbol", x);
+
+         /* Sanity check.  */
+         if (! current_function_uses_pic_offset_table)
+           internal_error ("Emitting PIC operand, but PIC register isn't set up");
+         break;
+       }
+
+      output_addr_const (file, x);
+      break;
+
+    case NOTE:
+      if (NOTE_LINE_NUMBER (x) != NOTE_INSN_DELETED_LABEL)
+       fatal_insn ("Unexpected NOTE as addr_const:", x);
+    case CODE_LABEL:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case ZERO_EXTEND:
+    case SIGN_EXTEND:
+      output_addr_const (file, x);
+      break;
+
+    case CONST:
+      /* This used to output parentheses around the expression,
+        but that does not work on the 386 (either ATT or BSD assembler).  */
+      cris_output_addr_const (file, XEXP (x, 0));
+      break;
+
+    case PLUS:
+      /* Some assemblers need integer constants to appear last (eg masm).  */
+      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+       {
+         cris_output_addr_const (file, XEXP (x, 1));
+         if (INTVAL (XEXP (x, 0)) >= 0)
+           fprintf (file, "+");
+         output_addr_const (file, XEXP (x, 0));
+       }
+      else
+       {
+         cris_output_addr_const (file, XEXP (x, 0));
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT
+             || INTVAL (XEXP (x, 1)) >= 0)
+           fprintf (file, "+");
+         cris_output_addr_const (file, XEXP (x, 1));
+       }
+      break;
+
+    case MINUS:
+      /* Avoid outputting things like x-x or x+5-x,
+        since some assemblers can't handle that.  */
+      x = simplify_subtraction (x);
+      if (GET_CODE (x) != MINUS)
+       goto restart;
+
+      cris_output_addr_const (file, XEXP (x, 0));
+      fprintf (file, "-");
+      if ((GET_CODE (XEXP (x, 1)) == CONST_INT
+          && INTVAL (XEXP (x, 1)) < 0)
+         || GET_CODE (XEXP (x, 1)) != CONST_INT)
+       {
+         fprintf (file, "%s", targetm.asm_out.open_paren);
+         cris_output_addr_const (file, XEXP (x, 1));
+         fprintf (file, "%s", targetm.asm_out.close_paren);
+       }
+      else
+       output_addr_const (file, XEXP (x, 1));
+      break;
+
+    default:
+      fatal_insn ("Unexpected address expression", x);
+    }
+}
+
+/* The ENCODE_SECTION_INFO worker.  Code-in whether we can get away
+   without a GOT entry (needed for externally visible objects but not for
+   functions) into SYMBOL_REF_FLAG and add the PLT suffix for global
+   functions.  */
+
+void
+cris_encode_section_info (exp)
+     tree exp;
+{
+  if (flag_pic)
+    {
+      if (DECL_P (exp))
+       {
+         if (TREE_CODE (exp) == FUNCTION_DECL
+             && (TREE_PUBLIC (exp) || DECL_WEAK (exp)))
+           SYMBOL_REF_FLAG (XEXP (DECL_RTL (exp), 0)) = 0;
+         else
+           SYMBOL_REF_FLAG (XEXP (DECL_RTL (exp), 0))
+             = ! TREE_PUBLIC (exp) && ! DECL_WEAK (exp);
+       }
+      else
+       /* Others are local entities.  */
+       SYMBOL_REF_FLAG (XEXP (TREE_CST_RTL (exp), 0)) = 1;
+    }
+}
+
+#if 0
+/* Various small functions to replace macros.  Only called from a
+   debugger.  They might collide with gcc functions or system functions,
+   so only emit them when '#if 1' above.  */
+
+enum rtx_code Get_code PARAMS ((rtx));
+
+enum rtx_code
+Get_code (x)
+     rtx x;
+{
+  return GET_CODE (x);
+}
+
+const char *Get_mode PARAMS ((rtx));
+
+const char *
+Get_mode (x)
+     rtx x;
+{
+  return GET_MODE_NAME (GET_MODE (x));
+}
+
+rtx Xexp PARAMS ((rtx, int));
+
+rtx
+Xexp (x, n)
+     rtx x;
+     int n;
+{
+  return XEXP (x, n);
+}
+
+rtx Xvecexp PARAMS ((rtx, int, int));
+
+rtx
+Xvecexp (x, n, m)
+     rtx x;
+     int n;
+{ 
+  return XVECEXP (x, n, m);
+}
+
+int Get_rtx_len PARAMS ((rtx));
+
+int
+Get_rtx_len (x)
+     rtx x;
+{
+  return GET_RTX_LENGTH (GET_CODE (x));
+}
+
+/* Use upper-case to distinguish from local variables that are sometimes
+   called next_insn and prev_insn.  */
+
+rtx Next_insn PARAMS ((rtx));
+
+rtx
+Next_insn (insn)
+     rtx insn;
+{
+  return NEXT_INSN (insn);
+}
+
+rtx Prev_insn PARAMS ((rtx));
+
+rtx
+Prev_insn (insn)
+     rtx insn;
+{
+  return PREV_INSN (insn);
+}
+#endif
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/gcc/config/cris/cris.h b/gcc/config/cris/cris.h
new file mode 100644 (file)
index 0000000..ccba9ae
--- /dev/null
@@ -0,0 +1,1937 @@
+/* Definitions for GCC.  Part of the machine description for CRIS.
+   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by Axis Communications.  Written by Hans-Peter Nilsson.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* After the first "Node:" comment comes all preprocessor directives and
+   attached declarations described in the info files, the "Using and
+   Porting GCC" manual (uapgcc), in the same order as found in the "Target
+   macros" section in the gcc-2.9x CVS edition of 2000-03-17.  FIXME: Not
+   really, but needs an update anyway.
+
+   There is no generic copy-of-uapgcc comment, you'll have to see uapgcc
+   for that.  If applicable, there is a CRIS-specific comment.  The order
+   of macro definitions follow the order in the manual.  Every section in
+   the manual (node in the info pages) has an introductory `Node:
+   <subchapter>' comment.  If no macros are defined for a section, only
+   the section-comment is present.  */
+
+/* Note that other header files (e.g. config/elfos.h, config/linux.h,
+   config/cris/linux.h and config/cris/aout.h) are responsible for lots of
+   settings not repeated below.  This file contains general CRIS
+   definitions and definitions for the cris-*-elf subtarget.  */
+
+/* Replacement for REG_P since it does not match SUBREGs.  Happens for
+   testcase Axis-20000320 with gcc-2.9x.  */
+#define REG_S_P(x) \
+ (REG_P (x) || (GET_CODE (x) == SUBREG && REG_P (XEXP (x, 0))))
+
+/* Last register in main register bank r0..r15.  */
+#define CRIS_LAST_GENERAL_REGISTER 15
+
+/* Descriptions of registers used for arguments.  */
+#define CRIS_FIRST_ARG_REG 10
+#define CRIS_MAX_ARGS_IN_REGS 4
+
+/* Other convenience definitions.  */
+#define CRIS_PC_REGNUM 15
+#define CRIS_SRP_REGNUM 16
+
+/* Most of the time, we need the index into the register-names array.
+   When passing debug-info, we need the real register number.  */
+#define CRIS_CANONICAL_SRP_REGNUM (16 + 11)
+#define CRIS_CANONICAL_MOF_REGNUM (16 + 7)
+
+/* When generating PIC, these suffixes are added to the names of non-local
+   functions when being output.  Contrary to other ports, we have offsets
+   relative to the GOT, not the PC.  We might implement PC-relative PLT
+   semantics later for the general case; they are used in some cases right
+   now, such as MI thunks.  */
+#define CRIS_GOTPLT_SUFFIX ":GOTPLT"
+#define CRIS_PLT_GOTOFFSET_SUFFIX ":PLTG"
+#define CRIS_PLT_PCOFFSET_SUFFIX ":PLT"
+
+#define CRIS_FUNCTION_ARG_SIZE(MODE, TYPE)     \
+  ((MODE) != BLKmode ? GET_MODE_SIZE (MODE)    \
+   : (unsigned) int_size_in_bytes (TYPE))
+
+/* Check for max allowed stackframe. A "const char *" to be parsed.  */
+extern const char *cris_max_stackframe_str;
+
+/* Which CPU version this is.  A "const char *" to be parsed.  */
+extern const char *cris_cpu_str;
+
+/* Which CPU version this is.  The parsed and adjusted cris_cpu_str.  */
+extern int cris_cpu_version;
+
+/* Which CPU version to tune for.  A "const char *" to be parsed.  */
+extern const char *cris_tune_str;
+
+/* The argument to "-melinux-stacksize=".  We don't parse it currently;
+   it's just passed on to the linker.  We might want to do something
+   here someday.  */
+extern const char *cris_elinux_stacksize_str;
+
+/* Changing the order used to be necessary to put the fourth __make_dp
+   argument (a DImode parameter) in registers, to fit with the libfunc
+   parameter passing scheme used for intrinsic functions.  FIXME: Check
+   performance and maybe remove definition from TARGET_LIBGCC2_CFLAGS now
+   that it isn't strictly necessary.  We used to do this through
+   TARGET_LIBGCC2_CFLAGS, but that became increasingly difficult as the
+   parenthesis (that needed quoting) travels through several layers of
+   make and shell invocations.  */
+#ifdef IN_LIBGCC2
+#define __make_dp(a,b,c,d) __cris_make_dp(d,a,b,c)
+#endif
+
+
+/* Node: Driver */
+
+/* When using make with defaults.mak for Sun this will handily remove
+   any "-target sun*" switches.  */
+/* We need to override any previous definitions (linux.h) */
+#undef WORD_SWITCH_TAKES_ARG
+#define WORD_SWITCH_TAKES_ARG(STR)             \
+ (DEFAULT_WORD_SWITCH_TAKES_ARG (STR)          \
+  || !strcmp (STR, "target"))
+
+/* Also provide canonical vN definitions when user specifies an alias.
+   Note that -melf overrides -maout.  */
+
+/* The `-$' is here mostly due to the integrated preprocessor not
+   handling the builtin expansion of "#define __REGISTER_PREFIX__ $"
+   gracefully.  This is slightly redundant although not incorrect.
+   We're quite alone defining REGISTER_PREFIX as "$" so it's unlikely
+   someone will fight for us.  This year in the mountains.
+   Note that for -melinux and -mlinux, command-line -isystem options are
+   emitted both before and after the synthesized one.  We can't remove all
+   of them: a %{<isystem} will only remove the first one and %{<isystem*}
+   will not do TRT.  Those extra occurences are harmless anyway.  */
+#define CPP_SPEC \
+ "-$ -D__CRIS_ABI_version=2\
+  %{mtune=*:-D__tune_%* %{mtune=v*:-D__CRIS_arch_tune=%*}}\
+   %{mtune=etrax4:-D__tune_v3 -D__CRIS_arch_tune=3}\
+   %{mtune=etrax100:-D__tune_v8 -D__CRIS_arch_tune=8}\
+   %{mtune=svinto:-D__tune_v8 -D__CRIS_arch_tune=8}\
+   %{mtune=etrax100lx:-D__tune_v10 -D__CRIS_arch_tune=10}\
+   %{mtune=ng:-D__tune_v10 -D__CRIS_arch_tune=10}\
+  %{mcpu=*:-D__arch_%* %{mcpu=v*:-D__CRIS_arch_version=%*}}\
+   %{mcpu=etrax4:-D__arch_v3 -D__CRIS_arch_version=3}\
+   %{mcpu=etrax100:-D__arch_v8 -D__CRIS_arch_version=8}\
+   %{mcpu=svinto:-D__arch_v8 -D__CRIS_arch_version=8}\
+   %{mcpu=etrax100lx:-D__arch_v10 -D__CRIS_arch_version=10}\
+   %{mcpu=ng:-D__arch_v10 -D__CRIS_arch_version=10}\
+  %{march=*:-D__arch_%* %{march=v*:-D__CRIS_arch_version=%*}}\
+   %{march=etrax4:-D__arch_v3 -D__CRIS_arch_version=3}\
+   %{march=etrax100:-D__arch_v8 -D__CRIS_arch_version=8}\
+   %{march=svinto:-D__arch_v8 -D__CRIS_arch_version=8}\
+   %{march=etrax100lx:-D__arch_v10 -D__CRIS_arch_version=10}\
+   %{march=ng:-D__arch_v10 -D__CRIS_arch_version=10}\
+  %{metrax100:-D__arch__v8 -D__CRIS_arch_version=8}\
+  %{metrax4:-D__arch__v3 -D__CRIS_arch_version=3}\
+  %(cpp_subtarget)"
+
+/* For the cris-*-elf subtarget.  */
+#define CRIS_CPP_SUBTARGET_SPEC \
+ "-D__ELF__\
+  %{mbest-lib-options:\
+   %{!moverride-best-lib-options:\
+    %{!march=*:%{!metrax*:%{!mcpu=*:-D__tune_v10 -D__CRIS_arch_tune=10}}}}}"
+
+/* Remove those Sun-make "target" switches.  */
+/* Override previous definitions (linux.h).  */
+#undef CC1_SPEC
+#define CC1_SPEC \
+ "%{target*:}\
+  %{metrax4:-march=v3}\
+  %{metrax100:-march=v8}\
+  %(cc1_subtarget)"
+
+/* For the cris-*-elf subtarget.  */
+#define CRIS_CC1_SUBTARGET_SPEC \
+ "-melf\
+  %{mbest-lib-options:\
+   %{!moverride-best-lib-options:\
+    %{!march=*:%{!mcpu=*:-mtune=v10 -D__CRIS_arch_tune=10}}\
+    %{!finhibit-size-directive:\
+      %{!fno-function-sections: -ffunction-sections}\
+      %{!fno-data-sections: -fdata-sections}}}}"
+
+/* This adds to CC1_SPEC.  When bugs are removed from -fvtable-gc
+   (-fforce-addr causes invalid .vtable_entry asm in tinfo.cc and
+   nothing at all works in GCC 3.0-pre), add this line:
+   "%{mbest-lib-options:%{!moverride-best-lib-options:\
+   %{!melinux:%{!maout|melf:%{!fno-vtable-gc:-fvtable-gc}}}}}".  */
+#define CC1PLUS_SPEC ""
+
+/* Override previous definitions (linux.h).  */
+#undef ASM_SPEC
+#define ASM_SPEC \
+ "%{v:-v}\
+  %(asm_subtarget)"
+
+/* For the cris-*-elf subtarget.  */
+#define CRIS_ASM_SUBTARGET_SPEC "--em=criself"
+
+/* FIXME: We should propagate the -melf option to make the criself
+   "emulation" unless a linker script is provided (-T*), but I don't know
+   how to do that if either of -Ttext, -Tdata or -Tbss is given but no
+   linker script, as is usually the case.  Leave it to the user for the
+   time being.
+
+   Note that -melf overrides -maout except that a.out-compiled libraries
+   are linked in (multilibbing).  The somewhat cryptic -rpath-link pair is
+   to avoid *only* picking up the linux multilib subdir from the "-B./"
+   option during build, while still giving it preference.  We'd need some
+   %s-variant that checked for existance of some specific file.  */
+/* Override previous definitions (svr4.h).  */
+#undef LINK_SPEC
+#define LINK_SPEC \
+ "%{v:--verbose}\
+  %(link_subtarget)" 
+
+/* For the cris-*-elf subtarget.  */
+#define CRIS_LINK_SUBTARGET_SPEC \
+ "-mcriself\
+  %{sim2:%{!T*:-Tdata 0x4000000 -Tbss 0x8000000}}\
+  %{O2|O3: --gc-sections}"
+
+/* Which library to get.  The only difference from the default is to get
+   libsc.a if -sim is given to the driver.  Repeat -lc -lsysX
+   {X=sim,linux}, because libsysX needs (at least) errno from libc, and
+   then we want to resolve new unknowns in libc against libsysX, not
+   libnosys.  */
+/* Override previous definitions (linux.h).  */
+#undef LIB_SPEC
+#define LIB_SPEC \
+ "%{sim*:-lc -lsyssim -lc -lsyssim}\
+  %{!sim*:%{g*:-lg}\
+    %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} -lbsp}\
+  -lnosys"
+
+/* Linker startfile options; crt0 flavors.
+
+   At the moment there are no gcrt0.o or mcrt0.o, but keep them here and
+   link them to crt0.o to be prepared.  Use scrt0.c if running the
+   simulator, linear style, or s2crt0.c if fixed style.  */
+/* We need to remove any previous definition (elfos.h).  */
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+ "%{sim2:s2crt0.o%s}\
+  %{!sim2:%{sim:scrt0.o%s}\
+   %{!sim:%{pg:gcrt0.o%s}\
+    %{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}}\
+  crtbegin.o%s"
+
+#define EXTRA_SPECS                            \
+  {"cpp_subtarget", CRIS_CPP_SUBTARGET_SPEC},  \
+  {"cc1_subtarget", CRIS_CC1_SUBTARGET_SPEC},  \
+  {"asm_subtarget", CRIS_ASM_SUBTARGET_SPEC},  \
+  {"link_subtarget", CRIS_LINK_SUBTARGET_SPEC},        \
+  CRIS_SUBTARGET_EXTRA_SPECS
+
+#define CRIS_SUBTARGET_EXTRA_SPECS
+
+
+/* Node: Run-time Target */
+
+/* Only keep the non-varying ones here.  */
+#define CPP_PREDEFINES "-Dcris -DCRIS -DGNU_CRIS"
+
+/* This needs to be at least 32 bits.  */
+extern int target_flags;
+
+/* Currently this just affects aligment.  FIXME:  Redundant with
+   TARGET_ALIGN_BY_32, or put machine stuff here?  */
+#define TARGET_MASK_SVINTO 1
+#define TARGET_SVINTO (target_flags & TARGET_MASK_SVINTO)
+
+/* If to use condition-codes generated by insns other than the
+   immediately preceding compare/test insn.
+    Used to check for errors in notice_update_cc. */
+#define TARGET_MASK_CCINIT 2
+#define TARGET_CCINIT (target_flags & TARGET_MASK_CCINIT)
+
+/* Debug option.  */
+#define TARGET_MASK_PDEBUG 4
+#define TARGET_PDEBUG (target_flags & TARGET_MASK_PDEBUG)
+
+/* If to use side-effect patterns.  Used to debug the [rx=ry+i] type
+   patterns.  */
+#define TARGET_MASK_SIDE_EFFECT_PREFIXES 8
+#define TARGET_SIDE_EFFECT_PREFIXES \
+ (target_flags & TARGET_MASK_SIDE_EFFECT_PREFIXES)
+
+/* If to expand mul into mstep.  Only used when making libc.a.  */
+#define TARGET_MASK_EXPAND_MUL 16
+#define TARGET_EXPAND_MUL (target_flags & TARGET_MASK_EXPAND_MUL)
+
+/* If to *keep* (not force) alignment of stack at 16 bits.  */
+#define TARGET_MASK_STACK_ALIGN 32
+#define TARGET_STACK_ALIGN (target_flags & TARGET_MASK_STACK_ALIGN)
+
+/* If to do alignment on individual non-modifiable objects.  */
+#define TARGET_MASK_CONST_ALIGN 64
+#define TARGET_CONST_ALIGN (target_flags & TARGET_MASK_CONST_ALIGN)
+
+/* If to do alignment on individual modifiable objects.  */
+#define TARGET_MASK_DATA_ALIGN 128
+#define TARGET_DATA_ALIGN (target_flags & TARGET_MASK_DATA_ALIGN)
+
+/* If not to omit funtion prologue and epilogue.  */
+#define TARGET_MASK_PROLOGUE_EPILOGUE 256
+#define TARGET_PROLOGUE_EPILOGUE (target_flags & TARGET_MASK_PROLOGUE_EPILOGUE)
+
+/* Instructions additions from Etrax 4 and up.
+   (Just "lz", which we don't really generate from GCC -- yet).  */
+#define TARGET_MASK_ETRAX4_ADD 512
+#define TARGET_ETRAX4_ADD (target_flags & TARGET_MASK_ETRAX4_ADD)
+
+/* Say that all alignment specifications say to prefer 32 rather
+   than 16 bits.  */
+#define TARGET_MASK_ALIGN_BY_32 1024
+#define TARGET_ALIGN_BY_32 (target_flags & TARGET_MASK_ALIGN_BY_32)
+
+/* This condition is of limited use, as gcc is riddled with #ifdef:s
+   controlling this, rather than if (...):s.  */
+#define TARGET_MASK_ELF 2048
+#define TARGET_ELF (target_flags & TARGET_MASK_ELF)
+
+/* Currently just used to error-check other options.  Note that this is
+   *not* set for -melinux.  */
+#define TARGET_MASK_LINUX 4096
+#define TARGET_LINUX (target_flags & TARGET_MASK_LINUX)
+
+/* There's a small setup cost with using GOTPLT references, but should
+   in total be a win both in code-size and execution-time.  */
+#define TARGET_MASK_AVOID_GOTPLT 8192
+#define TARGET_AVOID_GOTPLT (target_flags & TARGET_MASK_AVOID_GOTPLT)
+
+#define TARGET_SWITCHES                                                        \
+ {                                                                     \
+  /* No "no-etrax" as it does not really imply any model.              \
+     On the other hand, "etrax" implies the common (and large)         \
+     subset matching all models.  */                                   \
+  {"etrax4",                            TARGET_MASK_ETRAX4_ADD,        \
+   N_("Compile for ETRAX 4 (CRIS v3)")},                               \
+  {"no-etrax4",                                -TARGET_MASK_ETRAX4_ADD, ""},   \
+  {"etrax100",                      (TARGET_MASK_SVINTO                \
+                                     + TARGET_MASK_ETRAX4_ADD          \
+                                     + TARGET_MASK_ALIGN_BY_32),       \
+   N_("Compile for ETRAX 100 (CRIS v8)")},                             \
+  {"no-etrax100",                  -(TARGET_MASK_SVINTO                \
+                                     + TARGET_MASK_ETRAX4_ADD), ""},   \
+  {"pdebug",                                TARGET_MASK_PDEBUG,        \
+   N_("Emit verbose debug information in assembly code")},             \
+  {"no-pdebug",                                    -TARGET_MASK_PDEBUG, ""},   \
+  {"cc-init",                               TARGET_MASK_CCINIT,        \
+   N_("Do not use condition codes from normal instructions")},         \
+  {"no-cc-init",                           -TARGET_MASK_CCINIT, ""},   \
+  {"side-effects",            TARGET_MASK_SIDE_EFFECT_PREFIXES, ""},   \
+  {"no-side-effects",        -TARGET_MASK_SIDE_EFFECT_PREFIXES,        \
+   N_("Do not emit addressing modes with side-effect assignment")},    \
+  {"stack-align",                      TARGET_MASK_STACK_ALIGN, ""},   \
+  {"no-stack-align",                  -TARGET_MASK_STACK_ALIGN,        \
+   N_("Do not tune stack alignment")},                                 \
+  {"data-align",                        TARGET_MASK_DATA_ALIGN, ""},   \
+  {"no-data-align",                    -TARGET_MASK_DATA_ALIGN,        \
+   N_("Do not tune writable data alignment")},                         \
+  {"const-align",                      TARGET_MASK_CONST_ALIGN, ""},   \
+  {"no-const-align",                  -TARGET_MASK_CONST_ALIGN,        \
+   N_("Do not tune code and read-only data alignment")},               \
+  {"32-bit",                       (TARGET_MASK_STACK_ALIGN            \
+                                    + TARGET_MASK_CONST_ALIGN          \
+                                    + TARGET_MASK_DATA_ALIGN           \
+                                    + TARGET_MASK_ALIGN_BY_32), ""},   \
+  {"32bit",                        (TARGET_MASK_STACK_ALIGN            \
+                                    + TARGET_MASK_CONST_ALIGN          \
+                                    + TARGET_MASK_DATA_ALIGN           \
+                                    + TARGET_MASK_ALIGN_BY_32),        \
+   N_("Align code and data to 32 bits")},                              \
+  {"16-bit",                        (TARGET_MASK_STACK_ALIGN           \
+                                     + TARGET_MASK_CONST_ALIGN         \
+                                     + TARGET_MASK_DATA_ALIGN), ""},   \
+  {"16bit",                         (TARGET_MASK_STACK_ALIGN           \
+                                     + TARGET_MASK_CONST_ALIGN         \
+                                     + TARGET_MASK_DATA_ALIGN), ""},   \
+  {"8-bit",                        -(TARGET_MASK_STACK_ALIGN           \
+                                     + TARGET_MASK_CONST_ALIGN         \
+                                     + TARGET_MASK_DATA_ALIGN), ""},   \
+  {"8bit",                         -(TARGET_MASK_STACK_ALIGN           \
+                                     + TARGET_MASK_CONST_ALIGN         \
+                                     + TARGET_MASK_DATA_ALIGN),        \
+   N_("Don't align items in code or data")},                           \
+  {"prologue-epilogue",                  TARGET_MASK_PROLOGUE_EPILOGUE, ""},   \
+  {"no-prologue-epilogue",      -TARGET_MASK_PROLOGUE_EPILOGUE,        \
+   N_("Do not emit function prologue or epilogue")},                   \
+  /* We have to handle this m-option here since we can't wash it off in \
+     both CC1_SPEC and CC1PLUS_SPEC.  */                               \
+  {"best-lib-options",                                       0,        \
+ N_("Use the most feature-enabling options allowed by other options")},        \
+                                                                       \
+  /* We must call it "override-" since calling it "no-" will cause     \
+     gcc.c to forget it, if there's a "later" -mbest-lib-options.      \
+     Kludgy, but needed for some multilibbed files.  */                        \
+  {"override-best-lib-options",                                      0,        \
+   N_("Override -mbest-lib-options")},                                 \
+  CRIS_SUBTARGET_SWITCHES                                              \
+  {"",                 TARGET_DEFAULT | CRIS_SUBTARGET_DEFAULT, ""}}   \
+
+/* For the cris-*-elf subtarget.  */
+#define CRIS_SUBTARGET_SWITCHES \
+ {"elf", 0, ""},
+
+/* Default target_flags if no switches specified.  */
+#ifndef TARGET_DEFAULT
+# define TARGET_DEFAULT \
+ (TARGET_MASK_SIDE_EFFECT_PREFIXES + TARGET_MASK_STACK_ALIGN \
+  + TARGET_MASK_CONST_ALIGN + TARGET_MASK_DATA_ALIGN \
+  + TARGET_MASK_PROLOGUE_EPILOGUE)
+#endif
+
+/* For the cris-*-elf subtarget.  */
+#define CRIS_SUBTARGET_DEFAULT TARGET_MASK_ELF
+
+#define CRIS_CPU_BASE 0
+#define CRIS_CPU_ETRAX4 3      /* Just lz added.  */
+#define CRIS_CPU_SVINTO 8      /* Added swap, jsrc & Co., 32-bit accesses.  */
+#define CRIS_CPU_NG 10         /* Added mul[su].  */
+
+/* Local, providing a default for cris_cpu_version.  */
+#define CRIS_DEFAULT_CPU_VERSION CRIS_CPU_BASE
+
+#define TARGET_HAS_MUL_INSNS (cris_cpu_version >= CRIS_CPU_NG)
+
+#define TARGET_OPTIONS                                                 \
+ {{"cpu=", &cris_cpu_str, ""},                                         \
+  {"arch=", &cris_cpu_str,                                             \
+   N_("Generate code for the specified chip or CPU version")},         \
+  {"tune=", &cris_tune_str,                                            \
+   N_("Tune alignment for the specified chip or CPU version")},                \
+  {"max-stackframe=", &cris_max_stackframe_str,                                \
+   N_("Warn when a stackframe is larger than the specified size")},    \
+  CRIS_SUBTARGET_LONG_OPTIONS                                          \
+  {"ax-stackframe=", &cris_max_stackframe_str, ""}}
+
+#define CRIS_SUBTARGET_LONG_OPTIONS
+
+/* Print subsidiary information on the compiler version in use.
+   Do not use VD.D syntax (D=digit), since this will cause confusion
+   with the base gcc version among users, when we ask which version of
+   gcc-cris they are using.  Please use some flavor of "R<number>" for
+   the version (no need for major.minor versions, I believe).  */
+#define TARGET_VERSION \
+ fprintf (stderr, " [Axis CRIS release R36a%s]", CRIS_SUBTARGET_VERSION)
+
+/* For the cris-*-elf subtarget.  */
+#define CRIS_SUBTARGET_VERSION " - generic ELF"
+
+#define OVERRIDE_OPTIONS cris_override_options ()
+
+/* The following gives optimal code for gcc-2.7.2, but *may* be subject
+   to change.  Omitting flag_force_addr gives .1-.7% faster code for gcc
+   *only*, but 1.3% larger code.  On ipps it gives 5.3-10.6% slower
+   code(!) and 0.3% larger code.  For products, images gets .1-1.8%
+   larger.  Do not set strict aliasing from optimization options.  */
+#define OPTIMIZATION_OPTIONS(OPTIMIZE, SIZE)   \
+  do                                           \
+    {                                          \
+      if ((OPTIMIZE) >= 2 || (SIZE))           \
+       {                                       \
+         flag_force_addr =                     \
+           flag_omit_frame_pointer = 1;        \
+       }                                       \
+      flag_strict_aliasing = 0;                        \
+    }                                          \
+  while (0)
+
+
+/* Node: Storage Layout */
+
+#define BITS_BIG_ENDIAN 0
+
+#define BYTES_BIG_ENDIAN 0
+
+/* WORDS_BIG_ENDIAN is not defined in the hardware, but for consistency,
+   we use little-endianness, and we may also be able to use
+   post-increment on DImode indirect.  */
+#define WORDS_BIG_ENDIAN 0
+
+#define BITS_PER_UNIT 8
+
+#define BITS_PER_WORD 32
+
+#define UNITS_PER_WORD 4
+
+#define POINTER_SIZE 32
+
+/* A combination of defining PROMOTE_MODE, PROMOTE_FUNCTION_ARGS,
+   PROMOTE_FOR_CALL_ONLY and *not* defining PROMOTE_PROTOTYPES gives the
+   best code size and speed for gcc, ipps and products in gcc-2.7.2.  */
+#define CRIS_PROMOTED_MODE(MODE, UNSIGNEDP, TYPE) \
+ (GET_MODE_CLASS (MODE) == MODE_INT && GET_MODE_SIZE (MODE) < 4) \
+  ? SImode : MODE
+
+#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE)  \
+  (MODE) = CRIS_PROMOTED_MODE (MODE, UNSIGNEDP, TYPE)
+
+#define PROMOTE_FUNCTION_ARGS
+
+/* Defining PROMOTE_FUNCTION_RETURN in gcc-2.7.2 uncovers bug 981110 (even
+   if defining FUNCTION_VALUE with MODE as PROMOTED_MODE ;-)
+
+   FIXME: Report this when cris.h is part of GCC, so others can easily
+   see the problem.  Maybe check other systems that define
+   PROMOTE_FUNCTION_RETURN.  */
+#define PROMOTE_FOR_CALL_ONLY
+
+/* We will be using prototype promotion, so they will be 32 bit.  */
+#define PARM_BOUNDARY 32
+
+/* Stack boundary is guided by -mstack-align, -mno-stack-align,
+   -malign.
+   Old comment: (2.1: still valid in 2.7.2?)
+    Note that to make this macro affect the alignment of stack
+   locals, a fix was required, and special precautions when handling
+   the stack pointer in various other macros (FUNCTION_PROLOGUE et al)
+   were required.  See file "function.c".  If you would just define
+   this macro, it would only affect the builtin alloca and variable
+   local data (non-ANSI, non-K&R, Gnu C extension).  */
+#define STACK_BOUNDARY \
+ (TARGET_STACK_ALIGN ? (TARGET_ALIGN_BY_32 ? 32 : 16) : 8)
+
+#define FUNCTION_BOUNDARY 16
+
+/* Do not change BIGGEST_ALIGNMENT (when optimizing), as it will affect
+   strange places, at least in 2.1. */
+#define BIGGEST_ALIGNMENT 8
+
+/* If -m16bit, -m16-bit, -malign or -mdata-align,
+   align everything to 16 bit. */
+#define DATA_ALIGNMENT(TYPE, BASIC_ALIGN)                      \
+ (TARGET_DATA_ALIGN                                            \
+  ? (TARGET_ALIGN_BY_32                                                \
+     ? (BASIC_ALIGN < 32 ? 32 : BASIC_ALIGN)                   \
+     : (BASIC_ALIGN < 16 ? 16 : BASIC_ALIGN)) : BASIC_ALIGN)
+
+/* Note that CONSTANT_ALIGNMENT has the effect of making gcc believe that
+   ALL references to constant stuff (in code segment, like strings) has
+   this alignment.  That is a rather rushed assumption.  Luckily we do not
+   care about the "alignment" operand to builtin memcpy (only place where
+   it counts), so it doesn't affect any bad spots.  */
+#define CONSTANT_ALIGNMENT(CONSTANT, BASIC_ALIGN)              \
+ (TARGET_CONST_ALIGN                                           \
+  ? (TARGET_ALIGN_BY_32                                                \
+     ? (BASIC_ALIGN < 32 ? 32 : BASIC_ALIGN)                   \
+     : (BASIC_ALIGN < 16 ? 16 : BASIC_ALIGN)) : BASIC_ALIGN)
+
+/* FIXME: Define LOCAL_ALIGNMENT for word and dword or arrays and
+   structures (if -mstack-align=), and check that it is good.  */
+
+#define EMPTY_FIELD_BOUNDARY 8
+
+#define STRUCTURE_SIZE_BOUNDARY 8
+
+#define STRICT_ALIGNMENT 0
+
+/* Remove any previous definition (elfos.h).
+   ??? If it wasn't for all the other stuff that affects layout of
+   structures and bit-fields, this could presumably cause incompatibility
+   with other GNU/Linux ports (i.e. elfos.h users).  */
+#undef PCC_BITFIELD_TYPE_MATTERS
+
+/* This is only used for non-scalars.  Strange stuff happens to structs
+   (FIXME: What?) if we use anything larger than largest actually used
+   datum size, so lets make it 32.  The type "long long" will still work
+   as usual.  We can still have DImode insns, but they will only be used
+   for scalar data (i.e. long long).  */
+#define MAX_FIXED_MODE_SIZE 32
+
+
+/* Node: Type Layout */
+
+/* Note that DOUBLE_TYPE_SIZE is not defined anymore, since the default
+   value gives a 64-bit double, which is what we now use.  */
+
+/* For compatibility and historical reasons, a char should be signed.  */
+#define DEFAULT_SIGNED_CHAR 1
+
+/* No DEFAULT_SHORT_ENUMS, please.  */
+
+/* Note that WCHAR_TYPE_SIZE is used in cexp.y,
+   where TARGET_SHORT is not available.  */
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 32
+
+
+/* Node: Register Basics */
+
+/*  We count all 16 non-special registers, SRP and a faked argument
+    pointer register.  */
+#define FIRST_PSEUDO_REGISTER (16 + 1 + 1)
+
+/* For CRIS, these are r15 (pc) and r14 (sp). Register r8 is used as a
+   frame-pointer, but is not fixed.  SRP is not included in general
+   registers and will not be used automatically.  All other special
+   registers are fixed at the moment.  The faked argument pointer register
+   is fixed too.  */
+#define FIXED_REGISTERS \
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1}
+
+/* Register r9 is used for structure-address, r10-r13 for parameters,
+   r10- for return values.  */
+#define CALL_USED_REGISTERS \
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1}
+
+#define CONDITIONAL_REGISTER_USAGE cris_conditional_register_usage ()
+
+
+/* Node: Allocation Order */
+
+/* We need this on CRIS, because call-used regs should be used first,
+   (so we dont need to push).  Else start using registers from r0 and up.
+    This preference is mainly because if we put call-used-regs from r0
+   and up, then we can't use movem to push the rest, (which have to be
+   saved if we use them, and movem has to start with r0).
+   Change here if you change which registers to use as call registers.
+
+   The actual need to explicitly prefer call-used registers improved the
+   situation a lot for 2.1, but might not actually be needed anymore.
+   Still, this order reflects what GCC should find out by itself, so it
+   probably does not hurt.
+
+   Order of preference: Call-used-regs first, then r0 and up, last fp &
+   sp & pc as fillers.
+   Call-used regs in opposite order, so they will cause less conflict if
+   a function has few args (<= 3) and it wants a scratch reg.
+    Use struct-return address first, since very few functions use
+   structure return values so it is likely to be available.  */
+#define REG_ALLOC_ORDER \
+ {9, 13, 12, 11, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15, 16, 17}
+
+
+/* Node: Values in Registers */
+
+/* The VOIDmode test is so we can omit mode on anonymous insns.  FIXME:
+   Still needed in 2.9x, at least for Axis-20000319.  */
+#define HARD_REGNO_NREGS(REGNO, MODE)  \
+ (MODE == VOIDmode \
+  ? 1 : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+/* CRIS permits all registers to hold all modes.  */
+#define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+
+#define MODES_TIEABLE_P(MODE1, MODE2)  1
+
+
+/* Node: Leaf Functions */
+/* (no definitions) */
+
+/* Node: Stack Registers */
+/* (no definitions) */
+
+
+/* Node: Register Classes */
+
+/* CRIS has only one kind of registers, so NO_REGS and ALL_REGS
+   are the only classes.  FIXME: It actually makes sense to have another
+   class for special registers, and yet another class for the
+   multiply-overflow register in v10; then a class for the return
+   register also makes sense.  */
+enum reg_class {NO_REGS, ALL_REGS, LIM_REG_CLASSES};
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+#define REG_CLASS_NAMES {"NO_REGS", "ALL_REGS"}
+
+#define GENERAL_REGS ALL_REGS
+
+/* Count in the faked argument register in GENERAL_REGS.  Keep out SRP.  */
+#define REG_CLASS_CONTENTS {{0}, {0x2ffff}}
+
+#define REGNO_REG_CLASS(REGNO) GENERAL_REGS
+
+#define BASE_REG_CLASS GENERAL_REGS
+
+#define INDEX_REG_CLASS GENERAL_REGS
+
+/* Get reg_class from a letter such as appears in the machine
+   description.  No letters are used, since 'r' is used for any
+   register.  */
+#define REG_CLASS_FROM_LETTER(C) NO_REGS
+
+/* Since it uses reg_renumber, it is safe only once reg_renumber
+   has been allocated, which happens in local-alloc.c.  */
+#define REGNO_OK_FOR_BASE_P(REGNO)                                     \
+ ((REGNO) <= CRIS_LAST_GENERAL_REGISTER                                        \
+  || (REGNO) == ARG_POINTER_REGNUM                                     \
+  || (unsigned) reg_renumber[REGNO] <= CRIS_LAST_GENERAL_REGISTER      \
+  || (unsigned) reg_renumber[REGNO] == ARG_POINTER_REGNUM)
+
+/* See REGNO_OK_FOR_BASE_P.  */
+#define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO)
+
+/* It seems like gcc (2.7.2 and 2.9x of 2000-03-22) may send "NO_REGS" as
+   the class for a constant (testcase: __Mul in arit.c).  To avoid forcing
+   out a constant into the constant pool, we will trap this case and
+   return something a bit more sane.  FIXME: Check if this is a bug.  */
+#define PREFERRED_RELOAD_CLASS(X, CLASS) \
+ ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS))
+
+/* For CRIS, this is always the size of MODE in words,
+   since all registers are the same size.  To use omitted modes in
+   patterns with reload constraints, you must say the widest size
+   which is allowed for VOIDmode.
+   FIXME:  Does that still apply for gcc-2.9x?  Keep poisoned until such
+   patterns are added back.  News: 2001-03-16: Happens as early as the
+   underscore-test.  */
+#define CLASS_MAX_NREGS(CLASS, MODE)                                   \
+ ((MODE) == VOIDmode                                                   \
+  ? 1 /* + cris_fatal ("CLASS_MAX_NREGS with VOIDmode")        */              \
+  : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+/* We are now out of letters; we could use ten more.  This forces us to
+   use C-code in the 'md' file.  FIXME: Use some EXTRA_CONSTRAINTS.  */
+#define CONST_OK_FOR_LETTER_P(VALUE, C)                        \
+ (                                                     \
+  /* MOVEQ, CMPQ, ANDQ, ORQ.  */                       \
+  (C) == 'I' ? (VALUE) >= -32 && (VALUE) <= 31 :       \
+  /* ADDQ, SUBQ.  */                                   \
+  (C) == 'J' ? (VALUE) >= 0 && (VALUE) <= 63 :         \
+  /* ASRQ, BTSTQ, LSRQ, LSLQ.  */                      \
+  (C) == 'K' ? (VALUE) >= 0 && (VALUE) <= 31 :         \
+  /* A 16-bit signed number.  */                       \
+  (C) == 'L' ? (VALUE) >= -32768 && (VALUE) <= 32767 : \
+  /* The constant 0 for CLEAR.  */                     \
+  (C) == 'M' ? (VALUE) == 0 :                          \
+  /* A negative ADDQ or SUBQ.  */                      \
+  (C) == 'N' ? (VALUE) >= -63 && (VALUE) < 0 :         \
+  /* Quickened ints, QI and HI.  */                    \
+  (C) == 'O' ? (VALUE) >= 0 && (VALUE) <= 65535                \
+               && ((VALUE) >= (65535-31)               \
+                   || ((VALUE) >= (255-31)             \
+                       && (VALUE) <= 255 )) :          \
+  /* A 16-bit number signed *or* unsigned.  */         \
+  (C) == 'P' ? (VALUE) >= -32768 && (VALUE) <= 65535 : \
+  0)
+
+/* It is really simple to make up a 0.0; it is the same as int-0 in
+   IEEE754. */
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C)                 \
+ ((C) == 'G' && ((VALUE) == CONST0_RTX (DFmode)                        \
+                || (VALUE) == CONST0_RTX (SFmode)))
+
+/* We need this on cris to distinguish delay-slottable addressing modes.  */
+#define EXTRA_CONSTRAINT(X, C)                 \
+ (                                             \
+  /* Slottable address mode?  */               \
+  (C) == 'Q' ? EXTRA_CONSTRAINT_Q (X) :                \
+  /* Operand to BDAP or BIAP?  */              \
+  (C) == 'R' ? EXTRA_CONSTRAINT_R (X) :                \
+  /* A local PIC symbol?  */                   \
+  (C) == 'S' ? EXTRA_CONSTRAINT_S (X) :                \
+  /* A three-address addressing-mode?  */      \
+  (C) == 'T' ? EXTRA_CONSTRAINT_T (X) :                \
+  /* A global PIC symbol?  */                  \
+  (C) == 'U' ? EXTRA_CONSTRAINT_U (X) :                \
+  0)
+
+#define EXTRA_CONSTRAINT_Q(X)                          \
+ (                                                     \
+  /* Slottable addressing modes:                       \
+     A register?  FIXME: Unnecessary.  */              \
+  (BASE_P (X) && REGNO (X) != CRIS_PC_REGNUM)          \
+  /* Indirect register: [reg]?  */                     \
+  || (GET_CODE (X) == MEM && BASE_P (XEXP (X, 0))      \
+      && REGNO (XEXP (X, 0)) != CRIS_PC_REGNUM)                \
+ )
+
+#define EXTRA_CONSTRAINT_R(X)                                  \
+ (                                                             \
+  /* An operand to BDAP or BIAP:                               \
+     A BIAP; r.S? */                                           \
+  BIAP_INDEX_P (X)                                             \
+  /* A [reg] or (int) [reg], maybe with post-increment.  */    \
+  || BDAP_INDEX_P (X)                                          \
+  || CONSTANT_INDEX_P (X)                                      \
+ )
+
+/* FIXME: Bug below: We can't have XEXP (X, 0)) both be MEM and a
+   CONSTANT_P.  Parens don't match indentation.  */
+
+#define EXTRA_CONSTRAINT_T(X)                                          \
+ (                                                                     \
+  /* Three-address-operands.  All are indirect-memory:  */             \
+  GET_CODE (X) == MEM                                                  \
+  && ((GET_CODE (XEXP (X, 0)) == MEM                                   \
+  /* Double indirect: [[reg]] or [[reg+]]?  */                         \
+  && (BASE_OR_AUTOINCR_P (XEXP (XEXP (X, 0), 0))))                     \
+      /* Just an explicite indirect reference: [const]?  */            \
+      || CONSTANT_P (XEXP (X, 0))                                      \
+      /* Something that is indexed; [...+...]?  */                     \
+      || (GET_CODE (XEXP (X, 0)) == PLUS                               \
+         /* A BDAP constant: [reg+(8|16|32)bit offset]?  */            \
+         && ((BASE_P (XEXP (XEXP (X, 0), 0))                           \
+              && CONSTANT_INDEX_P (XEXP (XEXP (X, 0), 1)))             \
+             /* Swap arguments to the above.  FIXME: gcc-2.9x? */      \
+             || (BASE_P (XEXP (XEXP (X, 0), 1))                        \
+                 && CONSTANT_INDEX_P (XEXP (XEXP (X, 0), 0)))          \
+             /* A BDAP register: [reg+[reg(+)].S]?  */                 \
+             || (BASE_P (XEXP (XEXP (X, 0), 0))                        \
+                 && BDAP_INDEX_P(XEXP(XEXP(X, 0), 1)))                 \
+             /* Same, but with swapped arguments.  */                  \
+             || (BASE_P (XEXP (XEXP (X, 0), 1))                        \
+                 && BDAP_INDEX_P (XEXP (XEXP (X, 0), 0)))              \
+             /* A BIAP: [reg+reg.S].  */                               \
+             || (BASE_P (XEXP (XEXP (X, 0), 0))                        \
+                 && BIAP_INDEX_P (XEXP (XEXP (X, 0), 1)))              \
+             /* Same, but with swapped arguments.  */                  \
+             || (BASE_P (XEXP (XEXP (X, 0), 1))                        \
+                 && BIAP_INDEX_P (XEXP (XEXP (X, 0), 0))))))           \
+ )
+
+#define EXTRA_CONSTRAINT_S(X) \
+ (flag_pic && CONSTANT_P (X) && cris_gotless_symbol (X))
+
+#define EXTRA_CONSTRAINT_U(X) \
+ (flag_pic && CONSTANT_P (X) && cris_got_symbol (X))
+
+
+/* Node: Frame Layout */
+
+#define STACK_GROWS_DOWNWARD
+#define FRAME_GROWS_DOWNWARD
+
+/* It seems to be indicated in the code (at least 2.1) that this is
+   better a constant, and best 0.  */
+#define STARTING_FRAME_OFFSET 0
+
+#define FIRST_PARM_OFFSET(FNDECL) 0
+
+#define RETURN_ADDR_RTX(COUNT, FRAMEADDR) \
+ cris_return_addr_rtx (COUNT, FRAMEADDR)
+
+#define INCOMING_RETURN_ADDR_RTX gen_rtx (REG, Pmode, CRIS_SRP_REGNUM)
+
+/* FIXME: Any __builtin_eh_return callers must not return anything and
+   there must not be collisions with incoming parameters.  Luckily the
+   number of __builtin_eh_return callers is limited.  For now return
+   parameter registers in reverse order and hope for the best.  */
+#define EH_RETURN_DATA_REGNO(N) \
+  (((N) >= 0 && (N) < 4) ? (CRIS_FIRST_ARG_REG + 3 - (N)) : INVALID_REGNUM)
+
+/* Store the stack adjustment in the structure-return-address register.  */
+#define CRIS_STACKADJ_REG STRUCT_VALUE_REGNUM
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (SImode, CRIS_STACKADJ_REG)
+
+#define EH_RETURN_HANDLER_RTX \
+  cris_return_addr_rtx (0, NULL)
+
+#define INIT_EXPANDERS cris_init_expanders ()
+
+/* FIXME: Move this to right node (it's not documented properly yet).  */
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (CRIS_SRP_REGNUM)
+
+/* FIXME: Move this to right node (it's not documented properly yet).
+   FIXME: Check what alignment we can assume regarding
+   TARGET_STACK_ALIGN and TARGET_ALIGN_BY_32.  */
+#define DWARF_CIE_DATA_ALIGNMENT -1
+
+/* If we would ever need an exact mapping between canonical register
+   number and dwarf frame register, we would either need to include all
+   registers in the gcc decription (with some marked fixed of course), or
+   an inverse mapping from dwarf register to gcc register.  There is one
+   need in dwarf2out.c:expand_builtin_init_dwarf_reg_sizes.  Right now, I
+   don't see that we need exact correspondence between DWARF *frame*
+   registers and DBX_REGISTER_NUMBER, so map them onto GCC registers.  */
+#define DWARF_FRAME_REGNUM(REG) (REG)
+
+/* Node: Stack Checking */
+/* (no definitions) FIXME: Check.  */
+
+/* Node: Frame Registers */
+
+#define STACK_POINTER_REGNUM 14
+
+/* Register used for frame pointer.  This is also the last of the saved
+   registers, when a frame pointer is not used. */
+#define FRAME_POINTER_REGNUM 8
+
+/* Faked register, is always eliminated.  We need it to eliminate
+   allocating stack slots for the return address and the frame pointer.  */
+#define ARG_POINTER_REGNUM 17
+
+#define STATIC_CHAIN_REGNUM 7
+
+
+/* Node: Elimination */
+
+/* Really only needed if the stack frame has variable length (alloca
+   or variable sized local arguments (GNU C extension).  */
+#define FRAME_POINTER_REQUIRED 0
+
+#define ELIMINABLE_REGS                                \
+ {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},  \
+  {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},  \
+  {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+
+/* We need not worry about when the frame-pointer is required for other
+   reasons.  */
+#define CAN_ELIMINATE(FROM, TO) 1
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ (OFFSET) = cris_initial_elimination_offset (FROM, TO)
+
+
+/* Node: Stack Arguments */
+
+/* Since many parameters take up one register each in any case,
+   PROMOTE_PROTOTYPES would seem like a good idea, but measurements
+   indicate that a combination using PROMOTE_MODE is better.  */
+
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0
+
+
+/* Node: Register Arguments */
+
+/* The void_type_node is sent as a "closing" call.  We have to stop it
+   since it's invalid to FUNCTION_ARG_PASS_BY_REFERENCE (or was invalid at
+   some time).  */
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED)                   \
+ ((CUM).regs < CRIS_MAX_ARGS_IN_REGS                           \
+  && (TYPE) != void_type_node                                  \
+  && ! FUNCTION_ARG_PASS_BY_REFERENCE (CUM, MODE, TYPE, NAMED) \
+  ? gen_rtx (REG, MODE, (CRIS_FIRST_ARG_REG) + (CUM).regs)     \
+  : NULL_RTX)
+
+/* The differences between this and the previous, is that this one checks
+   that an argument is named, since incoming stdarg/varargs arguments are
+   pushed onto the stack, and we don't have to check against the "closing"
+   void_type_node TYPE parameter.  */
+#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED)                  \
+ (((NAMED) && (CUM).regs < CRIS_MAX_ARGS_IN_REGS                       \
+   && ! FUNCTION_ARG_PASS_BY_REFERENCE (CUM, MODE, TYPE, NAMED))       \
+  ? gen_rtx (REG, MODE, CRIS_FIRST_ARG_REG + (CUM).regs)               \
+  : NULL_RTX)
+
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED)     \
+ (((CUM).regs == (CRIS_MAX_ARGS_IN_REGS - 1)                   \
+   && !MUST_PASS_IN_STACK (MODE, TYPE)                         \
+   && CRIS_FUNCTION_ARG_SIZE (MODE, TYPE) > 4                  \
+   && CRIS_FUNCTION_ARG_SIZE (MODE, TYPE) <= 8)                        \
+  ? 1 : 0)
+
+/* Structs may be passed by value, but they must not be more than 8
+   bytes long.  */
+#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED)         \
+ (MUST_PASS_IN_STACK (MODE, TYPE)                                      \
+  || CRIS_FUNCTION_ARG_SIZE (MODE, TYPE) > 8)                          \
+
+/* Contrary to what you'd believe, defining FUNCTION_ARG_CALLEE_COPIES
+   seems like a (small total) loss, at least for gcc-2.7.2 compiling and
+   running gcc-2.1 (small win in size, small loss running -- 100.1%),
+   and similarly for size for products (.1 .. .3% bloat, sometimes win).
+   Due to the empirical likeliness of making slower code, it is not
+   defined.  */
+
+/* This no longer *needs* to be a structure; but keeping it as such should
+   not hurt (and hacking the ABI is simpler).  */
+#define CUMULATIVE_ARGS struct cum_args
+struct cum_args {int regs;};
+
+/* The regs member is an integer, the number of arguments got into
+   registers so far, and lib is nonzero if init_cumulative_args was
+   found to generate a call to a library function.  */
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT)     \
+ ((CUM).regs = 0)
+
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)           \
+ ((CUM).regs                                                   \
+  = (FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED)    \
+     ? (CRIS_MAX_ARGS_IN_REGS) + 1                             \
+     : ((CUM).regs                                             \
+       + (3 + (CRIS_FUNCTION_ARG_SIZE (MODE, TYPE))) / 4)))
+
+#define FUNCTION_ARG_REGNO_P(REGNO)                    \
+ ((REGNO) >= CRIS_FIRST_ARG_REG                                \
+  && (REGNO) < CRIS_FIRST_ARG_REG + (CRIS_MAX_ARGS_IN_REGS))
+
+
+/* Node: Scalar Return */
+
+/* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the
+   time being.  */
+#define FUNCTION_VALUE(VALTYPE, FUNC)  \
+ gen_rtx (REG, TYPE_MODE (VALTYPE), CRIS_FIRST_ARG_REG)
+
+#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, CRIS_FIRST_ARG_REG)
+
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == CRIS_FIRST_ARG_REG)
+
+
+/* Node: Aggregate Return */
+
+#if 0
+/* FIXME: Let's try this some time, so we return structures in registers.
+   We would cast the result of int_size_in_bytes to unsigned, so we will
+   get a huge number for "structures" of variable size (-1).  */
+#define RETURN_IN_MEMORY(TYPE) \
+ ((unsigned) int_size_in_bytes (TYPE) > CRIS_MAX_ARGS_IN_REGS * UNITS_PER_WORD)
+#endif
+
+#define STRUCT_VALUE_REGNUM ((CRIS_FIRST_ARG_REG) - 1)
+
+
+/* Node: Caller Saves */
+/* (no definitions) */
+
+/* Node: Function entry */
+
+/* See cris.c for TARGET_ASM_FUNCTION_PROLOGUE and
+   TARGET_ASM_FUNCTION_EPILOGUE.  */
+
+/* If the epilogue uses the "ret" insn, we need to fill the
+   delay slot.  */
+#define DELAY_SLOTS_FOR_EPILOGUE cris_delay_slots_for_epilogue ()
+
+#define ELIGIBLE_FOR_EPILOGUE_DELAY(INSN, N) \
+  cris_eligible_for_epilogue_delay (INSN)
+
+#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
+ cris_asm_output_mi_thunk(FILE, THUNK_FNDECL, DELTA, FUNCTION)
+
+
+/* Node: Profiling */
+
+#define FUNCTION_PROFILER(FILE, LABELNO)  \
+ error ("No FUNCTION_PROFILER for CRIS")
+
+/* No profiling for the time being.  */
+#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \
+ error ("No FUNCTION_BLOCK_PROFILER for CRIS")
+
+/* No profiling for the time being.  */
+#define BLOCK_PROFILER(FILE, BLOCKNO)  \
+ error ("No BLOCK_PROFILER for CRIS")
+
+/* FIXME: Some of the undefined macros might be mandatory.  If so, fix
+   documentation.  */
+
+
+/* Node: Varargs */
+
+/* We save the register number of the first anonymous argument in
+   first_vararg_reg, and take care of this in the function prologue.
+   This behaviour is used by at least one more port (the ARM?), but
+   may be unsafe when compiling nested functions.  (With varargs? Hairy.)
+   Note that nested-functions is a GNU C extension.
+
+   FIXME: We can actually put the size in PRETEND and deduce the number
+   of registers from it in the prologue and epilogue.  */
+#define SETUP_INCOMING_VARARGS(ARGSSF, MODE, TYPE, PRETEND, SECOND)    \
+  do                                                                   \
+    {                                                                  \
+      if ((ARGSSF).regs < (CRIS_MAX_ARGS_IN_REGS))                     \
+       (PRETEND) = ((CRIS_MAX_ARGS_IN_REGS) - (ARGSSF).regs) * 4;      \
+      if (TARGET_PDEBUG)                                               \
+       {                                                               \
+         fprintf (asm_out_file,                                        \
+                  "\n; VA:: %s: %d args before, anon @ #%d, %dtime\n", \
+                  current_function_varargs ? "OLD" : "ANSI",           \
+                  (ARGSSF).regs, PRETEND, SECOND);                     \
+       }                                                               \
+    }                                                                  \
+  while (0)
+
+/* FIXME: This and other EXPAND_BUILTIN_VA_... target macros are not
+   documented, although used by several targets.  */
+#define EXPAND_BUILTIN_VA_ARG(VALIST, TYPE) \
+ cris_expand_builtin_va_arg (VALIST, TYPE)
+
+
+/* Node: Trampolines */
+
+/* This looks too complicated, and it is.  I assigned r7 to be the
+   static chain register, but it is call-saved, so we have to save it,
+   and come back to restore it after the call, so we have to save srp...
+   Anyway, trampolines are rare enough that we can cope with this
+   somewhat lack of elegance.
+    (Do not be tempted to "straighten up" whitespace in the asms; the
+   assembler #NO_APP state mandates strict spacing). */
+#define TRAMPOLINE_TEMPLATE(FILE)              \
+  do                                           \
+    {                                          \
+      fprintf (FILE, "\tmove.d $%s,[$pc+20]\n",        \
+              reg_names[STATIC_CHAIN_REGNUM]); \
+      fprintf (FILE, "\tmove $srp,[$pc+22]\n");        \
+      fprintf (FILE, "\tmove.d 0,$%s\n",       \
+              reg_names[STATIC_CHAIN_REGNUM]); \
+      fprintf (FILE, "\tjsr 0\n");             \
+      fprintf (FILE, "\tmove.d 0,$%s\n",       \
+              reg_names[STATIC_CHAIN_REGNUM]); \
+      fprintf (FILE, "\tjump 0\n");            \
+    }                                          \
+  while (0)
+
+#define TRAMPOLINE_SIZE 32
+
+/* CRIS wants instructions on word-boundary.
+   Note that due to a bug (reported) in 2.7.2 and earlier, this is
+   actually treated as alignment in _bytes_, not _bits_.  (Obviously
+   this is not fatal, only a slight waste of stack space). */
+#define TRAMPOLINE_ALIGNMENT 16
+
+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT)              \
+  do                                                           \
+    {                                                          \
+      emit_move_insn (gen_rtx (MEM, SImode,                    \
+                              plus_constant (TRAMP, 10)),      \
+                     CXT);                                     \
+      emit_move_insn (gen_rtx (MEM, SImode,                    \
+                              plus_constant (TRAMP, 16)),      \
+                     FNADDR);                                  \
+    }                                                          \
+  while (0)
+
+/* Note that there is no need to do anything with the cache for sake of
+   a trampoline.  */
+
+
+/* Node: Library Calls */
+
+#define MULSI3_LIBCALL "__Mul"
+#define DIVSI3_LIBCALL "__Div"
+#define UDIVSI3_LIBCALL "__Udiv"
+#define MODSI3_LIBCALL "__Mod"
+#define UMODSI3_LIBCALL "__Umod"
+
+/* If you change this, you have to check whatever libraries and systems
+   that use it.  */
+#define TARGET_EDOM 33
+
+
+/* Node: Addressing Modes */
+
+#define HAVE_POST_INCREMENT 1
+
+#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X)
+
+#define MAX_REGS_PER_ADDRESS 2
+
+/* There are helper macros defined here which are used only in
+   GO_IF_LEGITIMATE_ADDRESS.
+
+   Note that you *have to* reject invalid addressing modes for mode
+   MODE, even if it is legal for normal addressing modes.  You cannot
+   rely on the constraints to do this work.  They can only be used to
+   doublecheck your intentions.  One example is that you HAVE TO reject
+   (mem:DI (plus:SI (reg:SI x) (reg:SI y))) because for some reason
+   this cannot be reloaded.  (Which of course you can argue that gcc
+   should have done.)  FIXME:  Strange.  Check.  */
+
+/* No symbol can be used as an index (or more correct, as a base) together
+   with a register with PIC; the PIC register must be there.  */
+#define CONSTANT_INDEX_P(X) \
+ (CONSTANT_P (X) && !(flag_pic && cris_symbol (X)))
+
+/* True if X is a valid base register.  */
+#define BASE_P(X) \
+ (REG_P (X) && REG_OK_FOR_BASE_P (X))
+
+/* True if X is a valid base register with or without autoincrement.  */
+#define BASE_OR_AUTOINCR_P(X) \
+ (BASE_P (X) || (GET_CODE (X) == POST_INC && BASE_P (XEXP (X, 0))))
+
+/* True if X is a valid (register) index for BDAP, i.e. [Rs].S or [Rs+].S.  */
+#define BDAP_INDEX_P(X)                                        \
+ ((GET_CODE (X) == MEM && GET_MODE (X) == SImode       \
+   && BASE_OR_AUTOINCR_P (XEXP (X, 0)))                        \
+  || (GET_CODE (X) == SIGN_EXTEND                      \
+      && GET_CODE (XEXP (X, 0)) == MEM                 \
+      && (GET_MODE (XEXP (X, 0)) == HImode             \
+         || GET_MODE (XEXP (X, 0)) == QImode)          \
+      && BASE_OR_AUTOINCR_P (XEXP (XEXP (X, 0), 0))))
+
+/* True if X is a valid (register) index for BIAP, i.e. Rd.m.  */
+#define BIAP_INDEX_P(X)                                \
+ ((BASE_P (X) && REG_OK_FOR_INDEX_P (X))       \
+  || (GET_CODE (X) == MULT                     \
+      && BASE_P (XEXP (X, 0))                  \
+      && REG_OK_FOR_INDEX_P (XEXP (X, 0))      \
+      && GET_CODE (XEXP (X, 1)) == CONST_INT   \
+      && (INTVAL (XEXP (X, 1)) == 2            \
+         || INTVAL (XEXP (X, 1)) == 4)))
+
+/* True if X is an address that doesn't need a prefix i.e. [Rs] or [Rs+].  */
+#define SIMPLE_ADDRESS_P(X) \
+ (BASE_P (X)                                           \
+  || (GET_CODE (X) == POST_INC                         \
+      && BASE_P (XEXP (X, 0))))
+
+/* A PIC operand looks like a normal symbol here.  At output we dress it
+   in "[rPIC+symbol:GOT]" (global symbol) or "rPIC+symbol:GOTOFF" (local
+   symbol) so we exclude all addressing modes where we can't replace a
+   plain "symbol" with that.  A global PIC symbol does not fit anywhere
+   here (but is thankfully a general_operand in itself).  A local PIC
+   symbol is valid for the plain "symbol + offset" case.  */
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)                        \
+ {                                                             \
+   rtx x1, x2;                                                 \
+   if (SIMPLE_ADDRESS_P (X))                                   \
+     goto ADDR;                                                        \
+   if (CONSTANT_P (X)                                          \
+       && (! flag_pic                                          \
+          || cris_gotless_symbol (X)                           \
+          || ! cris_symbol (X)))                               \
+     goto ADDR;                                                        \
+   /* Indexed?  */                                             \
+   if (GET_CODE (X) == PLUS)                                   \
+     {                                                         \
+       x1 = XEXP (X, 0);                                       \
+       x2 = XEXP (X, 1);                                       \
+       /* BDAP o, Rd.  */                                      \
+       if ((BASE_P (x1) && CONSTANT_INDEX_P (x2))              \
+          || (BASE_P (x2) && CONSTANT_INDEX_P (x1))            \
+           /* BDAP Rs[+], Rd.  */                              \
+          || (GET_MODE_SIZE (MODE) <= UNITS_PER_WORD           \
+              && ((BASE_P (x1) && BDAP_INDEX_P (x2))           \
+                  || (BASE_P (x2) && BDAP_INDEX_P (x1))        \
+                  /* BIAP.m Rs, Rd */                          \
+                  || (BASE_P (x1) && BIAP_INDEX_P (x2))        \
+                  || (BASE_P (x2) && BIAP_INDEX_P (x1)))))     \
+        goto ADDR;                                             \
+     }                                                         \
+   else if (GET_CODE (X) == MEM)                               \
+     {                                                         \
+       /* DIP (Rs).  Reject [[reg+]] and [[reg]] for           \
+         DImode (long long).  */                               \
+       if (GET_MODE_SIZE (MODE) <= UNITS_PER_WORD              \
+          && (BASE_P (XEXP (X, 0))                             \
+              || BASE_OR_AUTOINCR_P (XEXP (X, 0))))            \
+        goto ADDR;                                             \
+     }                                                         \
+ }
+
+#ifndef REG_OK_STRICT
+ /* Nonzero if X is a hard reg that can be used as a base reg
+    or if it is a pseudo reg.  */
+# define REG_OK_FOR_BASE_P(X)                  \
+ (REGNO (X) <= CRIS_LAST_GENERAL_REGISTER      \
+  || REGNO (X) == ARG_POINTER_REGNUM           \
+  || REGNO (X) >= FIRST_PSEUDO_REGISTER)
+#else
+ /* Nonzero if X is a hard reg that can be used as a base reg.  */
+# define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+#endif
+
+#ifndef REG_OK_STRICT
+ /* Nonzero if X is a hard reg that can be used as an index
+    or if it is a pseudo reg.  */
+# define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
+#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))
+#endif
+
+/* For now, don't do anything.  GCC does a good job most often.
+
+    Maybe we could do something about gcc:s misbehaviour when it
+   recalculates frame offsets for local variables, from fp+offs to
+   sp+offs.  The resulting address expression gets screwed up
+   sometimes, but I'm not sure that it may be fixed here, since it is
+   already split up in several instructions (Is this still true?).
+   FIXME: Check and adjust for gcc-2.9x.  */
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) {}
+
+/* Functionality import from EGCS.
+   Kludge to solve Axis-990219: Work around imperfection in
+   reload_load_address1:
+    (plus (sign_extend (mem:qi (reg))) (reg))
+   should be reloaded as (plus (reg) (reg)), not
+    (plus (sign_extend (reg)) (reg)).
+   There are no checks that reload_load_address_1 "reloads"
+   addresses correctly, so invalidness is not caught or
+   corrected.
+    When the right thing happens, the "something_reloaded" kludge can
+   be removed.  The right thing does not appear to happen for
+   EGCS CVS as of this date (above).  */
+
+#define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN) \
+  do                                                                   \
+    {                                                                  \
+      if (GET_CODE (X) == PLUS                                         \
+         && REG_P (XEXP (X, 1))                                        \
+         && GET_CODE (XEXP (X, 0)) == SIGN_EXTEND                      \
+         && GET_CODE (XEXP (XEXP (X, 0), 0)) == MEM                    \
+         && (GET_MODE (XEXP (XEXP (X, 0), 0)) == HImode                \
+             || GET_MODE (XEXP (XEXP (X, 0), 0)) == QImode)            \
+         && (REG_P (XEXP (XEXP (XEXP (X, 0), 0), 0))                   \
+             || (GET_CODE (XEXP (XEXP (XEXP (X, 0), 0), 0))            \
+                 == POST_INC                                           \
+                 && REG_P (XEXP (XEXP (XEXP (XEXP (X, 0), 0), 0),      \
+                                 0)))))                                \
+       {                                                               \
+         int something_reloaded = 0;                                   \
+                                                                       \
+         if (REGNO (XEXP (X, 1)) >= FIRST_PSEUDO_REGISTER)             \
+           {                                                           \
+             /* Second reg is pseudo, reload it. */                    \
+             push_reload (XEXP (X, 1), NULL_RTX, &XEXP (X, 1),         \
+                          NULL,                                        \
+                          GENERAL_REGS, GET_MODE (X), VOIDmode, 0, 0,  \
+                          OPNUM, TYPE);                                \
+             something_reloaded = 1;                                   \
+           }                                                           \
+                                                                       \
+         if (REG_P (XEXP (XEXP (X, 0), 0))                             \
+             && (REGNO (XEXP (XEXP (X, 0), 0))                         \
+                 >= FIRST_PSEUDO_REGISTER))                            \
+           {                                                           \
+             /* First one is a pseudo - reload that. */                \
+             push_reload (XEXP (XEXP (X, 0), 0), NULL_RTX,             \
+                          &XEXP (XEXP (X, 0), 0), NULL,                \
+                          GENERAL_REGS,                                \
+                          GET_MODE (X), VOIDmode, 0, 0, OPNUM, TYPE);  \
+             something_reloaded = 1;                                   \
+           }                                                           \
+                                                                       \
+         if (! something_reloaded                                      \
+             || (GET_CODE (XEXP (XEXP (X, 0), 0)) == POST_INC          \
+                 && (REGNO (XEXP (XEXP (XEXP (X, 0), 0), 0))           \
+                     >= FIRST_PSEUDO_REGISTER)))                       \
+           /* Reload the sign_extend.  Happens if neither reg is a     \
+              pseudo, or the first one was inside post_increment.  */  \
+           push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL,     \
+                        GENERAL_REGS, GET_MODE (X), VOIDmode, 0, 0,    \
+                        OPNUM, TYPE);                                  \
+         goto WIN;                                                     \
+       }                                                               \
+    }                                                                  \
+  while (0)
+
+/* In CRIS, only the postincrement address mode depends thus,
+   since the increment depends on the size of the operand.  */
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)      \
+  do                                                   \
+    {                                                  \
+      if (GET_CODE (ADDR) == POST_INC)                 \
+       goto LABEL;                                     \
+    }                                                  \
+  while (0)
+
+#define LEGITIMATE_CONSTANT_P(X) 1
+
+
+/* Node: Condition Code */
+
+#define NOTICE_UPDATE_CC(EXP, INSN) cris_notice_update_cc (EXP, INSN)
+
+/* FIXME: Maybe define CANONICALIZE_COMPARISON later, when playing with
+   optimizations.  It is needed; currently we do this with instruction
+   patterns and NOTICE_UPDATE_CC.  */
+
+
+/* Node: Costs */
+
+#define CONST_COSTS(RTX, CODE, OUTER_CODE)                             \
+ case CONST_INT:                                                       \
+   if (INTVAL (RTX) == 0)                                              \
+     return 0;                                                         \
+   if (INTVAL (RTX) < 32 && INTVAL (RTX) >= -32)                       \
+     return 1;                                                         \
+   /* Eight or 16 bits are a word and cycle more expensive.  */                \
+   if (INTVAL (RTX) <= 32767 && INTVAL (RTX) >= -32768)                        \
+     return 2;                                                         \
+   /* A 32 bit constant (or very seldom, unsigned 16 bits) costs       \
+      another word.  FIXME: This isn't linear to 16 bits.  */          \
+   return 4;                                                           \
+ case LABEL_REF:                                                       \
+   return 6;                                                           \
+ case CONST:                                                           \
+ case SYMBOL_REF:                                                      \
+   /* For PIC, we need a prefix (if it isn't already there),           \
+      and the PIC register.  For a global PIC symbol, we also need a   \
+      read of the GOT.  */                                             \
+   return                                                              \
+     flag_pic ? (cris_got_symbol (RTX) ? (2 + 4 + 6) : (2 + 6)) : 6;   \
+ case CONST_DOUBLE:                                                    \
+   if (RTX != CONST0_RTX (GET_MODE (RTX) == VOIDmode ? DImode          \
+                         : GET_MODE (RTX)))                            \
+     return 12;                                                                \
+   /* Make 0.0 cheap, else test-insns will not be used.  */            \
+   return 0;
+
+#define RTX_COSTS(X, CODE, OUTER_CODE)                                 \
+ case MULT:                                                            \
+   /* Identify values that are no powers of two.  Powers of 2 are      \
+      taken care of already and those values should not be             \
+      changed.  */                                                     \
+   if (GET_CODE (XEXP (X, 1)) != CONST_INT                             \
+       || exact_log2 (INTVAL (XEXP (X, 1)) < 0))                       \
+     {                                                                 \
+       /* If we have a multiply insn, then the cost is between         \
+          1 and 2 "fast" instructions.  */                             \
+       if (TARGET_HAS_MUL_INSNS)                                       \
+         return COSTS_N_INSNS (1) + COSTS_N_INSNS (1) /2;              \
+                                                                       \
+       /* Estimate as 4 + 4 * #ofbits.  */                             \
+       return COSTS_N_INSNS (132);                                     \
+     }                                                                 \
+     break;                                                            \
+ case UDIV:                                                            \
+ case MOD:                                                             \
+ case UMOD:                                                            \
+ case DIV:                                                             \
+   if (GET_CODE (XEXP (X, 1)) != CONST_INT                             \
+       || exact_log2 (INTVAL (XEXP (X, 1)) < 0))                       \
+     /* Estimate this as 4 + 8 * #of bits.  */                         \
+     return COSTS_N_INSNS (260);                                       \
+                                                                       \
+ case AND:                                                             \
+   if (GET_CODE (XEXP (X, 1)) == CONST_INT                             \
+       /* Two constants may actually happen before optimization.  */   \
+       && GET_CODE (XEXP (X, 0)) != CONST_INT                          \
+       && !CONST_OK_FOR_LETTER_P (INTVAL (XEXP (X, 1)), 'I'))          \
+     return                                                            \
+       rtx_cost (XEXP (X, 0), OUTER_CODE) + 2                          \
+       + 2 * GET_MODE_NUNITS (GET_MODE (XEXP (X, 0)));                 \
+                                                                       \
+ case ZERO_EXTEND: case SIGN_EXTEND:                                   \
+   /* Same as move. If embedded in other insn, cost is 0.  */          \
+   return rtx_cost (XEXP (X, 0), OUTER_CODE);
+
+#define ADDRESS_COST(X) cris_address_cost (X)
+
+/* FIXME: Need to define REGISTER_MOVE_COST when more register classes are
+   introduced.  */
+
+/* This isn't strictly correct for v0..3 in buswidth-8bit mode, but
+   should suffice.  */
+#define MEMORY_MOVE_COST(M, CLASS, IN) \
+ (((M) == QImode) ? 4 : ((M) == HImode) ? 4 : 6)
+
+/* Regardless of the presence of delay slots, the default value of 1 for
+   BRANCH_COST is the best in the range (1, 2, 3), tested with gcc-2.7.2
+   with testcases ipps and gcc, giving smallest and fastest code.  */
+
+#define SLOW_BYTE_ACCESS 0
+
+/* This is the threshold *below* which inline move sequences of
+   word-length sizes will be emitted.  The "9" will translate to
+   (9 - 1) * 4 = 32 bytes maximum moved, but using 16 instructions
+   (8 instruction sequences) or less.  */
+#define MOVE_RATIO 9
+
+
+/* Node: Sections */
+
+#define TEXT_SECTION_ASM_OP "\t.text"
+
+#define DATA_SECTION_ASM_OP "\t.data"
+
+#define FORCE_EH_FRAME_INFO_IN_DATA_SECTION (! TARGET_ELF)
+
+/* The jump table is immediately connected to the preceding insn.  */
+#define JUMP_TABLES_IN_TEXT_SECTION 1
+
+/* We need to code in PIC-specific flags into SYMBOL_REF_FLAG.  */
+
+#define ENCODE_SECTION_INFO(EXP) cris_encode_section_info (EXP)
+
+/* We pull a little trick to register the _fini function with atexit,
+   after (presumably) registering the eh frame info, since we don't handle
+   _fini (a.k.a. ___fini_start) in crt0 or have a crti for "pure" ELF.  */
+#ifdef CRT_BEGIN
+#define FORCE_INIT_SECTION_ALIGN               \
+ do                                            \
+   {                                           \
+     extern void __fini__start (void);         \
+     atexit (__fini__start);                   \
+   }                                           \
+ while (0)
+#endif
+
+/* Node: PIC */
+
+#define PIC_OFFSET_TABLE_REGNUM 0
+
+#define LEGITIMATE_PIC_OPERAND_P(X) cris_legitimate_pic_operand (X)
+
+
+/* Node: File Framework */
+
+/* NO_APP *only at file start* means faster assembly.
+   It also means comments are not allowed.
+   In some cases comments will be output for debugging purposes.
+   Make sure they are allowed then.  */
+/* Override previous definitions (elfos.h).  */
+#undef ASM_FILE_START
+#define ASM_FILE_START(STREAM)                                 \
+  do                                                           \
+    {                                                          \
+      if (TARGET_PDEBUG || flag_print_asm_name)                        \
+       fprintf ((STREAM), "#APP\n");                           \
+      else                                                     \
+       fprintf ((STREAM), "#NO_APP\n");                        \
+      if (TARGET_ELF)                                          \
+       output_file_directive ((STREAM), main_input_filename);  \
+    }                                                          \
+  while (0)
+
+/* Override previous definitions (elfos.h).  */
+#undef ASM_FILE_END
+#define ASM_FILE_END(STREAM)
+
+/* We don't want an .ident for gcc.  To avoid that but still support
+   #ident, we override ASM_OUTPUT_IDENT and, since the gcc .ident is its
+   only use besides ASM_OUTPUT_IDENT, undef IDENT_ASM_OP from elfos.h.  */
+#undef IDENT_ASM_OP
+#undef ASM_OUTPUT_IDENT
+#define ASM_OUTPUT_IDENT(FILE, NAME) \
+  fprintf (FILE, "%s\"%s\"\n", "\t.ident\t", NAME);
+
+#define ASM_APP_ON "#APP\n"
+
+#define ASM_APP_OFF "#NO_APP\n"
+
+
+/* Node: Data Output */
+
+/* We must use REAL_VALUE_TO_TARGET_SINGLE and
+   REAL_VALUE_TO_TARGET_LONG_DOUBLE.  It seems real.h cannot support when
+   target-double is target-single is 32bit-single.  */
+#define ASM_OUTPUT_LONG_DOUBLE(FILE, VALUE)            \
+  do                                                   \
+    {                                                  \
+      long l[2];                                       \
+      REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l);     \
+      fprintf (FILE, "\t.dword 0x%lx\n", l[0]);                \
+      fprintf (FILE, "\t.dword 0x%lx\n", l[1]);                \
+    }                                                  \
+  while (0)
+
+/* FIXME: The manual says "array of long:s", but
+   REAL_VALUE_TO_TARGET_SINGLE actually writes a long.  */
+#define ASM_OUTPUT_FLOAT(FILE, VALUE)          \
+  do                                           \
+    {                                          \
+      long l;                                  \
+      REAL_VALUE_TO_TARGET_SINGLE (VALUE, l);  \
+      fprintf (FILE, "\t.dword 0x%lx\n", l);   \
+    }                                          \
+  while (0)
+
+/* This is what is used by gcc for 64-bit floats,
+   not the "long double" one. */
+#define ASM_OUTPUT_DOUBLE(FILE, VALUE) \
+ ASM_OUTPUT_LONG_DOUBLE (FILE, VALUE)
+
+
+/* This is a kludge for a.out+ELF support: For non-ELF prioritized
+   [cd]tors, globalize the function so collect2 can collect it.  This is
+   due to short-sightedness guided by defined (ASM_OUTPUT_SECTION_NAME)
+   && defined (ASM_OUTPUT_CONSTRUCTOR).  */
+
+#define ASM_OUTPUT_INT(FILE, VALUE)            \
+  do                                           \
+    {                                          \
+      fprintf (FILE, "\t.dword ");             \
+      output_addr_const (FILE, (VALUE));       \
+      fprintf (FILE, "\n");                    \
+    }                                          \
+  while (0)
+
+#define ASM_OUTPUT_SHORT(FILE, VALUE)          \
+  do                                           \
+    {                                          \
+      fprintf (FILE, "\t.word ");              \
+      output_addr_const (FILE, (VALUE));       \
+      fprintf (FILE, "\n");                    \
+    }                                          \
+  while (0)
+
+#define ASM_OUTPUT_CHAR(FILE, VALUE)           \
+  do                                           \
+    {                                          \
+      fprintf (FILE, "\t.byte ");              \
+      output_addr_const (FILE, (VALUE));       \
+      fprintf (FILE, "\n");                    \
+    }                                          \
+  while (0)
+
+#define ASM_OUTPUT_BYTE(FILE, VALUE)  \
+ fprintf (FILE, "\t.byte 0x%x\n", (VALUE))
+
+#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) (C) == '@'
+
+/* FIXME: These are undocumented. */
+/* We need to define these, since the 2byte, 4byte, 8byte op:s are only
+   available in ELF.  These "normal" pseudos do not have any alignment
+   constraints or side-effects.  */
+#undef UNALIGNED_SHORT_ASM_OP
+#define UNALIGNED_SHORT_ASM_OP "\t.word\t"
+
+#undef INT_ASM_OP
+#define INT_ASM_OP "\t.dword\t"
+
+#undef UNALIGNED_INT_ASM_OP
+#define UNALIGNED_INT_ASM_OP "\t.dword\t"
+
+#undef UNALIGNED_DOUBLE_INT_ASM_OP
+#define UNALIGNED_DOUBLE_INT_ASM_OP "\t.quad\t"
+
+/* Node: Uninitialized Data */
+
+/* Remember to round off odd values if we want data alignment,
+   since we cannot do that with an .align directive.
+
+   Using .comm causes the space not to be reserved in .bss, but by
+   tricks with the symbol type.  Not good if other tools than binutils
+   are used on the object files.  Since ".global ... .lcomm ..." works, we
+   use that.  Use .._ALIGNED_COMMON, since gcc whines when we only have
+   ..._COMMON, and we prefer to whine outselves; BIGGEST_ALIGNMENT is not
+   the one to check.  This done for a.out only.  */
+/* FIXME: I suspect a bug in gcc with alignment.  Do not warn until
+   investigated; it mucks up the testsuite results.  */
+#define CRIS_ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN, LOCAL) \
+  do                                                                   \
+    {                                                                  \
+      int align_ = (ALIGN) / BITS_PER_UNIT;                            \
+      if (TARGET_DATA_ALIGN && TARGET_ALIGN_BY_32 && align_ < 4)       \
+       align_ = 4;                                                     \
+      else if (TARGET_DATA_ALIGN && align_ < 2)                                \
+       align_ = 2;                                                     \
+      /* FIXME: Do we need this?  */                                   \
+      else if (align_ < 1)                                             \
+       align_ = 1;                                                     \
+                                                                       \
+      if (TARGET_ELF)                                                  \
+       {                                                               \
+         if (LOCAL)                                                    \
+           {                                                           \
+             fprintf ((FILE), "%s", LOCAL_ASM_OP);                     \
+             assemble_name ((FILE), (NAME));                           \
+             fprintf ((FILE), "\n");                                   \
+           }                                                           \
+         fprintf ((FILE), "%s", COMMON_ASM_OP);                        \
+         assemble_name ((FILE), (NAME));                               \
+         fprintf ((FILE), ",%u,%u\n", (SIZE), align_);                 \
+       }                                                               \
+      else                                                             \
+       {                                                               \
+         /* We can't tell a one-only or weak COMM from a "global       \
+            COMM" so just make all non-locals weak.  */                \
+         if (! (LOCAL))                                                \
+           ASM_WEAKEN_LABEL (FILE, NAME);                              \
+         fputs ("\t.lcomm ", (FILE));                                  \
+         assemble_name ((FILE), (NAME));                               \
+         fprintf ((FILE), ",%u\n",                                     \
+                  ((SIZE) + (align_ - 1)) & ~(align_ - 1));            \
+       }                                                               \
+    }                                                                  \
+  while (0)
+
+#define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN) \
+ CRIS_ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN, 0)
+
+#undef ASM_OUTPUT_ALIGNED_DECL_LOCAL
+#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \
+ CRIS_ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN, 1)
+
+/* FIXME: define ASM_OUTPUT_SHARED_COMMON and emit an error when it is
+   used with -melinux and a.out.  */
+
+/* Node: Label Output */
+
+#define ASM_OUTPUT_LABEL(FILE, NAME)           \
+  do                                           \
+    {                                          \
+      assemble_name (FILE, NAME);              \
+      fputs (":\n", FILE);                     \
+    }                                          \
+  while (0)
+
+#define ASM_GLOBALIZE_LABEL(FILE, NAME)                \
+  do                                           \
+    {                                          \
+      fputs ("\t.global ", FILE);              \
+      assemble_name (FILE, NAME);              \
+      fputs ("\n", FILE);                      \
+    }                                          \
+  while (0)
+
+#define SUPPORTS_WEAK 1
+
+/* FIXME: This macro isn't documented, but this would probably be an
+   appropriate location.  It's only used in crtstuff.c, else we'd have to
+   handle (to #undef or ignore it) in a.out.  */
+#define HAVE_GAS_HIDDEN 1
+
+#undef  ASM_OUTPUT_INTERNAL_LABEL
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE, PREFIX, NUM)   \
+  do                                                   \
+    {                                                  \
+      asm_fprintf (FILE, "%L%s%d:\n", PREFIX, NUM);    \
+    }                                                  \
+  while (0)
+
+/* Remove any previous definition (elfos.h).  */
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM)        \
+  sprintf (LABEL, "*%s%s%ld", LOCAL_LABEL_PREFIX, PREFIX, (long) NUM)
+
+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO)         \
+  do                                                           \
+    {                                                          \
+      (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10);       \
+      sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO));          \
+    }                                                          \
+  while (0)
+
+
+/* Node: Initialization */
+/* (no definitions) */
+
+/* Node: Macros for Initialization */
+
+/* We don't want to use "strip" for anything linked with "-melinux"
+   "-shlib", seen by the linker as "-Ur -d -Bdynamic" in combination.  */
+#define SET_STRIPPABLE_EXECUTABLE(DS, ARGC, ARGV)              \
+  do                                                           \
+    {                                                          \
+      int i;                                                   \
+      int flags = 0;                                           \
+      for (i = (ARGC) - 1; i > 0; i--)                         \
+       {                                                       \
+         if (strcmp ((ARGV)[i], "-Ur") == 0)                   \
+           flags |= 1;                                         \
+         else if (strcmp ((ARGV)[i], "-d") == 0)               \
+           flags |= 2;                                         \
+         else if (strcmp ((ARGV)[i], "-Bdynamic") == 0)        \
+           flags |= 4;                                         \
+                                                               \
+         if (flags == 7)                                       \
+           break;                                              \
+       }                                                       \
+                                                               \
+      (DS) = (flags != 7);                                     \
+    }                                                          \
+  while (0)
+
+
+/* Node: Instruction Output */
+
+#define REGISTER_NAMES                                 \
+ {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",        \
+  "r9", "r10", "r11", "r12", "r13", "sp", "pc", "srp", "faked_ap"}
+
+#define ADDITIONAL_REGISTER_NAMES \
+ {{"r14", 14}, {"r15", 15}}
+
+#define PRINT_OPERAND(FILE, X, CODE)           \
+ cris_print_operand (FILE, X, CODE)
+
+/* For delay-slot handling.  */
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) (CODE == '#')
+
+#define PRINT_OPERAND_ADDRESS(FILE, ADDR)      \
+   cris_print_operand_address (FILE, ADDR)
+
+/* Output an empty line to illustrate the presence of the delay slot.  */
+#define DBR_OUTPUT_SEQEND(FILE) \
+  fprintf (FILE, "\n")
+
+#define LOCAL_LABEL_PREFIX (TARGET_ELF ? "." : "")
+
+/* cppinit.c initializes a const array from this, so it must be constant,
+   can't have it different based on options.  Luckily, the prefix is
+   always allowed, so let's have it on all GCC-generated code.  Note that
+   we have this verbatim everywhere in the back-end, not using %R or %s or
+   such.  */
+#define REGISTER_PREFIX "$"
+
+/* Remove any previous definition (elfos.h).  */
+/* We use -fno-leading-underscore to remove it, when necessary.  */
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX "_"
+
+#define ASM_OUTPUT_REG_PUSH(FILE, REGNO) \
+  fprintf (FILE, "\tpush $%s\n", reg_names[REGNO])
+
+#define ASM_OUTPUT_REG_POP(FILE, REGNO) \
+  fprintf (FILE, "\tpop $%s\n", reg_names[REGNO])
+
+
+/* Node: Dispatch Tables */
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL)       \
+  asm_fprintf (FILE, "\t.word %LL%d-%LL%d\n", VALUE, REL)
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE)  \
+  asm_fprintf (FILE, "\t.dword %LL%d\n", VALUE)
+
+/* Defined to also emit an .align in elfos.h.  We don't want that.  */
+#undef ASM_OUTPUT_CASE_LABEL
+
+/* Since the "bound" insn loads the comparison value if the compared<
+   value (register) is out of bounds (0..comparison value-1), we need
+   to output another case to catch it.
+   The way to find it is to look for the label_ref at the else-arm inside
+   the expanded casesi core-insn.
+   FIXME: Check this construct when changing to new version of gcc.  */
+#define ASM_OUTPUT_CASE_END(STREAM, NUM, TABLE)                                \
+  do                                                                   \
+    {                                                                  \
+      asm_fprintf (STREAM, "\t.word %LL%d-%LL%d%s\n",                  \
+                  CODE_LABEL_NUMBER                                    \
+                   (XEXP (XEXP (XEXP                                   \
+                                 (XVECEXP                              \
+                                   (PATTERN (PREV_INSN (PREV_INSN      \
+                                                         (TABLE))),    \
+                                    0, 0), 1), 2), 0)),                \
+                  NUM,                                                 \
+                  (TARGET_PDEBUG ? "; default" : ""));                 \
+    }                                                                  \
+  while (0)
+
+
+/* Node: Exception Region Output */
+/* (no definitions) */
+/* FIXME: Fill in with our own optimized layout.  */
+
+/* Node: Alignment Output */
+
+#define ASM_OUTPUT_ALIGN(FILE, LOG)  \
+ fprintf (FILE, "\t.align %d\n", (LOG))
+
+
+/* Node: All Debuggers */
+
+#define DBX_REGISTER_NUMBER(REGNO) \
+ ((REGNO) == CRIS_SRP_REGNUM ? CRIS_CANONICAL_SRP_REGNUM : (REGNO))
+
+/* FIXME: Investigate DEBUGGER_AUTO_OFFSET, DEBUGGER_ARG_OFFSET.  */
+
+
+/* Node: DBX Options */
+
+/* Is this correct? Check later. */
+#define DBX_NO_XREFS
+
+#define DBX_CONTIN_LENGTH 0
+
+/* FIXME: Is this needed when we have 0 DBX_CONTIN_LENGTH?  */
+#define DBX_CONTIN_CHAR '?'
+
+
+/* Node: DBX Hooks */
+/* (no definitions) */
+
+/* Node: File names and DBX */
+/* (no definitions) */
+
+
+/* Node: SDB and DWARF */
+
+#define DWARF_LINE_MIN_INSTR_LENGTH 2
+
+
+/* Node: Cross-compilation */
+#define REAL_ARITHMETIC
+
+
+/* Node: Misc */
+
+/* FIXME: Check this one more time.  */
+#define PREDICATE_CODES                                        \
+ {"cris_orthogonal_operator",                          \
+  {PLUS, MINUS, IOR, AND, UMIN}},                      \
+ {"cris_commutative_orth_op",                          \
+  {PLUS, IOR, AND, UMIN}},                             \
+ {"cris_operand_extend_operator",                      \
+  {PLUS, MINUS, UMIN}},                                        \
+ {"cris_extend_operator",                              \
+  {ZERO_EXTEND, SIGN_EXTEND}},                         \
+ {"cris_plus_or_bound_operator",                       \
+  {PLUS, UMIN}},                                       \
+ {"cris_bdap_operand",                                 \
+  {SUBREG, REG, LABEL_REF, SYMBOL_REF, MEM, CONST_INT, \
+   CONST_DOUBLE, CONST, SIGN_EXTEND}},                 \
+ {"cris_bdap_biap_operand",                            \
+  {SUBREG, REG, LABEL_REF, SYMBOL_REF, MEM, CONST_INT, \
+   CONST_DOUBLE, CONST, SIGN_EXTEND, MULT}},           \
+ {"cris_general_operand_or_gotless_symbol",            \
+  {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,         \
+   LABEL_REF, SUBREG, REG, MEM}},                      \
+ {"cris_general_operand_or_symbol",                    \
+  {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,         \
+   LABEL_REF, SUBREG, REG, MEM}},                      \
+ {"cris_general_operand_or_plt_symbol",                        \
+  {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,         \
+   LABEL_REF, SUBREG, REG, MEM}},                      \
+ {"cris_mem_call_operand",                             \
+  {MEM}},
+
+/* A combination of the bound (umin) insn together with a
+   sign-extended add via the table to PC seems optimal.
+   If the table overflows, the assembler will take care of it.
+   Theoretically, in extreme cases (uncertain if they occur), an error
+   will be emitted, so FIXME: Check how large case-tables are emitted,
+   possible add an option to emit SImode case-tables.  */
+#define CASE_VECTOR_MODE HImode
+
+#define CASE_VECTOR_PC_RELATIVE 1
+
+/* FIXME: Investigate CASE_VECTOR_SHORTEN_MODE to make sure HImode is not
+   used when broken-.word could possibly fail (plus test-case).  */
+
+#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
+
+#define FIXUNS_TRUNC_LIKE_FIX_TRUNC
+
+#define EASY_DIV_EXPR TRUNC_DIV_EXPR
+
+/* This is the number of bytes that can be moved in one
+   reasonably fast instruction sequence.  For CRIS, this is two
+   instructions: mem => reg, reg => mem.  */
+#define MOVE_MAX 4
+
+/* Maybe SHIFT_COUNT_TRUNCATED is safe to define?  FIXME: Check later.  */
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+#define STORE_FLAG_VALUE 1
+
+#define Pmode SImode
+
+#define FUNCTION_MODE QImode
+
+#define NO_IMPLICIT_EXTERN_C
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/gcc/config/cris/cris.md b/gcc/config/cris/cris.md
new file mode 100644 (file)
index 0000000..3df8aaa
--- /dev/null
@@ -0,0 +1,5096 @@
+;; GCC machine description for CRIS cpu cores.
+;; Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+;; Contributed by Axis Communications.
+
+;; This file is part of GCC.
+;;
+;; GCC 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.
+;;
+;; GCC 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 GCC; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;; The original PO technology requires these to be ordered by speed,
+;; so that assigner will pick the fastest.
+
+;; See files "md.texi" and "rtl.def" for documentation on define_insn,
+;; match_*, et. al.
+;;
+;; The function cris_notice_update_cc in cris.c handles condition code
+;; updates for most instructions, helped by the "cc" attribute.
+
+;; There are several instructions that are orthogonal in size, and seems
+;; they could be matched by a single pattern without a specified size
+;; for the operand that is orthogonal.  However, this did not work on
+;; gcc-2.7.2 (and problably not on gcc-2.8.1), relating to that when a
+;; constant is substituted into an operand, the actual mode must be
+;; deduced from the pattern.  There is reasonable hope that that has been
+;; fixed in egcs post 1.1.1, so FIXME: try again.
+
+;; You will notice that three-operand alternatives ("=r", "r", "!To")
+;; are marked with a "!" constraint modifier to avoid being reloaded
+;; into.  This is because gcc would otherwise prefer to use the constant
+;; pool and its offsettable address instead of reloading to an
+;; ("=r", "0", "i") alternative.  Also, the constant-pool support was not
+;; only suboptimal but also buggy in 2.7.2, ??? maybe only in 2.6.3.
+
+;; All insns that look like (set (...) (plus (...) (reg:SI 8)))
+;; get problems when reloading r8 (frame pointer) to r14 + offs (stack
+;; pointer).  Thus the instructions that get into trouble have specific
+;; checks against matching frame_pointer_rtx.
+;; ??? But it should be re-checked for gcc > 2.7.2
+;; FIXME: This changed some time ago (from 2000-03-16) for gcc-2.9x.
+
+;; FIXME: When PIC, all [rX=rY+S] could be enabled to match
+;; [rX=gotless_symbol].
+;; The movsi for a gotless symbol could be split (post reload).
+\f
+;; UNSPEC Usage:
+;; 0 PLT reference from call expansion: operand 0 is the address,
+;;   the mode is VOIDmode.  Always wrapped in CONST.
+
+;; We need an attribute to define whether an instruction can be put in
+;; a branch-delay slot or not, and whether it has a delay slot.
+;;
+;; Branches and return instructions have a delay slot, and cannot
+;; themselves be put in a delay slot.  This has changed *for short
+;; branches only* between architecture variants, but the possible win
+;; is presumed negligible compared to the added complexity of the machine
+;; description: one would have to add always-correct infrastructure to
+;; distinguish short branches.
+;;
+;; Whether an instruction can be put in a delay slot depends on the
+;; instruction (all short instructions except jumps and branches)
+;; and the addressing mode (must not be prefixed or referring to pc).
+;; In short, any "slottable" instruction must be 16 bit and not refer
+;; to pc, or alter it.
+;;
+;; The possible values are "yes", "no" and "has_slot".  Yes/no means if
+;; the insn is slottable or not.  Has_slot means that the insn is a
+;; return insn or branch insn (which are not considered slottable since
+;; that is generally true).  Having the semmingly illogical value
+;; "has_slot" means we do not have to add another attribute just to say
+;; that an insn has a delay-slot, since it also infers that it is not
+;; slottable.  Better names for the attribute were found to be longer and
+;; not add readability to the machine description.
+;;
+;; The default that is defined here for this attribute is "no", not
+;; slottable, not having a delay-slot, so there's no need to worry about
+;; it being wrong for non-branch and return instructions.
+;;  The default could depend on the kind of insn and the addressing
+;; mode, but that would need more attributes and hairier, more error
+;; prone code.
+;;
+;;  There is an extra constraint, 'Q', which recognizes indirect reg,
+;; except when the reg is pc.  The constraints 'Q' and '>' together match
+;; all possible memory operands that are slottable.
+;;  For other operands, you need to check if it has a valid "slottable"
+;; quick-immediate operand, where the particular signedness-variation
+;; may match the constraints 'I' or 'J'.), and include it in the
+;; constraint pattern for the slottable pattern.  An alternative using
+;; only "r" constraints is most often slottable.
+
+(define_attr "slottable" "no,yes,has_slot" (const_string "no"))
+
+;; We also need attributes to sanely determine the condition code
+;; state.  See cris_notice_update_cc for how this is used.
+
+(define_attr "cc" "none,clobber,normal" (const_string "normal"))
+
+;; A branch or return has one delay-slot.  The instruction in the
+;; delay-slot is always executed, independent of whether the branch is
+;; taken or not.  Note that besides setting "slottable" to "has_slot",
+;; there also has to be a "%#" at the end of a "delayed" instruction
+;; output pattern (for "jump" this means "ba %l0%#"), so print_operand can
+;; catch it and print a "nop" if necessary.  This method was stolen from
+;; sparc.md.
+
+(define_delay (eq_attr "slottable" "has_slot")
+  [(eq_attr "slottable" "yes") (nil) (nil)])
+\f
+;; Test insns.
+
+;; DImode
+;;
+;; Allow register and offsettable mem operands only; post-increment is
+;; not worth the trouble.
+
+(define_insn "tstdi"
+  [(set (cc0)
+       (match_operand:DI 0 "nonimmediate_operand" "r,o"))]
+  ""
+  "test.d %M0\;ax\;test.d %H0")
+
+;; No test insns with side-effect on the mem addressing.
+;;
+;; See note on cmp-insns with side-effects (or lack of them)
+
+;; Normal named test patterns from SI on.
+;; FIXME: Seems they should change to be in order smallest..largest.
+
+(define_insn "tstsi"
+  [(set (cc0)
+       (match_operand:SI 0 "nonimmediate_operand" "r,Q>,m"))]
+  ""
+  "test.d %0"
+  [(set_attr "slottable" "yes,yes,no")])
+
+(define_insn "tsthi"
+  [(set (cc0)
+       (match_operand:HI 0 "nonimmediate_operand" "r,Q>,m"))]
+  ""
+  "test.w %0"
+  [(set_attr "slottable" "yes,yes,no")])
+
+(define_insn "tstqi"
+  [(set (cc0)
+       (match_operand:QI 0 "nonimmediate_operand" "r,Q>,m"))]
+  ""
+  "test.b %0"
+  [(set_attr "slottable" "yes,yes,no")])
+
+;; It seems that the position of the sign-bit and the fact that 0.0 is
+;; all 0-bits would make "tstsf" a straight-forward implementation;
+;; either "test.d" it for positive/negative or "btstq 30,r" it for
+;; zeroness.
+;;
+;; FIXME: Do that some time; check next_cc0_user to determine if
+;; zero or negative is tested for.
+\f
+;; Compare insns.
+
+;; We could optimize the sizes of the immediate operands for various
+;; cases, but that is not worth it because of the very little usage of
+;; DImode for anything else but a structure/block-mode.  Just do the
+;; obvious stuff for the straight-forward constraint letters.
+
+(define_insn "cmpdi"
+  [(set (cc0)
+       (compare (match_operand:DI 0 "nonimmediate_operand" "r,r,r,r,r,r,o")
+                (match_operand:DI 1 "general_operand" "K,I,P,n,r,o,r")))]
+  ""
+  "@
+   cmpq %1,%M0\;ax\;cmpq 0,%H0
+   cmpq %1,%M0\;ax\;cmpq -1,%H0
+   cmp%e1.%z1 %1,%M0\;ax\;cmpq %H1,%H0
+   cmp.d %M1,%M0\;ax\;cmp.d %H1,%H0
+   cmp.d %M1,%M0\;ax\;cmp.d %H1,%H0
+   cmp.d %M1,%M0\;ax\;cmp.d %H1,%H0
+   cmp.d %M0,%M1\;ax\;cmp.d %H0,%H1")
+
+;; Note that compare insns with side effect addressing mode (e.g.):
+;;
+;; cmp.S [rx=ry+i],rz;
+;; cmp.S [%3=%1+%2],%0
+;;
+;; are *not* usable for gcc since the reloader *does not accept*
+;; cc0-changing insns with side-effects other than setting the condition
+;; codes.  The reason is that the reload stage *may* cause another insn to
+;; be output after the main instruction, in turn invalidating cc0 for the
+;; insn using the test.  (This does not apply to the CRIS case, since a
+;; reload for output -- move to memory -- does not change the condition
+;; code.  Unfortunately we have no way to describe that at the moment.  I
+;; think code would improve being in the order of one percent faster.
+\f
+;; We have cmps and cmpu (compare reg w. sign/zero extended mem).
+;; These are mostly useful for compares in SImode, using 8 or 16-bit
+;; constants, but sometimes gcc will find its way to use it for other
+;; (memory) operands.  Avoid side-effect patterns, though (see above).
+;;
+;; FIXME: These could have an anonymous mode for operand 1.
+
+;; QImode
+
+(define_insn "*cmp_extsi"
+  [(set (cc0)
+       (compare
+        (match_operand:SI 0 "register_operand" "r,r")
+        (match_operator:SI 2 "cris_extend_operator"
+                        [(match_operand:QI 1 "memory_operand" "Q>,m")])))]
+  ""
+  "cmp%e2.%s1 %1,%0"
+  [(set_attr "slottable" "yes,no")])
+
+;; HImode
+(define_insn "*cmp_exthi"
+  [(set (cc0)
+       (compare
+        (match_operand:SI 0 "register_operand" "r,r")
+        (match_operator:SI 2 "cris_extend_operator"
+                        [(match_operand:HI 1 "memory_operand" "Q>,m")])))]
+  ""
+  "cmp%e2.%s1 %1,%0"
+  [(set_attr "slottable" "yes,no")])
+
+;; Swap operands; it seems the canonical look (if any) is not enforced.
+;;
+;; FIXME: Investigate that.
+;; FIXME: These could have an anonymous mode for operand 1.
+
+;; QImode
+
+(define_insn "*cmp_swapextqi"
+  [(set (cc0)
+       (compare
+        (match_operator:SI 2 "cris_extend_operator"
+                           [(match_operand:QI 0 "memory_operand" "Q>,m")])
+        (match_operand:SI 1 "register_operand" "r,r")))]
+  ""
+  "cmp%e2.%s0 %0,%1" ; The function cris_notice_update_cc knows about
+                    ; swapped operands to compares.
+  [(set_attr "slottable" "yes,no")])
+
+;; HImode
+
+(define_insn "*cmp_swapexthi"
+  [(set (cc0)
+       (compare
+        (match_operator:SI 2 "cris_extend_operator"
+                           [(match_operand:HI 0 "memory_operand" "Q>,m")])
+        (match_operand:SI 1 "register_operand" "r,r")))]
+  ""
+  "cmp%e2.%s0 %0,%1" ; The function cris_notice_update_cc knows about
+                    ; swapped operands to compares.
+  [(set_attr "slottable" "yes,no")])
+\f
+;; The "normal" compare patterns, from SI on.
+
+(define_insn "cmpsi"
+  [(set (cc0)
+       (compare
+        (match_operand:SI 0 "nonimmediate_operand" "r,r,r,r,Q>,Q>,r,r,m,m")
+        (match_operand:SI 1 "general_operand" "I,r,Q>,M,M,r,P,g,M,r")))]
+  ""
+  "@
+   cmpq %1,%0
+   cmp.d %1,%0
+   cmp.d %1,%0
+   test.d %0
+   test.d %0
+   cmp.d %0,%1
+   cmp%e1.%z1 %1,%0
+   cmp.d %1,%0
+   test.d %0
+   cmp.d %0,%1"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no")])
+
+(define_insn "cmphi"
+  [(set (cc0)
+       (compare (match_operand:HI 0 "nonimmediate_operand" "r,r,Q>,Q>,r,m,m")
+                (match_operand:HI 1 "general_operand" "r,Q>,M,r,g,M,r")))]
+  ""
+  "@
+   cmp.w %1,%0
+   cmp.w %1,%0
+   test.w %0
+   cmp.w %0,%1
+   cmp.w %1,%0
+   test.w %0
+   cmp.w %0,%1"
+  [(set_attr "slottable" "yes,yes,yes,yes,no,no,no")])
+
+(define_insn "cmpqi"
+  [(set (cc0)
+       (compare
+        (match_operand:QI 0 "nonimmediate_operand" "r,r,r,Q>,Q>,r,m,m")
+        (match_operand:QI 1 "general_operand" "r,Q>,M,M,r,g,M,r")))]
+  ""
+  "@
+   cmp.b %1,%0
+   cmp.b %1,%0
+   test.b %0
+   test.b %0
+   cmp.b %0,%1
+   cmp.b %1,%0
+   test.b %0
+   cmp.b %0,%1"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
+\f
+;; Pattern matching the BTST insn.
+;; It is useful for "if (i & val)" constructs, where val is an exact
+;; power of 2, or if val + 1 is a power of two, where we check for a bunch
+;; of zeros starting at bit 0).
+
+;; SImode.  This mode is the only one needed, since gcc automatically
+;; extends subregs for lower-size modes.  FIXME: Add test-case.
+(define_insn "*btst"
+  [(set (cc0)
+       (zero_extract
+        (match_operand:SI 0 "nonmemory_operand" "r,r,r,r,r,r,n")
+        (match_operand:SI 1 "const_int_operand" "K,n,K,n,K,n,n")
+        (match_operand:SI 2 "nonmemory_operand" "M,M,K,n,r,r,r")))]
+  ;; Either it is a single bit, or consecutive ones starting at 0.
+  "GET_CODE (operands[1]) == CONST_INT
+   && (operands[1] == const1_rtx || operands[2] == const0_rtx)
+   && (REG_S_P (operands[0])
+       || (operands[1] == const1_rtx
+          && REG_S_P (operands[2])
+          && GET_CODE (operands[0]) == CONST_INT
+          && exact_log2 (INTVAL (operands[0])) >= 0))"
+
+;; The last "&&" condition above should be caught by some kind of
+;; canonicalization in gcc, but we can easily help with it here.
+;;  It results from expressions of the type
+;; "power_of_2_value & (1 << y)".
+;;
+;; Since there may be codes with tests in on bits (in constant position)
+;; beyond the size of a word, handle that by assuming those bits are 0.
+;; GCC should handle that, but it's a matter of easily-added belts while
+;; having suspenders.
+
+  "@
+   btstq (%1-1),%0
+   test.d %0
+   btstq %2,%0
+   clearf nz
+   btst %2,%0
+   clearf nz
+   cmpq %p0,%2"
+ [(set_attr "slottable" "yes")])
+\f
+;; Move insns.
+
+;; The whole mandatory movdi family is here; expander, "anonymous"
+;; recognizer and splitter.  We're forced to have a movdi pattern,
+;; although GCC should be able to split it up itself.  Normally it can,
+;; but if other insns have DI operands (as is the case here), reload
+;; must be able to generate or match a movdi.  many testcases fail at
+;; -O3 or -fssa if we don't have this.  FIXME: Fix GCC...  See
+;; <URL:http://gcc.gnu.org/ml/gcc-patches/2000-04/msg00104.html>.
+;; However, a patch from Richard Kenner (similar to the cause of
+;; discussion at the URL above), indicates otherwise.  See
+;; <URL:http://gcc.gnu.org/ml/gcc-patches/2000-04/msg00554.html>.
+;; The truth has IMO is not been decided yet, so check from time to
+;; time by disabling the movdi patterns.
+
+(define_expand "movdi"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+       (match_operand:DI 1 "general_operand" ""))]
+  ""
+  "
+{
+  if (GET_CODE (operands[0]) == MEM && operands[1] != const0_rtx)
+    operands[1] = copy_to_mode_reg (DImode, operands[1]);
+
+  /* Some other ports (as of 2001-09-10 for example mcore and romp) also
+     prefer to split up constants early, like this.  The testcase in
+     gcc.c-torture/execute/961213-1.c shows that CSE2 gets confused by the
+     resulting subreg sets when using the construct from mcore (as of FSF
+     CVS, version -r 1.5), and it believe that the high part (the last one
+     emitted) is the final value.  This construct from romp seems more
+     robust, especially considering the head comments from
+     emit_no_conflict_block.  */
+  if ((GET_CODE (operands[1]) == CONST_INT
+       || GET_CODE (operands[1]) == CONST_DOUBLE)
+      && ! reload_completed
+      && ! reload_in_progress)
+    {
+      rtx insns;
+      rtx op0 = operands[0];
+      rtx op1 = operands[1];
+
+      start_sequence ();
+      emit_move_insn (operand_subword (op0, 0, 1, DImode),
+                     operand_subword (op1, 0, 1, DImode));
+      emit_move_insn (operand_subword (op0, 1, 1, DImode),
+                     operand_subword (op1, 1, 1, DImode));
+      insns = get_insns ();
+      end_sequence ();
+
+      emit_no_conflict_block (insns, op0, op1, 0, op1);
+      DONE;
+    }
+}")
+
+(define_insn "*movdi_insn"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m")
+       (match_operand:DI 1 "general_operand" "r,g,rM"))]
+  "register_operand (operands[0], DImode)
+   || register_operand (operands[1], DImode)
+   || operands[1] == const0_rtx"
+  "#")
+
+(define_split
+  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+       (match_operand:DI 1 "general_operand" ""))]
+  "reload_completed"
+  [(match_dup 2)]
+  "operands[2] = cris_split_movdx (operands);")
+\f
+;; Side-effect patterns for move.S1 [rx=ry+rx.S2],rw
+;; and move.S1 [rx=ry+i],rz
+;;  Then movs.S1 and movu.S1 for both modes.
+;;
+;; move.S1 [rx=ry+rz.S],rw avoiding when rx is ry, or rw is rx
+;; FIXME: These could have anonymous mode for operand 0.
+
+;; QImode
+
+(define_insn "*mov_sideqi_biap"
+  [(set (match_operand:QI 0 "register_operand" "=r,r")
+       (mem:QI (plus:SI
+                (mult:SI (match_operand:SI 1 "register_operand" "r,r")
+                         (match_operand:SI 2 "const_int_operand" "n,n"))
+                (match_operand:SI 3 "register_operand" "r,r"))))
+   (set (match_operand:SI 4 "register_operand" "=*3,r")
+       (plus:SI (mult:SI (match_dup 1)
+                         (match_dup 2))
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (MULT, operands, 4, 3, 1, 2, 0)"
+  "@
+   #
+   move.%s0 [%4=%3+%1%T2],%0")
+
+;; HImode
+
+(define_insn "*mov_sidehi_biap"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (mem:HI (plus:SI
+                (mult:SI (match_operand:SI 1 "register_operand" "r,r")
+                         (match_operand:SI 2 "const_int_operand" "n,n"))
+                (match_operand:SI 3 "register_operand" "r,r"))))
+   (set (match_operand:SI 4 "register_operand" "=*3,r")
+       (plus:SI (mult:SI (match_dup 1)
+                         (match_dup 2))
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (MULT, operands, 4, 3, 1, 2, 0)"
+  "@
+   #
+   move.%s0 [%4=%3+%1%T2],%0")
+
+;; SImode
+
+(define_insn "*mov_sidesi_biap"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (mem:SI (plus:SI
+                (mult:SI (match_operand:SI 1 "register_operand" "r,r")
+                         (match_operand:SI 2 "const_int_operand" "n,n"))
+                (match_operand:SI 3 "register_operand" "r,r"))))
+   (set (match_operand:SI 4 "register_operand" "=*3,r")
+       (plus:SI (mult:SI (match_dup 1)
+                         (match_dup 2))
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (MULT, operands, 4, 3, 1, 2, 0)"
+  "@
+   #
+   move.%s0 [%4=%3+%1%T2],%0")
+\f
+;; move.S1 [rx=ry+i],rz
+;; avoiding move.S1 [ry=ry+i],rz
+;; and      move.S1 [rz=ry+i],rz
+;; Note that "i" is allowed to be a register.
+;; FIXME: These could have anonymous mode for operand 0.
+
+;; QImode
+
+(define_insn "*mov_sideqi"
+  [(set (match_operand:QI 0 "register_operand" "=r,r,r")
+       (mem:QI
+        (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
+                 (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri"))))
+   (set (match_operand:SI 3 "register_operand" "=*1,r,r")
+       (plus:SI (match_dup 1)
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 3, 1, 2, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[2]) != CONST_INT
+         || INTVAL (operands[2]) > 127
+         || INTVAL (operands[2]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
+    return \"#\";
+  return \"move.%s0 [%3=%1%S2],%0\";
+}")
+
+;; HImode
+
+(define_insn "*mov_sidehi"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
+       (mem:HI
+        (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
+                 (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri"))))
+   (set (match_operand:SI 3 "register_operand" "=*1,r,r")
+       (plus:SI (match_dup 1)
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 3, 1, 2, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[2]) != CONST_INT
+         || INTVAL (operands[2]) > 127
+         || INTVAL (operands[2]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
+    return \"#\";
+  return \"move.%s0 [%3=%1%S2],%0\";
+}")
+
+;; SImode
+
+(define_insn "*mov_sidesi"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (mem:SI
+        (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
+                 (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri"))))
+   (set (match_operand:SI 3 "register_operand" "=*1,r,r")
+       (plus:SI (match_dup 1)
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 3, 1, 2, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[2]) != CONST_INT
+         || INTVAL (operands[2]) > 127
+         || INTVAL (operands[2]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
+    return \"#\";
+  return \"move.%s0 [%3=%1%S2],%0\";
+}")
+\f
+;; Other way around; move to memory.
+
+;; For all side-effect patterns, it seems to be the case that the
+;; predicate isn't consulted after combine.  For sake of stability, we
+;; recognize and split the cases where dangerous register combinations are
+;; spotted: where a register is set in the side-effect, and used in the
+;; main insn.  We don't handle the case where the set in the main insn
+;; overlaps the set in the side-effect; that would be too big a bug to
+;; paper over.  We handle just the case where the set in the side-effect
+;; overlaps the input operand of the main insn (i.e. just moves to memory).
+
+;;
+;; move.s rx,[ry=rx+rw.S]
+;; FIXME: These could have anonymous mode for operand 3.
+
+;; QImode
+
+(define_insn "*mov_sideqi_biap_mem"
+  [(set (mem:QI (plus:SI
+                (mult:SI (match_operand:SI 0 "register_operand" "r,r,r")
+                         (match_operand:SI 1 "const_int_operand" "n,n,n"))
+                (match_operand:SI 2 "register_operand" "r,r,r")))
+       (match_operand:QI 3 "register_operand" "r,r,r"))
+   (set (match_operand:SI 4 "register_operand" "=*2,!*3,r")
+       (plus:SI (mult:SI (match_dup 0)
+                         (match_dup 1))
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (MULT, operands, 4, 2, 0, 1, 3)"
+  "@
+   #
+   #
+   move.%s3 %3,[%4=%2+%0%T1]")
+
+;; HImode
+
+(define_insn "*mov_sidehi_biap_mem"
+  [(set (mem:HI (plus:SI
+                (mult:SI (match_operand:SI 0 "register_operand" "r,r,r")
+                         (match_operand:SI 1 "const_int_operand" "n,n,n"))
+                (match_operand:SI 2 "register_operand" "r,r,r")))
+       (match_operand:HI 3 "register_operand" "r,r,r"))
+   (set (match_operand:SI 4 "register_operand" "=*2,!*3,r")
+       (plus:SI (mult:SI (match_dup 0)
+                         (match_dup 1))
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (MULT, operands, 4, 2, 0, 1, 3)"
+  "@
+   #
+   #
+   move.%s3 %3,[%4=%2+%0%T1]")
+
+;; SImode
+
+(define_insn "*mov_sidesi_biap_mem"
+  [(set (mem:SI (plus:SI
+                (mult:SI (match_operand:SI 0 "register_operand" "r,r,r")
+                         (match_operand:SI 1 "const_int_operand" "n,n,n"))
+                (match_operand:SI 2 "register_operand" "r,r,r")))
+       (match_operand:SI 3 "register_operand" "r,r,r"))
+   (set (match_operand:SI 4 "register_operand" "=*2,!*3,r")
+       (plus:SI (mult:SI (match_dup 0)
+                         (match_dup 1))
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (MULT, operands, 4, 2, 0, 1, 3)"
+  "@
+   #
+   #
+   move.%s3 %3,[%4=%2+%0%T1]")
+
+;; Split for the case above where the predicate isn't honored; only the
+;; constraint, and we end up with the set in the side-effect gets the same
+;; register as the input register.  Arguably a GCC bug, but we'll spot it
+;; rarely enough that we need to catch it ourselves to be safe.
+
+(define_split
+  [(parallel
+    [(set (mem (plus:SI
+               (mult:SI (match_operand:SI 0 "register_operand" "")
+                        (match_operand:SI 1 "const_int_operand" ""))
+               (match_operand:SI 2 "register_operand" "")))
+         (match_operand 3 "register_operand" ""))
+     (set (match_operand:SI 4 "register_operand" "")
+         (plus:SI (mult:SI (match_dup 0)
+                           (match_dup 1))
+                  (match_dup 2)))])]
+  "reload_completed && reg_overlap_mentioned_p (operands[4], operands[3])"
+  [(set (match_dup 5) (match_dup 3))
+   (set (match_dup 4) (match_dup 2))
+   (set (match_dup 4)
+       (plus:SI (mult:SI (match_dup 0)
+                         (match_dup 1))
+                (match_dup 4)))]
+  "operands[5]
+     = gen_rtx_MEM (GET_MODE (operands[3]),
+                   gen_rtx_PLUS (SImode,
+                                 gen_rtx_MULT (SImode,
+                                               operands[0], operands[1]),
+                                 operands[2]));")
+\f
+;; move.s rx,[ry=rz+i]
+;; FIXME: These could have anonymous mode for operand 2.
+
+;; QImode
+
+(define_insn "*mov_sideqi_mem"
+  [(set (mem:QI
+        (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r,r")
+                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r>Ri,r,>Ri")))
+       (match_operand:QI 2 "register_operand" "r,r,r,r"))
+   (set (match_operand:SI 3 "register_operand" "=*0,!*2,r,r")
+       (plus:SI (match_dup 0)
+                (match_dup 1)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 3, 0, 1, -1, 2)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[1]) != CONST_INT
+         || INTVAL (operands[1]) > 127
+         || INTVAL (operands[1]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'J')))
+    return \"#\";
+  if (which_alternative == 1)
+    return \"#\";
+  return \"move.%s2 %2,[%3=%0%S1]\";
+}")
+
+;; HImode
+
+(define_insn "*mov_sidehi_mem"
+  [(set (mem:HI
+        (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r,r")
+                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r>Ri,r,>Ri")))
+       (match_operand:HI 2 "register_operand" "r,r,r,r"))
+   (set (match_operand:SI 3 "register_operand" "=*0,!*2,r,r")
+       (plus:SI (match_dup 0)
+                (match_dup 1)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 3, 0, 1, -1, 2)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[1]) != CONST_INT
+         || INTVAL (operands[1]) > 127
+         || INTVAL (operands[1]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'J')))
+    return \"#\";
+  if (which_alternative == 1)
+    return \"#\";
+  return \"move.%s2 %2,[%3=%0%S1]\";
+}")
+
+;; SImode
+
+(define_insn "*mov_sidesi_mem"
+  [(set (mem:SI
+        (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r,r")
+                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r>Ri,r,>Ri")))
+       (match_operand:SI 2 "register_operand" "r,r,r,r"))
+   (set (match_operand:SI 3 "register_operand" "=*0,!*2,r,r")
+       (plus:SI (match_dup 0)
+                (match_dup 1)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 3, 0, 1, -1, 2)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[1]) != CONST_INT
+         || INTVAL (operands[1]) > 127
+         || INTVAL (operands[1]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'J')))
+    return \"#\";
+  if (which_alternative == 1)
+    return \"#\";
+  return \"move.%s2 %2,[%3=%0%S1]\";
+}")
+
+;; Like the biap case, a split where the set in the side-effect gets the
+;; same register as the input register to the main insn due to gcc not
+;; always checking the predicate.
+
+(define_split
+  [(parallel
+    [(set (mem (plus:SI
+               (match_operand:SI 0 "cris_bdap_operand" "")
+               (match_operand:SI 1 "cris_bdap_operand" "")))
+         (match_operand:SI 2 "register_operand" ""))
+     (set (match_operand:SI 3 "register_operand" "")
+         (plus:SI (match_dup 0) (match_dup 1)))])]
+  "reload_completed && reg_overlap_mentioned_p (operands[3], operands[2])"
+  [(set (match_dup 4) (match_dup 2))
+   (set (match_dup 3) (match_dup 0))
+   (set (match_dup 3) (plus:SI (match_dup 3) (match_dup 1)))]
+  "operands[4]
+     = gen_rtx_MEM (GET_MODE (operands[2]),
+                   gen_rtx_PLUS (SImode, operands[0], operands[1]));")
+\f
+;; Clear memory side-effect patterns.  It is hard to get to the mode if
+;; the MEM was anonymous, so there will be one for each mode.
+
+;; clear.d [ry=rx+rw.s2]
+
+(define_insn "*clear_sidesi_biap"
+  [(set (mem:SI (plus:SI
+                (mult:SI (match_operand:SI 0 "register_operand" "r,r")
+                         (match_operand:SI 1 "const_int_operand" "n,n"))
+                (match_operand:SI 2 "register_operand" "r,r")))
+       (const_int 0))
+   (set (match_operand:SI 3 "register_operand" "=*2,r")
+       (plus:SI (mult:SI (match_dup 0)
+                         (match_dup 1))
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (MULT, operands, 3, 2, 0, 1, -1)"
+  "@
+   #
+   clear.d [%3=%2+%0%T1]")
+
+;; clear.d [ry=rz+i]
+
+(define_insn "*clear_sidesi"
+  [(set (mem:SI
+        (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r")
+                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r,>Ri")))
+       (const_int 0))
+   (set (match_operand:SI 2 "register_operand" "=*0,r,r")
+       (plus:SI (match_dup 0)
+                (match_dup 1)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 2, 0, 1, -1, -1)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[1]) != CONST_INT
+         || INTVAL (operands[1]) > 127
+         || INTVAL (operands[1]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'J')))
+    return \"#\";
+  return \"clear.d [%2=%0%S1]\";
+}")
+
+;;  clear.w [ry=rx+rw.s2]
+
+(define_insn "*clear_sidehi_biap"
+  [(set (mem:HI (plus:SI
+                (mult:SI (match_operand:SI 0 "register_operand" "r,r")
+                         (match_operand:SI 1 "const_int_operand" "n,n"))
+                (match_operand:SI 2 "register_operand" "r,r")))
+       (const_int 0))
+   (set (match_operand:SI 3 "register_operand" "=*2,r")
+       (plus:SI (mult:SI (match_dup 0)
+                         (match_dup 1))
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (MULT, operands, 3, 2, 0, 1, -1)"
+  "@
+   #
+   clear.w [%3=%2+%0%T1]")
+
+;; clear.w [ry=rz+i]
+
+(define_insn "*clear_sidehi"
+  [(set (mem:HI
+        (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r")
+                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r,>Ri")))
+       (const_int 0))
+   (set (match_operand:SI 2 "register_operand" "=*0,r,r")
+       (plus:SI (match_dup 0)
+                (match_dup 1)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 2, 0, 1, -1, -1)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[1]) != CONST_INT
+         || INTVAL (operands[1]) > 127
+         || INTVAL (operands[1]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'J')))
+    return \"#\";
+  return \"clear.w [%2=%0%S1]\";
+}")
+
+;;  clear.b [ry=rx+rw.s2]
+
+(define_insn "*clear_sideqi_biap"
+  [(set (mem:QI (plus:SI
+                (mult:SI (match_operand:SI 0 "register_operand" "r,r")
+                         (match_operand:SI 1 "const_int_operand" "n,n"))
+                (match_operand:SI 2 "register_operand" "r,r")))
+       (const_int 0))
+   (set (match_operand:SI 3 "register_operand" "=*2,r")
+       (plus:SI (mult:SI (match_dup 0)
+                         (match_dup 1))
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (MULT, operands, 3, 2, 0, 1, -1)"
+  "@
+   #
+   clear.b [%3=%2+%0%T1]")
+
+;; clear.b [ry=rz+i]
+
+(define_insn "*clear_sideqi"
+  [(set (mem:QI
+        (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r")
+                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r,>Ri")))
+       (const_int 0))
+   (set (match_operand:SI 2 "register_operand" "=*0,r,r")
+       (plus:SI (match_dup 0)
+                (match_dup 1)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 2, 0, 1, -1, -1)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[1]) != CONST_INT
+         || INTVAL (operands[1]) > 127
+         || INTVAL (operands[1]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'J')))
+    return \"#\";
+  return \"clear.b [%2=%0%S1]\";
+}")
+\f
+;; To appease test-case gcc.c-torture/execute/920501-2.c (and others) at
+;; -O0, we need a movdi as a temporary measure.  Here's how things fail:
+;;  A cmpdi RTX needs reloading (global):
+;;    (insn 185 326 186 (set (cc0)
+;;         (compare (mem/f:DI (reg/v:SI 22) 0)
+;;             (const_int 1 [0x1]))) 4 {cmpdi} (nil)
+;;     (nil))
+;; Now, reg 22 is reloaded for input address, and the mem is also moved
+;; out of the instruction (into a register), since one of the operands
+;; must be a register.  Reg 22 is reloaded (into reg 10), and the mem is
+;; moved out and synthesized in SImode parts (reg 9, reg 10 - should be ok
+;; wrt. overlap).  The bad things happen with the synthesis in
+;; emit_move_insn_1; the location where to substitute reg 10 is lost into
+;; two new RTX:es, both still having reg 22.  Later on, the left-over reg
+;; 22 is recognized to have an equivalent in memory which is substituted
+;; straight in, and we end up with an unrecognizable insn:
+;;    (insn 325 324 326 (set (reg:SI 9 r9)
+;;           (mem/f:SI (mem:SI (plus:SI (reg:SI 8 r8)
+;;                       (const_int -84 [0xffffffac])) 0) 0)) -1 (nil)
+;;       (nil))
+;; which is the first part of the reloaded synthesized "movdi".
+;;  The right thing would be to add equivalent replacement locations for
+;; insn with pseudos that need more reloading.  The question is where.
+
+;; Normal move patterns from SI on.
+
+(define_expand "movsi"
+  [(set
+    (match_operand:SI 0 "nonimmediate_operand" "")
+    (match_operand:SI 1 "cris_general_operand_or_symbol" ""))]
+  ""
+  "
+{
+  /* If the output goes to a MEM, make sure we have zero or a register as
+     input.  */
+  if (GET_CODE (operands[0]) == MEM
+      && ! REG_S_P (operands[1])
+      && operands[1] != const0_rtx
+      && ! no_new_pseudos)
+    operands[1] = force_reg (SImode, operands[1]);
+
+  /* If we're generating PIC and have an incoming symbol, validize it to a
+     general operand or something that will match a special pattern.
+
+     FIXME: Do we *have* to recognize anything that would normally be a
+     valid symbol?  Can we exclude global PIC addresses with an added
+     offset?  */
+  if (flag_pic
+      && CONSTANT_ADDRESS_P (operands[1])
+      && cris_symbol (operands[1]))
+    {
+      /* We must have a register as destination for what we're about to
+        do, and for the patterns we generate.  */
+      if (! REG_S_P (operands[0]))
+       {
+         if (no_new_pseudos)
+           abort ();
+         operands[1] = force_reg (SImode, operands[1]);
+       }
+      else
+       {
+         /* Mark a needed PIC setup for a LABEL_REF:s coming in here:
+            they are so rare not-being-branch-targets that we don't mark
+            a function as needing PIC setup just because we have
+            inspected LABEL_REF:s as operands.  It is only in
+            __builtin_setjmp and such that we can get a LABEL_REF
+            assigned to a register.  */
+         if (GET_CODE (operands[1]) == LABEL_REF)
+           current_function_uses_pic_offset_table = 1;
+
+         /* We don't have to do anything for global PIC operands; they
+            look just like ``[rPIC+sym]''.  */
+         if (! cris_got_symbol (operands[1])
+             /* We don't do anything for local PIC operands; we match
+                that with a special alternative.  */
+             && ! cris_gotless_symbol (operands[1]))
+           {
+             /* We get here when we have to change something that would
+                be recognizable if it wasn't PIC.  A ``sym'' is ok for
+                PIC symbols both with and without a GOT entry.  And ``sym
+                + offset'' is ok for local symbols, so the only thing it
+                could be, is a global symbol with an offset.  Check and
+                abort if not.  */
+             rtx sym = get_related_value (operands[1]);
+             HOST_WIDE_INT offs = get_integer_term (operands[1]);
+
+             if (sym == NULL_RTX || offs == 0)
+               abort ();
+             emit_move_insn (operands[0], sym);
+             if (expand_binop (SImode, add_optab, operands[0],
+                               GEN_INT (offs), operands[0], 0,
+                               OPTAB_LIB_WIDEN) != operands[0])
+               abort ();
+             DONE;
+           }
+       }
+    }
+}")
+
+(define_insn "*movsi_internal"
+  [(set
+    (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,Q>,r,Q>,g,r,r,r,g")
+    (match_operand:SI 1
+    ;; FIXME: We want to put S last, but apparently g matches S.
+    ;; It's a bug: an S is not a general_operand and shouldn't match g.
+     "cris_general_operand_or_gotless_symbol" "r,Q>,M,M,I,r,M,n,!S,g,r"))]
+  ""
+  "*
+{
+  /* Better to have c-switch here; it is worth it to optimize the size of
+     move insns.  The alternative would be to try to find more constraint
+     letters.  FIXME: Check again.  It seems this could shrink a bit.  */
+  switch (which_alternative)
+    {
+    case 0:
+    case 1:
+    case 5:
+    case 9:
+    case 10:
+      return \"move.d %1,%0\";
+
+    case 2:
+    case 3:
+    case 6:
+      return \"clear.d %0\";
+
+      /* Constants -32..31 except 0.  */
+    case 4:
+      return \"moveq %1,%0\";
+
+      /* We can win a little on constants -32768..-33, 32..65535.  */
+    case 7:
+      if (INTVAL (operands[1]) > 0 && INTVAL (operands[1]) < 65536)
+       {
+         if (INTVAL (operands[1]) < 256)
+           return \"movu.b %1,%0\";
+         return \"movu.w %1,%0\";
+       }
+      else if (INTVAL (operands[1]) >= -32768 && INTVAL (operands[1]) < 32768)
+       {
+         if (INTVAL (operands[1]) >= -128 && INTVAL (operands[1]) < 128)
+           return \"movs.b %1,%0\";
+         return \"movs.w %1,%0\";
+       }
+      return \"move.d %1,%0\";
+
+      case 8:
+       /* FIXME: Try and split this into pieces GCC makes better code of,
+          than this multi-insn pattern.  Synopsis: wrap the GOT-relative
+          symbol into an unspec, and when PIC, recognize the unspec
+          everywhere a symbol is normally recognized.  (The PIC register
+          should be recognized by GCC as pic_offset_table_rtx when needed
+          and similar for PC.)  Each component can then be optimized with
+          the rest of the code; it should be possible to have a constant
+          term added on an unspec.  Don't forget to add a REG_EQUAL (or
+          is it REG_EQUIV) note to the destination.  It might not be
+          worth it.  Measure.
+
+          Note that the 'v' modifier makes PLT references be output as
+          sym:PLT rather than [rPIC+sym:GOTPLT].  */
+       return \"move.d %v1,%0\;add.d %P1,%0\";
+
+    default:
+      return \"BOGUS: %1 to %0\";
+    }
+}"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no,no")])
+\f
+;; Extend operations with side-effect from mem to register, using
+;; MOVS/MOVU.  These are from mem to register only.
+;;
+;; [rx=ry+rz.S]
+;;
+;; QImode to HImode
+;;
+;; FIXME: Can we omit extend to HImode, since GCC should truncate for
+;; HImode by itself?  Perhaps use only anonymous modes?
+
+(define_insn "*ext_sideqihi_biap"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (match_operator:HI
+        5 "cris_extend_operator"
+        [(mem:QI (plus:SI
+                  (mult:SI (match_operand:SI 1 "register_operand" "r,r")
+                           (match_operand:SI 2 "const_int_operand" "n,n"))
+                  (match_operand:SI 3 "register_operand" "r,r")))]))
+   (set (match_operand:SI 4 "register_operand" "=*3,r")
+       (plus:SI (mult:SI (match_dup 1)
+                         (match_dup 2))
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (MULT, operands, 4, 3, 1, 2, 0)"
+  "@
+   #
+   mov%e5.%m5 [%4=%3+%1%T2],%0")
+
+;; QImode to SImode
+
+(define_insn "*ext_sideqisi_biap"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (match_operator:SI
+        5 "cris_extend_operator"
+        [(mem:QI (plus:SI
+                  (mult:SI (match_operand:SI 1 "register_operand" "r,r")
+                           (match_operand:SI 2 "const_int_operand" "n,n"))
+                  (match_operand:SI 3 "register_operand" "r,r")))]))
+   (set (match_operand:SI 4 "register_operand" "=*3,r")
+       (plus:SI (mult:SI (match_dup 1)
+                         (match_dup 2))
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (MULT, operands, 4, 3, 1, 2, 0)"
+  "@
+   #
+   mov%e5.%m5 [%4=%3+%1%T2],%0")
+
+;; HImode to SImode
+
+(define_insn "*ext_sidehisi_biap"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (match_operator:SI
+        5 "cris_extend_operator"
+        [(mem:HI (plus:SI
+                  (mult:SI (match_operand:SI 1 "register_operand" "r,r")
+                           (match_operand:SI 2 "const_int_operand" "n,n"))
+                  (match_operand:SI 3 "register_operand" "r,r")))]))
+   (set (match_operand:SI 4 "register_operand" "=*3,r")
+       (plus:SI (mult:SI (match_dup 1)
+                         (match_dup 2))
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (MULT, operands, 4, 3, 1, 2, 0)"
+  "@
+   #
+   mov%e5.%m5 [%4=%3+%1%T2],%0")
+\f
+;; Same but [rx=ry+i]
+
+;; QImode to HImode
+
+(define_insn "*ext_sideqihi"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
+       (match_operator:HI
+        4 "cris_extend_operator"
+        [(mem:QI (plus:SI
+                  (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
+                  (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+   (set (match_operand:SI 3 "register_operand" "=*1,r,r")
+       (plus:SI (match_dup 1)
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 3, 1, 2, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[2]) != CONST_INT
+         || INTVAL (operands[2]) > 127
+         || INTVAL (operands[2]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
+    return \"#\";
+  return \"mov%e4.%m4 [%3=%1%S2],%0\";
+}")
+
+;; QImode to SImode
+
+(define_insn "*ext_sideqisi"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (match_operator:SI
+        4 "cris_extend_operator"
+        [(mem:QI (plus:SI
+                  (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
+                  (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+   (set (match_operand:SI 3 "register_operand" "=*1,r,r")
+       (plus:SI (match_dup 1)
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 3, 1, 2, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[2]) != CONST_INT
+         || INTVAL (operands[2]) > 127
+         || INTVAL (operands[2]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
+    return \"#\";
+  return \"mov%e4.%m4 [%3=%1%S2],%0\";
+}")
+
+;; HImode to SImode
+
+(define_insn "*ext_sidehisi"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (match_operator:SI
+        4 "cris_extend_operator"
+        [(mem:HI (plus:SI
+                  (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
+                  (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+   (set (match_operand:SI 3 "register_operand" "=*1,r,r")
+       (plus:SI (match_dup 1)
+                (match_dup 2)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 3, 1, 2, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[2]) != CONST_INT
+         || INTVAL (operands[2]) > 127
+         || INTVAL (operands[2]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
+    return \"#\";
+  return \"mov%e4.%m4 [%3=%1%S2],%0\";
+}")
+\f
+;; FIXME: See movsi.
+
+(define_insn "movhi"
+  [(set
+    (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,Q>,r,Q>,r,r,r,g,g,r")
+    (match_operand:HI 1 "general_operand" "r,Q>,M,M,I,r,L,O,n,M,r,g"))]
+  ""
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+    case 1:
+    case 5:
+    case 10:
+    case 11:
+      return \"move.w %1,%0\";
+    case 2:
+    case 3:
+    case 9:
+      return \"clear.w %0\";
+    case 4:
+      return \"moveq %1,%0\";
+    case 6:
+    case 8:
+      if (INTVAL (operands[1]) < 256 && INTVAL (operands[1]) >= -128)
+       {
+         if (INTVAL (operands[1]) > 0)
+           return \"movu.b %1,%0\";
+         return \"movs.b %1,%0\";
+       }
+      return \"move.w %1,%0\";
+    case 7:
+      return \"movEq %b1,%0\";
+    default:
+      return \"BOGUS: %1 to %0\";
+  }
+}"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,yes,no,no,no,no")
+   (set (attr "cc")
+       (if_then_else (eq_attr "alternative" "7")
+                     (const_string "clobber")
+                     (const_string "normal")))])
+
+(define_insn "movstricthi"
+  [(set
+    (strict_low_part
+     (match_operand:HI 0 "nonimmediate_operand" "+r,r,r,Q>,Q>,g,r,g"))
+    (match_operand:HI 1 "general_operand" "r,Q>,M,M,r,M,g,r"))]
+  ""
+  "@
+   move.w %1,%0
+   move.w %1,%0
+   clear.w %0
+   clear.w %0
+   move.w %1,%0
+   clear.w %0
+   move.w %1,%0
+   move.w %1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
+\f
+(define_insn "movqi"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,Q>,r,r,Q>,r,g,g,r,r")
+       (match_operand:QI 1 "general_operand" "r,r,Q>,M,M,I,M,r,O,g"))]
+  ""
+  "@
+   move.b %1,%0
+   move.b %1,%0
+   move.b %1,%0
+   clear.b %0
+   clear.b %0
+   moveq %1,%0
+   clear.b %0
+   move.b %1,%0
+   moveq %b1,%0
+   move.b %1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,yes,no")
+   (set (attr "cc")
+       (if_then_else (eq_attr "alternative" "8")
+                     (const_string "clobber")
+                     (const_string "normal")))])
+
+(define_insn "movstrictqi"
+  [(set (strict_low_part
+        (match_operand:QI 0 "nonimmediate_operand" "+r,Q>,r,r,Q>,g,g,r"))
+       (match_operand:QI 1 "general_operand" "r,r,Q>,M,M,M,r,g"))]
+  ""
+  "@
+   move.b %1,%0
+   move.b %1,%0
+   move.b %1,%0
+   clear.b %0
+   clear.b %0
+   clear.b %0
+   move.b %1,%0
+   move.b %1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
+
+;; The valid "quick" bit-patterns are, except for 0.0, denormalized
+;; values REALLY close to 0, and some NaN:s (I think; their exponent is
+;; all ones); the worthwhile one is "0.0".
+;; It will use clear, so we know ALL types of immediate 0 never change cc.
+
+(define_insn "movsf"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,Q>,r,r,Q>,g,g,r")
+       (match_operand:SF 1 "general_operand" "r,r,Q>,G,G,G,r,g"))]
+  ""
+  "@
+   move.d %1,%0
+   move.d %1,%0
+   move.d %1,%0
+   clear.d %0
+   clear.d %0
+   clear.d %0
+   move.d %1,%0
+   move.d %1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
+\f
+
+;; Sign- and zero-extend insns with standard names.
+;;  Those for integer source operand are ordered with the widest source
+;; type first.
+
+;; Sign-extend.
+
+(define_insn "extendsidi2"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (sign_extend:DI (match_operand:SI 1 "general_operand" "g")))]
+  ""
+  "move.d %1,%M0\;smi %H0\;neg.d %H0,%H0")
+
+(define_insn "extendhidi2"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (sign_extend:DI (match_operand:HI 1 "general_operand" "g")))]
+  ""
+  "movs.w %1,%M0\;smi %H0\;neg.d %H0,%H0")
+
+(define_insn "extendhisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (sign_extend:SI (match_operand:HI 1 "general_operand" "r,Q>,g")))]
+  ""
+  "movs.w %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
+
+(define_insn "extendqidi2"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (sign_extend:DI (match_operand:QI 1 "general_operand" "g")))]
+  ""
+  "movs.b %1,%M0\;smi %H0\;neg.d %H0,%H0")
+
+(define_insn "extendqisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (sign_extend:SI (match_operand:QI 1 "general_operand" "r,Q>,g")))]
+  ""
+  "movs.b %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
+
+;; To do a byte->word exension, extend to dword, exept that the top half
+;; of the register will be clobbered.  FIXME: Perhaps this is not needed.
+
+(define_insn "extendqihi2"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
+       (sign_extend:HI (match_operand:QI 1 "general_operand" "r,Q>,g")))]
+  ""
+  "movs.b %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
+\f
+
+;; Zero-extend.  The DImode ones are synthesized by gcc, so we don't
+;; specify them here.
+
+(define_insn "zero_extendhisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (zero_extend:SI
+        (match_operand:HI 1 "nonimmediate_operand" "r,Q>,m")))]
+  ""
+  "movu.w %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
+
+(define_insn "zero_extendqisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (zero_extend:SI
+        (match_operand:QI 1 "nonimmediate_operand" "r,Q>,m")))]
+  ""
+  "movu.b %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
+
+;; Same comment as sign-extend QImode to HImode above applies.
+
+(define_insn "zero_extendqihi2"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
+       (zero_extend:HI
+        (match_operand:QI 1 "nonimmediate_operand" "r,Q>,m")))]
+  ""
+  "movu.b %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
+\f
+;; All kinds of arithmetic and logical instructions.
+;;
+;; First, anonymous patterns to match addressing modes with
+;; side-effects.
+;;
+;; op.S [rx=ry+I],rz; (add, sub, or, and, bound).
+;;
+;; [rx=ry+rz.S]
+;; FIXME: These could have anonymous mode for operand 0.
+
+;; QImode
+
+(define_insn "*op_sideqi_biap"
+  [(set (match_operand:QI 0 "register_operand" "=r,r")
+       (match_operator:QI
+        6 "cris_orthogonal_operator"
+        [(match_operand:QI 1 "register_operand" "0,0")
+         (mem:QI (plus:SI
+                  (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                           (match_operand:SI 3 "const_int_operand" "n,n"))
+                  (match_operand:SI 4 "register_operand" "r,r")))]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x6.%s0 [%5=%4+%2%T3],%0")
+
+;; HImode
+
+(define_insn "*op_sidehi_biap"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (match_operator:HI
+        6 "cris_orthogonal_operator"
+        [(match_operand:HI 1 "register_operand" "0,0")
+         (mem:HI (plus:SI
+                  (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                           (match_operand:SI 3 "const_int_operand" "n,n"))
+                  (match_operand:SI 4 "register_operand" "r,r")))]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x6.%s0 [%5=%4+%2%T3],%0")
+
+;; SImode
+
+(define_insn "*op_sidesi_biap"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (match_operator:SI
+        6 "cris_orthogonal_operator"
+        [(match_operand:SI 1 "register_operand" "0,0")
+         (mem:SI (plus:SI
+                  (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                           (match_operand:SI 3 "const_int_operand" "n,n"))
+                  (match_operand:SI 4 "register_operand" "r,r")))]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x6.%s0 [%5=%4+%2%T3],%0")
+\f
+;; [rx=ry+i] ([%4=%2+%3])
+;; FIXME: These could have anonymous mode for operand 0.
+
+;; QImode
+
+(define_insn "*op_sideqi"
+  [(set (match_operand:QI 0 "register_operand" "=r,r,r")
+       (match_operator:QI
+        5 "cris_orthogonal_operator"
+        [(match_operand:QI 1 "register_operand" "0,0,0")
+         (mem:QI (plus:SI
+                  (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                  (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x5.%s0 [%4=%2%S3],%0\";
+}")
+
+;; HImode
+
+(define_insn "*op_sidehi"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
+       (match_operator:HI
+        5 "cris_orthogonal_operator"
+        [(match_operand:HI 1 "register_operand" "0,0,0")
+         (mem:HI (plus:SI
+                  (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                  (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x5.%s0 [%4=%2%S3],%0\";
+}")
+
+;; SImode
+
+(define_insn "*op_sidesi"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (match_operator:SI
+        5 "cris_orthogonal_operator"
+        [(match_operand:SI 1 "register_operand" "0,0,0")
+         (mem:SI (plus:SI
+                  (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                  (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x5.%s0 [%4=%2%S3],%0\";
+}")
+\f
+;; To match all cases for commutative operations we may have to have the
+;; following pattern for add, or & and.  I do not know really, but it does
+;; not break anything.
+;;
+;; FIXME: This really ought to be checked.
+;;
+;; op.S [rx=ry+I],rz;
+;;
+;; [rx=ry+rz.S]
+;; FIXME: These could have anonymous mode for operand 0.
+
+;; QImode
+
+(define_insn "*op_swap_sideqi_biap"
+  [(set (match_operand:QI 0 "register_operand" "=r,r")
+       (match_operator:QI
+        6 "cris_commutative_orth_op"
+        [(mem:QI (plus:SI
+                  (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                           (match_operand:SI 3 "const_int_operand" "n,n"))
+                  (match_operand:SI 4 "register_operand" "r,r")))
+         (match_operand:QI 1 "register_operand" "0,0")]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x6.%s0 [%5=%4+%2%T3],%0")
+
+;; HImode
+
+(define_insn "*op_swap_sidehi_biap"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (match_operator:HI
+        6 "cris_commutative_orth_op"
+        [(mem:HI (plus:SI
+                  (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                           (match_operand:SI 3 "const_int_operand" "n,n"))
+                  (match_operand:SI 4 "register_operand" "r,r")))
+         (match_operand:HI 1 "register_operand" "0,0")]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x6.%s0 [%5=%4+%2%T3],%0")
+
+;; SImode
+
+(define_insn "*op_swap_sidesi_biap"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (match_operator:SI
+        6 "cris_commutative_orth_op"
+        [(mem:SI (plus:SI
+                  (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                           (match_operand:SI 3 "const_int_operand" "n,n"))
+                  (match_operand:SI 4 "register_operand" "r,r")))
+         (match_operand:SI 1 "register_operand" "0,0")]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x6.%s0 [%5=%4+%2%T3],%0")
+\f
+;; [rx=ry+i] ([%4=%2+%3])
+;; FIXME: These could have anonymous mode for operand 0.
+
+;; QImode
+
+(define_insn "*op_swap_sideqi"
+  [(set (match_operand:QI 0 "register_operand" "=r,r,r")
+       (match_operator:QI
+        5 "cris_commutative_orth_op"
+        [(mem:QI
+          (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                   (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))
+         (match_operand:QI 1 "register_operand" "0,0,0")]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x5.%s0 [%4=%2%S3],%0\";
+}")
+
+;; HImode
+
+(define_insn "*op_swap_sidehi"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
+       (match_operator:HI
+        5 "cris_commutative_orth_op"
+        [(mem:HI
+          (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                   (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))
+         (match_operand:HI 1 "register_operand" "0,0,0")]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x5.%s0 [%4=%2%S3],%0\";
+}")
+
+;; SImode
+
+(define_insn "*op_swap_sidesi"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (match_operator:SI
+        5 "cris_commutative_orth_op"
+        [(mem:SI
+          (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                   (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))
+         (match_operand:SI 1 "register_operand" "0,0,0")]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x5.%s0 [%4=%2%S3],%0\";
+}")
+\f
+;; Add operations, standard names.
+
+;; Note that for the 'P' constraint, the high part can be -1 or 0.  We
+;; output the insn through the 'A' output modifier as "adds.w" and "addq",
+;; respectively.
+(define_insn "adddi3"
+  [(set (match_operand:DI 0 "register_operand" "=r,r,r,&r,&r")
+       (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,r")
+                (match_operand:DI 2 "general_operand" "J,N,P,g,!To")))]
+  ""
+  "@
+   addq %2,%M0\;ax\;addq 0,%H0
+   subq %n2,%M0\;ax\;subq 0,%H0
+   add%e2.%z2 %2,%M0\;ax\;%A2 %H2,%H0
+   add.d %M2,%M0\;ax\;add.d %H2,%H0
+   add.d %M2,%M1,%M0\;ax\;add.d %H2,%H1,%H0")
+
+(define_insn "addsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r")
+       (plus:SI
+        (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r")
+        (match_operand:SI 2 "general_operand" "r,Q>,J,N,n,g,!To,0")))]
+
+;; The last constraint is due to that after reload, the '%' is not
+;; honored, and canonicalization doesn't care about keeping the same
+;; register as in destination.  This will happen after insn splitting.
+;; gcc <= 2.7.2.  FIXME: Check for gcc-2.9x
+
+ ""
+ "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+    case 1:
+      return \"add.d %2,%0\";
+    case 2:
+      return \"addq %2,%0\";
+    case 3:
+      return \"subq %n2,%0\";
+    case 4:
+      /* 'Known value', but not in -63..63.
+        Check if addu/subu may be used.  */
+      if (INTVAL (operands[2]) > 0)
+       {
+         if (INTVAL (operands[2]) < 256)
+           return \"addu.b %2,%0\";
+         if (INTVAL (operands[2]) < 65536)
+           return \"addu.w %2,%0\";
+       }
+      else
+       {
+         if (INTVAL (operands[2]) >= -255)
+           return \"subu.b %n2,%0\";
+         if (INTVAL (operands[2]) >= -65535)
+           return \"subu.w %n2,%0\";
+       }
+      return \"add.d %2,%0\";
+    case 6:
+      return \"add.d %2,%1,%0\";
+    case 5:
+      return \"add.d %2,%0\";
+    case 7:
+      return \"add.d %1,%0\";
+    default:
+      return \"BOGUS addsi %2+%1 to %0\";
+    }
+}"
+ [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,yes")])
+\f
+(define_insn "addhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
+       (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,r")
+                (match_operand:HI 2 "general_operand" "r,Q>,J,N,g,!To")))]
+  ""
+  "@
+   add.w %2,%0
+   add.w %2,%0
+   addq %2,%0
+   subq %n2,%0
+   add.w %2,%0
+   add.w %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,no,no")
+   (set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])
+
+(define_insn "addqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r,r")
+       (plus:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0,0,r")
+                (match_operand:QI 2 "general_operand" "r,Q>,J,N,O,g,!To")))]
+  ""
+  "@
+   add.b %2,%0
+   add.b %2,%0
+   addq %2,%0
+   subq %n2,%0
+   subQ -%b2,%0
+   add.b %2,%0
+   add.b %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no")
+   (set_attr "cc" "normal,normal,clobber,clobber,clobber,normal,normal")])
+\f
+;; Subtract.
+;;
+;; Note that because of insn canonicalization these will *seldom* but
+;; rarely be used with a known constant as an operand.
+
+;; Note that for the 'P' constraint, the high part can be -1 or 0.  We
+;; output the insn through the 'D' output modifier as "subs.w" and "subq",
+;; respectively.
+(define_insn "subdi3"
+  [(set (match_operand:DI 0 "register_operand" "=r,r,r,&r,&r")
+       (minus:DI (match_operand:DI 1 "register_operand" "0,0,0,0,r")
+                 (match_operand:DI 2 "general_operand" "J,N,P,g,!To")))]
+  ""
+  "@
+   subq %2,%M0\;ax\;subq 0,%H0
+   addq %n2,%M0\;ax\;addq 0,%H0
+   sub%e2.%z2 %2,%M0\;ax\;%D2 %H2,%H0
+   sub.d %M2,%M0\;ax\;sub.d %H2,%H0
+   sub.d %M2,%M1,%M0\;ax\;sub.d %H2,%H1,%H0")
+
+(define_insn "subsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r")
+       (minus:SI
+        (match_operand:SI 1 "register_operand" "0,0,0,0,0,0,0,r")
+        (match_operand:SI 2 "general_operand" "r,Q>,J,N,P,n,g,!To")))]
+  ""
+
+;; This does not do the optimal: "addu.w 65535,r0" when %2 is negative.
+;; But then again, %2 should not be negative.
+
+  "@
+   sub.d %2,%0
+   sub.d %2,%0
+   subq %2,%0
+   addq %n2,%0
+   sub%e2.%z2 %2,%0
+   sub.d %2,%0
+   sub.d %2,%0
+   sub.d %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,no")])
+\f
+(define_insn "subhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
+       (minus:HI (match_operand:HI 1 "register_operand" "0,0,0,0,0,r")
+                 (match_operand:HI 2 "general_operand" "r,Q>,J,N,g,!To")))]
+  ""
+  "@
+   sub.w %2,%0
+   sub.w %2,%0
+   subq %2,%0
+   addq %n2,%0
+   sub.w %2,%0
+   sub.w %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,no,no")
+   (set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])
+
+(define_insn "subqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r")
+       (minus:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0,r")
+                 (match_operand:QI 2 "general_operand" "r,Q>,J,N,g,!To")))]
+  ""
+  "@
+   sub.b %2,%0
+   sub.b %2,%0
+   subq %2,%0
+   addq %2,%0
+   sub.b %2,%0
+   sub.b %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,no,no")
+   (set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])
+\f
+;; CRIS has some add/sub-with-sign/zero-extend instructions.
+;;  Although these perform sign/zero-extension to SImode, they are
+;; equally applicable for the HImode case.
+;; FIXME: Check; GCC should handle the widening.
+;;  Note that these must be located after the normal add/sub patterns,
+;; so not to get constants into any less specific operands.
+;;
+;; Extend with add/sub and side-effect.
+;;
+;; ADDS/SUBS/ADDU/SUBU and BOUND, which needs a check for zero_extend
+;;
+;; adds/subs/addu/subu bound [rx=ry+rz.S]
+;; FIXME: These could have anonymous mode for operand 0.
+
+;; QImode to HImode
+;; FIXME: GCC should widen.
+
+(define_insn "*extopqihi_side_biap"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (match_operator:HI
+        6 "cris_operand_extend_operator"
+        [(match_operand:HI 1 "register_operand" "0,0")
+         (match_operator:HI
+          7 "cris_extend_operator"
+          [(mem:QI (plus:SI
+                    (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                             (match_operand:SI 3 "const_int_operand" "n,n"))
+                    (match_operand:SI 4 "register_operand" "r,r")))])]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "(GET_CODE (operands[5]) != UMIN || GET_CODE (operands[7]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x6%e7.%m7 [%5=%4+%2%T3],%0")
+
+;; QImode to SImode
+
+(define_insn "*extopqisi_side_biap"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (match_operator:SI
+        6 "cris_operand_extend_operator"
+        [(match_operand:SI 1 "register_operand" "0,0")
+         (match_operator:SI
+          7 "cris_extend_operator"
+          [(mem:QI (plus:SI
+                    (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                             (match_operand:SI 3 "const_int_operand" "n,n"))
+                    (match_operand:SI 4 "register_operand" "r,r")))])]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "(GET_CODE (operands[5]) != UMIN || GET_CODE (operands[7]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x6%e7.%m7 [%5=%4+%2%T3],%0")
+
+;; HImode to SImode
+
+(define_insn "*extophisi_side_biap"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (match_operator:SI
+        6 "cris_operand_extend_operator"
+        [(match_operand:SI 1 "register_operand" "0,0")
+         (match_operator:SI
+          7 "cris_extend_operator"
+          [(mem:HI (plus:SI
+                    (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                             (match_operand:SI 3 "const_int_operand" "n,n"))
+                    (match_operand:SI 4 "register_operand" "r,r")))])]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "(GET_CODE (operands[5]) != UMIN || GET_CODE (operands[7]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x6%e7.%m7 [%5=%4+%2%T3],%0")
+\f
+
+;; [rx=ry+i]
+;; FIXME: These could have anonymous mode for operand 0.
+
+;; QImode to HImode
+
+(define_insn "*extopqihi_side"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
+       (match_operator:HI
+        5 "cris_operand_extend_operator"
+        [(match_operand:HI 1 "register_operand" "0,0,0")
+         (match_operator:HI
+          6 "cris_extend_operator"
+          [(mem:QI
+            (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                     (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")
+                     ))])]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+  "(GET_CODE (operands[5]) != UMIN || GET_CODE (operands[6]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x5%e6.%m6 [%4=%2%S3],%0\";
+}")
+
+;; QImode to SImode
+
+(define_insn "*extopqisi_side"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (match_operator:SI
+        5 "cris_operand_extend_operator"
+        [(match_operand:SI 1 "register_operand" "0,0,0")
+         (match_operator:SI
+          6 "cris_extend_operator"
+          [(mem:QI
+            (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                     (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")
+                     ))])]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+
+  "(GET_CODE (operands[5]) != UMIN || GET_CODE (operands[6]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x5%e6.%m6 [%4=%2%S3],%0\";
+}")
+
+;; HImode to SImode
+
+(define_insn "*extophisi_side"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (match_operator:SI
+        5 "cris_operand_extend_operator"
+        [(match_operand:SI 1 "register_operand" "0,0,0")
+         (match_operator:SI
+          6 "cris_extend_operator"
+          [(mem:HI
+            (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                     (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")
+                     ))])]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+  "(GET_CODE (operands[5]) != UMIN || GET_CODE (operands[6]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x5%e6.%m6 [%4=%2%S3],%0\";
+}")
+\f
+
+;; As with op.S we may have to add special pattern to match commuted
+;; operands to adds/addu  and bound
+;;
+;; adds/addu/bound [rx=ry+rz.S]
+
+;; QImode to HImode
+;; FIXME: GCC should widen.
+;; FIXME: These could have anonymous mode for operand 0.
+
+(define_insn "*extopqihi_swap_side_biap"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (match_operator:HI
+        7 "cris_plus_or_bound_operator"
+        [(match_operator:HI
+          6 "cris_extend_operator"
+          [(mem:QI (plus:SI
+                    (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                             (match_operand:SI 3 "const_int_operand" "n,n"))
+                    (match_operand:SI 4 "register_operand" "r,r")))])
+         (match_operand:HI 1 "register_operand" "0,0")]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "(GET_CODE (operands[6]) != UMIN || GET_CODE (operands[6]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x7%e6.%m6 [%5=%4+%2%T3],%0")
+
+;; QImode to SImode
+
+(define_insn "*extopqisi_swap_side_biap"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (match_operator:SI
+        7 "cris_plus_or_bound_operator"
+        [(match_operator:SI
+          6 "cris_extend_operator"
+          [(mem:QI (plus:SI
+                    (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                             (match_operand:SI 3 "const_int_operand" "n,n"))
+                    (match_operand:SI 4 "register_operand" "r,r")))])
+         (match_operand:SI 1 "register_operand" "0,0")]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "(GET_CODE (operands[6]) != UMIN || GET_CODE (operands[6]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x7%e6.%m6 [%5=%4+%2%T3],%0")
+
+;; HImode to SImode
+(define_insn "*extophisi_swap_side_biap"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (match_operator:SI
+        7 "cris_plus_or_bound_operator"
+        [(match_operator:SI
+          6 "cris_extend_operator"
+          [(mem:HI (plus:SI
+                    (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                             (match_operand:SI 3 "const_int_operand" "n,n"))
+                    (match_operand:SI 4 "register_operand" "r,r")))])
+         (match_operand:SI 1 "register_operand" "0,0")]))
+   (set (match_operand:SI 5 "register_operand" "=*4,r")
+       (plus:SI (mult:SI (match_dup 2)
+                         (match_dup 3))
+                (match_dup 4)))]
+  "(GET_CODE (operands[6]) != UMIN || GET_CODE (operands[6]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
+  "@
+   #
+   %x7%e6.%m6 [%5=%4+%2%T3],%0")
+\f
+;; [rx=ry+i]
+;; FIXME: These could have anonymous mode for operand 0.
+;; FIXME: GCC should widen.
+
+;; QImode to HImode
+
+(define_insn "*extopqihi_swap_side"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
+       (match_operator:HI
+        6 "cris_plus_or_bound_operator"
+        [(match_operator:HI
+          5 "cris_extend_operator"
+          [(mem:QI (plus:SI
+                    (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                    (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))])
+         (match_operand:HI 1 "register_operand" "0,0,0")]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+  "(GET_CODE (operands[6]) != UMIN || GET_CODE (operands[5]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x6%e5.%m5 [%4=%2%S3],%0\";
+}")
+
+;; QImode to SImode
+
+(define_insn "*extopqisi_swap_side"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (match_operator:SI
+        6 "cris_plus_or_bound_operator"
+        [(match_operator:SI
+          5 "cris_extend_operator"
+          [(mem:QI (plus:SI
+                    (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                    (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))])
+         (match_operand:SI 1 "register_operand" "0,0,0")]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+  "(GET_CODE (operands[6]) != UMIN || GET_CODE (operands[5]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x6%e5.%m5 [%4=%2%S3],%0\";
+}")
+
+;; HImode to SImode
+
+(define_insn "*extophisi_swap_side"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (match_operator:SI
+        6 "cris_plus_or_bound_operator"
+        [(match_operator:SI
+          5 "cris_extend_operator"
+          [(mem:HI (plus:SI
+                    (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
+                    (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))])
+         (match_operand:SI 1 "register_operand" "0,0,0")]))
+   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
+       (plus:SI (match_dup 2)
+                (match_dup 3)))]
+  "(GET_CODE (operands[6]) != UMIN || GET_CODE (operands[5]) == ZERO_EXTEND)
+   && cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
+  "*
+{
+  if (which_alternative == 0
+      && (GET_CODE (operands[3]) != CONST_INT
+         || INTVAL (operands[3]) > 127
+         || INTVAL (operands[3]) < -128
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
+         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
+    return \"#\";
+  return \"%x6%e5.%m5 [%4=%2%S3],%0\";
+}")
+\f
+;; Extend versions (zero/sign) of normal add/sub (no side-effects).
+;; FIXME: These could have anonymous mode for operand 0.
+
+;; QImode to HImode
+;; FIXME: GCC should widen.
+
+(define_insn "*extopqihi"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
+       (match_operator:HI
+        3 "cris_operand_extend_operator"
+        [(match_operand:HI 1 "register_operand" "0,0,0,r")
+         (match_operator:HI
+          4 "cris_extend_operator"
+          [(match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To")])]))]
+  "(GET_CODE (operands[3]) != UMIN || GET_CODE (operands[4]) == ZERO_EXTEND)
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
+  "@
+   %x3%e4.%m4 %2,%0
+   %x3%e4.%m4 %2,%0
+   %x3%e4.%m4 %2,%0
+   %x3%e4.%m4 %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,no,no")
+   (set_attr "cc" "clobber")])
+
+;; QImode to SImode
+
+(define_insn "*extopqisi"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (match_operator:SI
+        3 "cris_operand_extend_operator"
+        [(match_operand:SI 1 "register_operand" "0,0,0,r")
+         (match_operator:SI
+          4 "cris_extend_operator"
+          [(match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To")])]))]
+  "(GET_CODE (operands[3]) != UMIN || GET_CODE (operands[4]) == ZERO_EXTEND)
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
+  "@
+   %x3%e4.%m4 %2,%0
+   %x3%e4.%m4 %2,%0
+   %x3%e4.%m4 %2,%0
+   %x3%e4.%m4 %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,no,no")])
+
+;; HImode to SImode
+
+(define_insn "*extophisi"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (match_operator:SI
+        3 "cris_operand_extend_operator"
+        [(match_operand:SI 1 "register_operand" "0,0,0,r")
+         (match_operator:SI
+          4 "cris_extend_operator"
+          [(match_operand:HI 2 "nonimmediate_operand" "r,Q>,m,!To")])]))]
+  "(GET_CODE (operands[3]) != UMIN || GET_CODE (operands[4]) == ZERO_EXTEND)
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
+  "@
+   %x3%e4.%m4 %2,%0
+   %x3%e4.%m4 %2,%0
+   %x3%e4.%m4 %2,%0
+   %x3%e4.%m4 %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,no,no")])
+\f
+
+;; As with the side-effect patterns, may have to have swapped operands for add.
+;; FIXME: *should* be redundant to gcc.
+
+;; QImode to HImode
+
+(define_insn "*extopqihi_swap"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
+       (match_operator:HI
+        4 "cris_plus_or_bound_operator"
+        [(match_operator:HI
+          3 "cris_extend_operator"
+          [(match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To")])
+         (match_operand:HI 1 "register_operand" "0,0,0,r")]))]
+  "(GET_CODE (operands[3]) != UMIN || GET_CODE (operands[4]) == ZERO_EXTEND)
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && operands[1] != frame_pointer_rtx"
+  "@
+   %x4%e3.%m3 %2,%0
+   %x4%e3.%m3 %2,%0
+   %x4%e3.%m3 %2,%0
+   %x4%e3.%m3 %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,no,no")
+   (set_attr "cc" "clobber")])
+
+;; QImode to SImode
+
+(define_insn "*extopqisi_swap"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (match_operator:SI
+        4 "cris_plus_or_bound_operator"
+        [(match_operator:SI
+          3 "cris_extend_operator"
+          [(match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To")])
+         (match_operand:SI 1 "register_operand" "0,0,0,r")]))]
+  "(GET_CODE (operands[3]) != UMIN || GET_CODE (operands[4]) == ZERO_EXTEND)
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && operands[1] != frame_pointer_rtx"
+  "@
+   %x4%e3.%m3 %2,%0
+   %x4%e3.%m3 %2,%0
+   %x4%e3.%m3 %2,%0
+   %x4%e3.%m3 %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,no,no")])
+
+;; HImode to SImode
+
+(define_insn "*extophisi_swap"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (match_operator:SI
+        4 "cris_plus_or_bound_operator"
+        [(match_operator:SI
+          3 "cris_extend_operator"
+          [(match_operand:HI 2 "nonimmediate_operand" "r,Q>,m,!To")])
+         (match_operand:SI 1 "register_operand" "0,0,0,r")]))]
+  "(GET_CODE (operands[3]) != UMIN || GET_CODE (operands[4]) == ZERO_EXTEND)
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && operands[1] != frame_pointer_rtx"
+  "@
+   %x4%e3.%m3 %2,%0
+   %x4%e3.%m3 %2,%0
+   %x4%e3.%m3 %2,%0
+   %x4%e3.%m3 %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,no,no")])
+\f
+;; This is the special case when we use what corresponds to the
+;; instruction above in "casesi".  Do *not* change it to use the generic
+;; pattern and "REG 15" as pc; I did that and it led to madness and
+;; maintenance problems: Instead of (as imagined) recognizing and removing
+;; or replacing this pattern with something simpler, other variant
+;; patterns were recognized or combined, including some prefix variants
+;; where the value in pc is not that of the next instruction (which means
+;; this instruction actually *is* special and *should* be marked as such).
+;; When switching from the "generic pattern match" approach to this simpler
+;; approach, there were insignificant differences in gcc, ipps and
+;; product code, somehow due to scratching reload behind the ear or
+;; something.  Testcase "gcc" looked .01% slower and 4 bytes bigger;
+;; product code became .001% smaller but "looked better".  The testcase
+;; "ipps" was just different at register allocation).
+;;
+;; Assumptions in the jump optimizer forces us to use IF_THEN_ELSE in this
+;; pattern with the default-label as the else, with the "if" being
+;; index-is-less-than the max number of cases plus one.  The default-label
+;; is attached to the end of the case-table at time of output.
+
+(define_insn "*casesi_adds_w"
+  [(set (pc)
+       (if_then_else
+        (ltu (match_operand:SI 0 "register_operand" "r")
+             (match_operand:SI 1 "const_int_operand" "n"))
+        (plus:SI (sign_extend:SI
+                  (mem:HI
+                   (plus:SI (mult:SI (match_dup 0) (const_int 2))
+                            (pc))))
+                 (pc))
+        (label_ref (match_operand 2 "" ""))))
+   (use (label_ref (match_operand 3 "" "")))]
+
+  "operands[0] != frame_pointer_rtx"
+
+  "adds.w [$pc+%0.w],$pc"
+  [(set_attr "cc" "clobber")])
+\f
+;; Multiply instructions.
+
+;; Sometimes powers of 2 (which are normally canonicalized to a
+;; left-shift) appear here, as a result of address reloading.
+;; As a special, for values 3 and 5, we can match with an addi, so add those.
+;;
+;; FIXME: This may be unnecessary now.
+;; Explicitly named for convenience of having a gen_... function.
+
+(define_insn "addi_mul"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (mult:SI
+        (match_operand:SI 1 "register_operand" "%0")
+        (match_operand:SI 2 "const_int_operand" "n")))]
+  "operands[0] != frame_pointer_rtx
+   && operands[1] != frame_pointer_rtx
+   && GET_CODE (operands[2]) == CONST_INT
+   && (INTVAL (operands[2]) == 2
+       || INTVAL (operands[2]) == 4 || INTVAL (operands[2]) == 3
+       || INTVAL (operands[2]) == 5)"
+  "*
+{
+  if (INTVAL (operands[2]) == 2)
+    return \"lslq 1,%0\";
+  else if (INTVAL (operands[2]) == 4)
+    return \"lslq 2,%0\";
+  else if (INTVAL (operands[2]) == 3)
+    return \"addi %0.w,%0\";
+  else if (INTVAL (operands[2]) == 5)
+    return \"addi %0.d,%0\";
+  return \"BAD: adr_mulsi: %0=%1*%2\";
+}"
+[(set_attr "slottable" "yes")
+ ;; No flags are changed if this insn is "addi", but it does not seem
+ ;; worth the trouble to distinguish that to the lslq cases.
+ (set_attr "cc" "clobber")])
+
+;; The addi insn as it is normally used.
+
+(define_insn "*addi"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI
+        (mult:SI (match_operand:SI 2 "register_operand" "r")
+                 (match_operand:SI 3 "const_int_operand" "n"))
+        (match_operand:SI 1 "register_operand" "0")))]
+  "operands[0] != frame_pointer_rtx
+   && operands[1] != frame_pointer_rtx
+   && GET_CODE (operands[3]) == CONST_INT
+   && (INTVAL (operands[3]) == 1
+       || INTVAL (operands[3]) == 2 || INTVAL (operands[3]) == 4)"
+  "addi %2%T3,%0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "none")])
+
+;; The mstep instruction.  Probably not useful by itself; it's to
+;; non-linear wrt. the other insns.  We used to expand to it, so at least
+;; it's correct.
+
+(define_insn "mstep_shift"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (if_then_else:SI
+        (lt:SI (cc0) (const_int 0))
+        (plus:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
+                            (const_int 1))
+                 (match_operand:SI 2 "register_operand" "r"))
+        (ashift:SI (match_operand:SI 3 "register_operand" "0")
+                   (const_int 1))))]
+  ""
+  "mstep %2,%0"
+  [(set_attr "slottable" "yes")])
+
+;; When illegitimate addresses are legitimized, sometimes gcc forgets
+;; to canonicalize the multiplications.
+;;
+;; FIXME: Check gcc > 2.7.2, remove and possibly fix in gcc.
+
+(define_insn "mstep_mul"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (if_then_else:SI
+        (lt:SI (cc0) (const_int 0))
+        (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
+                          (const_int 2))
+                 (match_operand:SI 2 "register_operand" "r"))
+        (mult:SI (match_operand:SI 3 "register_operand" "0")
+                 (const_int 2))))]
+  "operands[0] != frame_pointer_rtx
+   && operands[1] != frame_pointer_rtx
+   && operands[2] != frame_pointer_rtx
+   && operands[3] != frame_pointer_rtx"
+  "mstep %2,%0"
+  [(set_attr "slottable" "yes")])
+
+(define_insn "umulhisi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (mult:SI
+        (zero_extend:SI (match_operand:HI 1 "register_operand" "0"))
+        (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+  "TARGET_HAS_MUL_INSNS"
+  "mulu.w %2,%0"
+  [(set_attr "slottable" "yes")
+   ;; Just N unusable here, but let's be safe.
+   (set_attr "cc" "clobber")])
+
+(define_insn "umulqihi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (mult:HI
+        (zero_extend:HI (match_operand:QI 1 "register_operand" "0"))
+        (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
+  "TARGET_HAS_MUL_INSNS"
+  "mulu.b %2,%0"
+  [(set_attr "slottable" "yes")
+   ;; Not exactly sure, but let's be safe.
+   (set_attr "cc" "clobber")])
+
+;; Note that gcc does not make use of such a thing as umulqisi3.  It gets
+;; confused and will erroneously use it instead of umulhisi3, failing (at
+;; least) gcc.c-torture/execute/arith-rand.c at all optimization levels.
+;; Inspection of optab code shows that there must be only one widening
+;; multiplication per mode widened to.
+
+(define_insn "mulsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (mult:SI (match_operand:SI 1 "register_operand" "0")
+                (match_operand:SI 2 "register_operand" "r")))]
+  "TARGET_HAS_MUL_INSNS"
+  "muls.d %2,%0"
+  [(set_attr "slottable" "yes")
+   ;; Just N unusable here, but let's be safe.
+   (set_attr "cc" "clobber")])
+\f
+;; A few multiply variations.
+
+;; This really extends to SImode, so cc should be considered clobbered.
+
+(define_insn "mulqihi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (mult:HI
+        (sign_extend:HI (match_operand:QI 1 "register_operand" "0"))
+        (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
+  "TARGET_HAS_MUL_INSNS"
+  "muls.b %2,%0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "clobber")])
+
+(define_insn "mulhisi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (mult:SI
+        (sign_extend:SI (match_operand:HI 1 "register_operand" "0"))
+        (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+  "TARGET_HAS_MUL_INSNS"
+  "muls.w %2,%0"
+  [(set_attr "slottable" "yes")
+   ;; Just N unusable here, but let's be safe.
+   (set_attr "cc" "clobber")])
+
+;; When needed, we can get the high 32 bits from the overflow
+;; register.  We don't care to split and optimize these.
+;;
+;; Note that cc0 is still valid after the move-from-overflow-register
+;; insn; no special precaution need to be taken in cris_notice_update_cc.
+
+(define_insn "mulsidi3"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (mult:DI
+        (sign_extend:DI (match_operand:SI 1 "register_operand" "0"))
+        (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+  "TARGET_HAS_MUL_INSNS"
+  "muls.d %2,%M0\;move $mof,%H0")
+
+(define_insn "umulsidi3"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (mult:DI
+        (zero_extend:DI (match_operand:SI 1 "register_operand" "0"))
+        (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+  "TARGET_HAS_MUL_INSNS"
+  "mulu.d %2,%M0\;move $mof,%H0")
+
+;; This pattern would probably not be needed if we add "mof" in its own
+;; register class (and open a can of worms about /not/ pairing it with a
+;; "normal" register).  Having multiple register classes here, and
+;; applicable to the v10 variant only, seems worse than having these two
+;; patterns with multi-insn contents for now (may change; having a free
+;; call-clobbered register is worth some trouble).
+
+(define_insn "smulsi3_highpart"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
+       (truncate:SI
+        (lshiftrt:DI
+         (mult:DI
+          (sign_extend:DI (match_operand:SI 1 "register_operand" "%0,r,r"))
+          (sign_extend:DI (match_operand:SI 2 "register_operand" "r,r,r")))
+         (const_int 32))))
+   (clobber (match_scratch:SI 3 "=X,1,1"))]
+  "TARGET_HAS_MUL_INSNS"
+  "muls.d %2,%1\;move $mof,%0"
+  [(set_attr "cc" "clobber")])
+
+(define_insn "umulsi3_highpart"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
+       (truncate:SI
+        (lshiftrt:DI
+         (mult:DI
+          (zero_extend:DI (match_operand:SI 1 "register_operand" "%0,r,r"))
+          (zero_extend:DI (match_operand:SI 2 "register_operand" "r,r,r")))
+         (const_int 32))))
+   (clobber (match_scratch:SI 3 "=X,1,1"))]
+  "TARGET_HAS_MUL_INSNS"
+  "mulu.d %2,%1\;move $mof,%0"
+  [(set_attr "cc" "clobber")])
+\f
+;; Divide and modulus instructions.  CRIS only has a step instruction.
+
+(define_insn "dstep_shift"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (if_then_else:SI
+        (geu:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
+                           (const_int 1))
+             (match_operand:SI 2 "register_operand" "r"))
+        (minus:SI (ashift:SI (match_operand:SI 3 "register_operand" "0")
+                       (const_int 1))
+                  (match_operand:SI 4 "register_operand" "2"))
+        (ashift:SI (match_operand:SI 5 "register_operand" "0")
+                       (const_int 1))))]
+  ""
+  "dstep %2,%0"
+  [(set_attr "slottable" "yes")])
+
+;; Here's a variant with mult instead of ashift.
+;;
+;; FIXME: This should be investigated.  Which one matches through combination?
+
+(define_insn "dstep_mul"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (if_then_else:SI
+        (geu:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
+                         (const_int 2))
+             (match_operand:SI 2 "register_operand" "r"))
+        (minus:SI (mult:SI (match_operand:SI 3 "register_operand" "0")
+                           (const_int 2))
+                  (match_operand:SI 4 "register_operand" "2"))
+        (mult:SI (match_operand:SI 5 "register_operand" "0")
+                 (const_int 2))))]
+  "operands[0] != frame_pointer_rtx
+   && operands[1] != frame_pointer_rtx
+   && operands[2] != frame_pointer_rtx
+   && operands[3] != frame_pointer_rtx"
+  "dstep %2,%0"
+  [(set_attr "slottable" "yes")])
+\f
+;; Logical operators.
+
+;; Bitwise "and".
+
+;; There is no use in defining "anddi3", because gcc can expand this by
+;; itself, and make reasonable code without interference.
+
+;; If the first operand is memory or a register and is the same as the
+;; second operand, and the third operand is -256 or -65536, we can use
+;; CLEAR instead.  Or, if the first operand is a register, and the third
+;; operand is 255 or 65535, we can zero_extend.
+;; GCC isnt smart enough to recognize these cases (yet), and they seem
+;; to be common enough to be worthwhile.
+;; FIXME: This should be made obsolete.
+
+(define_expand "andsi3"
+  [(set (match_operand:SI 0 "nonimmediate_operand"        "")
+       (and:SI (match_operand:SI 1 "nonimmediate_operand" "")
+               (match_operand:SI 2 "general_operand"    "")))]
+  ""
+  "
+{
+  if (! (GET_CODE (operands[2]) == CONST_INT
+        && (((INTVAL (operands[2]) == -256
+              || INTVAL (operands[2]) == -65536)
+             && rtx_equal_p (operands[1], operands[0]))
+            || ((INTVAL (operands[2]) == 255
+                 || INTVAL (operands[2]) == 65535)
+                && REG_P (operands[0])))))
+    {
+      /* Make intermediate steps if operand0 is not a register or
+        operand1 is not a register, and hope that the reload pass will
+        make something useful out of it.  Note that the operands are
+        *not* canonicalized.  For the moment, I chicken out on this,
+        because all or most ports do not describe 'and' with
+        canonicalized operands, and I seem to remember magic in reload,
+        checking that operand1 has constraint '%0', in which case
+        operand0 and operand1 must have similar predicates.
+        FIXME: Investigate.  */
+      rtx reg0 = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (SImode);
+      rtx reg1 = operands[1];
+
+      if (! REG_P (reg1))
+       {
+         emit_move_insn (reg0, reg1);
+         reg1 = reg0;
+       }
+
+      emit_insn (gen_rtx_SET (SImode, reg0,
+                         gen_rtx_AND (SImode, reg1, operands[2])));
+
+      /* Make sure we get the right *final* destination.  */
+      if (! REG_P (operands[0]))
+       emit_move_insn (operands[0], reg0);
+
+      DONE;
+    }
+}")
+
+;; Some special cases of andsi3.
+
+(define_insn "*andsi_movu"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (and:SI (match_operand:SI 1 "nonimmediate_operand" "%r,Q>,m")
+               (match_operand:SI 2 "const_int_operand" "n,n,n")))]
+  "INTVAL (operands[2]) == 255 || INTVAL (operands[2]) == 65535"
+  "movu.%z2 %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
+
+(define_insn "*andsi_clear"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,Q>,Q>,m,m")
+       (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0,0,0")
+               (match_operand:SI 2 "const_int_operand" "P,n,P,n,P,n")))]
+  "INTVAL (operands[2]) == -65536 || INTVAL (operands[2]) == -256"
+  "@
+   cLear.b %0
+   cLear.w %0
+   cLear.b %0
+   cLear.w %0
+   cLear.b %0
+   cLear.w %0"
+  [(set_attr "slottable" "yes,yes,yes,yes,no,no")
+   (set_attr "cc" "none")])
+
+;; This is a catch-all pattern, taking care of everything that was not
+;; matched in the insns above.
+;;
+;; Sidenote: the tightening from "nonimmediate_operand" to
+;; "register_operand" for operand 1 actually increased the register
+;; pressure (worse code).  That will hopefully change with an
+;; improved reload pass.
+
+(define_insn "*expanded_andsi"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
+       (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,r")
+               (match_operand:SI 2 "general_operand" "I,r,Q>,g,!To")))]
+  ""
+  "@
+   andq %2,%0
+   and.d %2,%0
+   and.d %2,%0
+   and.d %2,%0
+   and.d %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,no,no")])
+\f
+;; For both QI and HI we may use the quick patterns.  This results in
+;; useless condition codes, but that is used rarely enough for it to
+;; normally be a win (could check ahead for use of cc0, but seems to be
+;; more pain than win).
+
+;; FIXME: See note for andsi3
+
+(define_expand "andhi3"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "")
+       (and:HI (match_operand:HI 1 "nonimmediate_operand" "")
+               (match_operand:HI 2 "general_operand"  "")))]
+  ""
+  "
+{
+  if (! (GET_CODE (operands[2]) == CONST_INT
+        && (((INTVAL (operands[2]) == -256
+              || INTVAL (operands[2]) == 65280)
+             && rtx_equal_p (operands[1], operands[0]))
+            || (INTVAL (operands[2]) == 255
+                && REG_P (operands[0])))))
+    {
+      /* See comment for andsi3.  */
+      rtx reg0 = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (HImode);
+      rtx reg1 = operands[1];
+
+      if (! REG_P (reg1))
+       {
+         emit_move_insn (reg0, reg1);
+         reg1 = reg0;
+       }
+
+      emit_insn (gen_rtx_SET (HImode, reg0,
+                         gen_rtx_AND (HImode, reg1, operands[2])));
+
+      /* Make sure we get the right destination.  */
+      if (! REG_P (operands[0]))
+       emit_move_insn (operands[0], reg0);
+
+      DONE;
+    }
+}")
+
+;; Some fast andhi3 special cases.
+
+(define_insn "*andhi_movu"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
+       (and:HI (match_operand:HI 1 "nonimmediate_operand" "r,Q>,m")
+               (const_int 255)))]
+  ""
+  "mOvu.b %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
+
+(define_insn "*andhi_clear_signed"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,Q>,m")
+       (and:HI (match_operand:HI 1 "nonimmediate_operand" "0,0,0")
+               (const_int -256)))]
+  ""
+  "cLear.b %0"
+  [(set_attr "slottable" "yes,yes,no")
+   (set_attr "cc" "none")])
+
+;; FIXME: Either this or the pattern above should be redundant.
+(define_insn "*andhi_clear_unsigned"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,Q>,m")
+       (and:HI (match_operand:HI 1 "nonimmediate_operand" "0,0,0")
+               (const_int 65280)))]
+  ""
+  "cLear.b %0"
+  [(set_attr "slottable" "yes,yes,no")
+   (set_attr "cc" "none")])
+
+;; Catch-all andhi3 pattern.
+
+(define_insn "*expanded_andhi"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
+       (and:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0,r")
+               (match_operand:HI 2 "general_operand" "I,r,Q>,L,O,g,!To")))]
+
+;; Sidenote: the tightening from "general_operand" to
+;; "register_operand" for operand 1 actually increased the register
+;; pressure (worse code).  That will hopefully change with an
+;; improved reload pass.
+
+  ""
+  "@
+   andq %2,%0
+   and.w %2,%0
+   and.w %2,%0
+   and.w %2,%0
+   anDq %b2,%0
+   and.w %2,%0
+   and.w %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,no,yes,no,no")
+   (set_attr "cc" "clobber,normal,normal,normal,clobber,normal,normal")])
+
+;; A strict_low_part pattern.
+
+(define_insn "*andhi_lowpart"
+  [(set (strict_low_part
+        (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r"))
+       (and:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,r")
+               (match_operand:HI 2 "general_operand" "r,Q>,L,O,g,!To")))]
+  ""
+  "@
+   and.w %2,%0
+   and.w %2,%0
+   and.w %2,%0
+   anDq %b2,%0
+   and.w %2,%0
+   and.w %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,no,yes,no,no")
+   (set_attr "cc" "normal,normal,normal,clobber,normal,normal")])
+\f
+(define_insn "andqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r")
+       (and:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0,r")
+               (match_operand:QI 2 "general_operand" "I,r,Q>,O,g,!To")))]
+  ""
+  "@
+   andq %2,%0
+   and.b %2,%0
+   and.b %2,%0
+   andQ %b2,%0
+   and.b %2,%0
+   and.b %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,no,no")
+   (set_attr "cc" "clobber,normal,normal,clobber,normal,normal")])
+
+(define_insn "*andqi_lowpart"
+  [(set (strict_low_part
+        (match_operand:QI 0 "register_operand" "=r,r,r,r,r"))
+       (and:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,r")
+               (match_operand:QI 2 "general_operand" "r,Q>,O,g,!To")))]
+  ""
+  "@
+   and.b %2,%0
+   and.b %2,%0
+   andQ %b2,%0
+   and.b %2,%0
+   and.b %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,no,no")
+   (set_attr "cc" "normal,normal,clobber,normal,normal")])
+\f
+;; Bitwise or.
+
+;; Same comment as anddi3 applies here - no need for such a pattern.
+
+;; It seems there's no need to jump through hoops to get good code such as
+;; with andsi3.
+
+(define_insn "iorsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r")
+       (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,r")
+               (match_operand:SI 2 "general_operand" "I,r,Q>,n,g,!To")))]
+  ""
+  "@
+   orq %2,%0
+   or.d %2,%0
+   or.d %2,%0
+   oR.%s2 %2,%0
+   or.d %2,%0
+   or.d %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,no,no,no")
+   (set_attr "cc" "normal,normal,normal,clobber,normal,normal")])
+
+(define_insn "iorhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
+       (ior:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0,r")
+               (match_operand:HI 2 "general_operand" "I,r,Q>,L,O,g,!To")))]
+  ""
+  "@
+   orq %2,%0
+   or.w %2,%0
+   or.w %2,%0
+   or.w %2,%0
+   oRq %b2,%0
+   or.w %2,%0
+   or.w %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,no,yes,no,no")
+   (set_attr "cc" "clobber,normal,normal,normal,clobber,normal,normal")])
+
+(define_insn "iorqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r")
+       (ior:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0,r")
+               (match_operand:QI 2 "general_operand" "I,r,Q>,O,g,!To")))]
+  ""
+  "@
+   orq %2,%0
+   or.b %2,%0
+   or.b %2,%0
+   orQ %b2,%0
+   or.b %2,%0
+   or.b %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,no,no")
+   (set_attr "cc" "clobber,normal,normal,clobber,normal,normal")])
+\f
+;; Exclusive-or
+
+;; See comment about "anddi3" for xordi3 - no need for such a pattern.
+
+(define_insn "xorsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (xor:SI (match_operand:SI 1 "register_operand" "%0")
+               (match_operand:SI 2 "register_operand" "r")))]
+  ""
+  "xor %2,%0"
+  [(set_attr "slottable" "yes")])
+
+(define_insn "xorhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (xor:HI (match_operand:HI 1 "register_operand" "%0")
+               (match_operand:HI 2 "register_operand" "r")))]
+  ""
+  "xor %2,%0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "clobber")])
+
+(define_insn "xorqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (xor:QI (match_operand:QI 1 "register_operand" "%0")
+               (match_operand:QI 2 "register_operand" "r")))]
+  ""
+  "xor %2,%0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "clobber")])
+\f
+;; Negation insns.
+
+;; Questionable use, here mostly as a (slightly usable) define_expand
+;; example.
+
+(define_expand "negsf2"
+  [(set (match_dup 2)
+        (match_dup 3))
+   (parallel [(set (match_operand:SF 0 "register_operand" "=r")
+                   (neg:SF (match_operand:SF 1
+                            "register_operand" "0")))
+              (use (match_dup 2))])]
+  ""
+  "
+{
+  operands[2] = gen_reg_rtx (SImode);
+  operands[3] = GEN_INT (1 << 31);
+}")
+
+(define_insn "*expanded_negsf2"
+  [(set (match_operand:SF 0 "register_operand" "=r")
+       (neg:SF (match_operand:SF 1 "register_operand" "0")))
+   (use (match_operand:SI 2 "register_operand" "r"))]
+  ""
+  "xor %2,%0"
+  [(set_attr "slottable" "yes")])
+
+;; No "negdi2" although we could make one up that may be faster than
+;; the one in libgcc.
+
+(define_insn "negsi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (neg:SI (match_operand:SI 1 "register_operand" "r")))]
+  ""
+  "neg.d %1,%0"
+  [(set_attr "slottable" "yes")])
+
+(define_insn "neghi2"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (neg:HI (match_operand:HI 1 "register_operand" "r")))]
+  ""
+  "neg.w %1,%0"
+  [(set_attr "slottable" "yes")])
+
+(define_insn "negqi2"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (neg:QI (match_operand:QI 1 "register_operand" "r")))]
+  ""
+  "neg.b %1,%0"
+  [(set_attr "slottable" "yes")])
+\f
+;; One-complements.
+
+;; See comment on anddi3 - no need for a DImode pattern.
+
+(define_insn "one_cmplsi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (not:SI (match_operand:SI 1 "register_operand" "0")))]
+  ""
+  "not %0"
+  [(set_attr "slottable" "yes")])
+
+(define_insn "one_cmplhi2"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (not:HI (match_operand:HI 1 "register_operand" "0")))]
+  ""
+  "not %0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "clobber")])
+
+(define_insn "one_cmplqi2"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (not:QI (match_operand:QI 1 "register_operand" "0")))]
+  ""
+  "not %0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "clobber")])
+\f
+;; Arithmetic shift right.
+
+(define_insn "ashrsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
+                    (match_operand:SI 2 "nonmemory_operand" "Kr")))]
+  ""
+  "*
+{
+  if (REG_S_P (operands[2]))
+    return \"asr.d %2,%0\";
+
+  return \"asrq %2,%0\";
+}"
+  [(set_attr "slottable" "yes")])
+
+;; Since gcc gets lost, and forgets to zero-extend the source (or mask
+;; the destination) when it changes shifts of lower modes into SImode,
+;; it is better to make these expands an anonymous patterns instead of
+;; the more correct define_insns.  This occurs when gcc thinks that is
+;; is better to widen to SImode and use immediate shift count.
+
+;; FIXME: Is this legacy or still true for gcc >= 2.7.2?
+
+(define_expand "ashrhi3"
+  [(set (match_dup 3)
+       (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))
+   (set (match_dup 4)
+       (zero_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rm")))
+   (set (match_dup 5) (ashiftrt:SI (match_dup 3) (match_dup 4)))
+   (set (match_operand:HI 0 "general_operand" "=g")
+       (subreg:HI (match_dup 5) 0))]
+  ""
+  "
+{
+  int i;
+
+  for (i = 3; i < 6; i++)
+    operands[i] = gen_reg_rtx (SImode);
+}")
+
+(define_insn "*expanded_ashrhi"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
+                    (match_operand:HI 2 "register_operand" "r")))]
+  ""
+  "asr.w %2,%0"
+  [(set_attr "slottable" "yes")])
+
+(define_insn "*ashrhi_lowpart"
+  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r"))
+       (ashiftrt:HI (match_dup 0)
+                    (match_operand:HI 1 "register_operand" "r")))]
+  ""
+  "asr.w %1,%0"
+  [(set_attr "slottable" "yes")])
+
+;; Same comment goes as for "ashrhi3".
+
+(define_expand "ashrqi3"
+  [(set (match_dup 3)
+       (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))
+   (set (match_dup 4)
+       (zero_extend:SI (match_operand:QI 2 "nonimmediate_operand" "g")))
+   (set (match_dup 5) (ashiftrt:SI (match_dup 3) (match_dup 4)))
+   (set (match_operand:QI 0 "general_operand" "=g")
+       (subreg:QI (match_dup 5) 0))]
+  ""
+  "
+{
+  int i;
+
+  for (i = 3; i < 6; i++)
+    operands[i] = gen_reg_rtx (SImode);
+}")
+
+(define_insn "*expanded_ashrqi"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
+                    (match_operand:QI 2 "register_operand" "r")))]
+  ""
+  "asr.b %2,%0"
+  [(set_attr "slottable" "yes")])
+
+;; A strict_low_part matcher.
+
+(define_insn "*ashrqi_lowpart"
+  [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r"))
+       (ashiftrt:QI (match_dup 0)
+                    (match_operand:QI 1 "register_operand" "r")))]
+  ""
+  "asr.b %1,%0"
+  [(set_attr "slottable" "yes")])
+\f
+;; Logical shift right.
+
+(define_insn "lshrsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
+                    (match_operand:SI 2 "nonmemory_operand" "Kr")))]
+  ""
+  "*
+{
+  if (REG_S_P (operands[2]))
+    return \"lsr.d %2,%0\";
+
+  return \"lsrq %2,%0\";
+}"
+  [(set_attr "slottable" "yes")])
+
+;; Same comments as for ashrhi3.
+
+(define_expand "lshrhi3"
+  [(set (match_dup 3)
+       (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))
+   (set (match_dup 4)
+       (zero_extend:SI (match_operand:HI 2 "nonimmediate_operand" "g")))
+   (set (match_dup 5) (lshiftrt:SI (match_dup 3) (match_dup 4)))
+   (set (match_operand:HI 0 "general_operand" "=g")
+       (subreg:HI (match_dup 5) 0))]
+  ""
+  "
+{
+  int i;
+
+  for (i = 3; i < 6; i++)
+    operands[i] = gen_reg_rtx (SImode);
+}")
+
+(define_insn "*expanded_lshrhi"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
+                    (match_operand:HI 2 "register_operand" "r")))]
+  ""
+  "lsr.w %2,%0"
+  [(set_attr "slottable" "yes")])
+
+;; A strict_low_part matcher.
+
+(define_insn "*lshrhi_lowpart"
+  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r"))
+       (lshiftrt:HI (match_dup 0)
+                    (match_operand:HI 1 "register_operand" "r")))]
+  ""
+  "lsr.w %1,%0"
+  [(set_attr "slottable" "yes")])
+
+;; Same comments as for ashrhi3.
+
+(define_expand "lshrqi3"
+  [(set (match_dup 3)
+       (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))
+   (set (match_dup 4)
+       (zero_extend:SI (match_operand:QI 2 "nonimmediate_operand" "g")))
+   (set (match_dup 5) (lshiftrt:SI (match_dup 3) (match_dup 4)))
+   (set (match_operand:QI 0 "general_operand" "=g")
+       (subreg:QI (match_dup 5) 0))]
+  ""
+  "
+{
+  int i;
+
+  for (i = 3; i < 6; i++)
+    operands[i] = gen_reg_rtx (SImode);
+}")
+
+(define_insn "*expanded_lshrqi"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
+                    (match_operand:QI 2 "register_operand" "r")))]
+  ""
+  "lsr.b %2,%0"
+  [(set_attr "slottable" "yes")])
+
+;; A strict_low_part matcher.
+
+(define_insn "*lshrqi_lowpart"
+  [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r"))
+       (lshiftrt:QI (match_dup 0)
+                    (match_operand:QI 1 "register_operand" "r")))]
+  ""
+  "lsr.b %1,%0"
+  [(set_attr "slottable" "yes")])
+\f
+;; Arithmetic/logical shift left.
+
+(define_insn "ashlsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ashift:SI (match_operand:SI 1 "register_operand" "0")
+                  (match_operand:SI 2 "nonmemory_operand" "Kr")))]
+  ""
+  "*
+{
+  if (REG_S_P (operands[2]))
+    return \"lsl.d %2,%0\";
+
+  return \"lslq %2,%0\";
+}"
+  [(set_attr "slottable" "yes")])
+
+;; For narrower modes than SI, we can use lslq although it makes cc
+;; unusable.  The win is that we do not have to reload the shift-count
+;; into a register.
+
+(define_insn "ashlhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (ashift:HI (match_operand:HI 1 "register_operand" "0,0")
+                  (match_operand:HI 2 "nonmemory_operand" "r,K")))]
+  ""
+  "*
+{
+  return
+    (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 15)
+    ? \"moveq 0,%0\"
+    : (CONSTANT_P (operands[2])
+       ? \"lslq %2,%0\" : \"lsl.w %2,%0\");
+}"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "normal,clobber")])
+
+;; A strict_low_part matcher.
+
+(define_insn "*ashlhi_lowpart"
+  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r"))
+       (ashift:HI (match_dup 0)
+                  (match_operand:HI 1 "register_operand" "r")))]
+  ""
+  "lsl.w %1,%0"
+  [(set_attr "slottable" "yes")])
+
+(define_insn "ashlqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,r")
+       (ashift:QI (match_operand:QI 1 "register_operand" "0,0")
+                  (match_operand:QI 2 "nonmemory_operand" "r,K")))]
+  ""
+  "*
+{
+  return
+    (GET_CODE (operands[2]) == CONST_INT
+     && INTVAL (operands[2]) > 7)
+    ? \"moveq 0,%0\"
+    : (CONSTANT_P (operands[2])
+       ? \"lslq %2,%0\" : \"lsl.b %2,%0\");
+}"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "normal,clobber")])
+
+;; A strict_low_part matcher.
+
+(define_insn "*ashlqi_lowpart"
+  [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r"))
+       (ashift:QI (match_dup 0)
+                  (match_operand:QI 1 "register_operand" "r")))]
+  ""
+  "lsl.b %1,%0"
+  [(set_attr "slottable" "yes")])
+\f
+;; Various strange insns that gcc likes.
+
+;; Fortunately, it is simple to construct an abssf (although it may not
+;; be very much used in practice).
+
+(define_insn "abssf2"
+  [(set (match_operand:SF 0 "register_operand" "=r")
+       (abs:SF (match_operand:SF 1 "register_operand" "0")))]
+  ""
+  "lslq 1,%0\;lsrq 1,%0")
+
+(define_insn "abssi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (abs:SI (match_operand:SI 1 "register_operand" "r")))]
+  ""
+  "abs %1,%0"
+  [(set_attr "slottable" "yes")])
+
+;; FIXME: GCC should be able to do these expansions itself.
+
+(define_expand "abshi2"
+  [(set (match_dup 2)
+       (sign_extend:SI (match_operand:HI 1 "general_operand" "g")))
+   (set (match_dup 3) (abs:SI (match_dup 2)))
+   (set (match_operand:HI 0 "register_operand" "=r")
+       (subreg:HI (match_dup 3) 0))]
+  ""
+  "operands[2] = gen_reg_rtx (SImode); operands[3] = gen_reg_rtx (SImode);")
+
+(define_expand "absqi2"
+  [(set (match_dup 2)
+       (sign_extend:SI (match_operand:QI 1 "general_operand" "g")))
+   (set (match_dup 3) (abs:SI (match_dup 2)))
+   (set (match_operand:QI 0 "register_operand" "=r")
+       (subreg:QI (match_dup 3) 0))]
+  ""
+  "operands[2] = gen_reg_rtx (SImode); operands[3] = gen_reg_rtx (SImode);")
+\f
+;; Bound-insn.  Defined to be the same as an unsigned minimum, which is an
+;; operation supported by gcc.  Used in casesi, but used now and then in
+;; normal code too.
+
+(define_insn "uminsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (umin:SI  (match_operand:SI 1 "register_operand" "%0,0,0,r")
+                 (match_operand:SI 2 "general_operand" "r,Q>,g,!STo")))]
+  ""
+  "*
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      if (INTVAL (operands[2]) < 256)
+       return \"bound.b %2,%0\";
+
+      if (INTVAL (operands[2]) < 65536)
+       return \"bound.w %2,%0\";
+    }
+  else if (which_alternative == 3)
+    return \"bound.d %2,%1,%0\";
+
+  return \"bound.d %2,%0\";
+}"
+ [(set_attr "slottable" "yes,yes,no,no")])
+\f
+;; Jump and branch insns.
+
+(define_insn "jump"
+  [(set (pc)
+       (label_ref (match_operand 0 "" "")))]
+  ""
+  "ba %l0%#"
+  [(set_attr "slottable" "has_slot")])
+
+;; Testcase gcc.c-torture/compile/991213-3.c fails if we allow a constant
+;; here, since the insn is not recognized as an indirect jump by
+;; jmp_uses_reg_or_mem used by computed_jump_p.  Perhaps it is a kludge to
+;; change from general_operand to nonimmediate_operand (at least the docs
+;; should be changed), but then again the pattern is called indirect_jump.
+(define_insn "indirect_jump"
+  [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
+  ""
+  "jump %0")
+
+;; Return insn.  Used whenever the epilogue is very simple; if it is only
+;; a single ret or jump [sp+] or a contiguous sequence of movem:able saved
+;; registers.  No allocated stack space is allowed.
+;; Note that for this pattern, although named, it is ok to check the
+;; context of the insn in the test, not only compiler switches.
+
+(define_insn "return"
+  [(return)]
+  "cris_simple_epilogue ()"
+  "*
+{
+  int i;
+
+  /* Just needs to hold a 'movem [sp+],rN'.  */
+  char rd[sizeof (\"movem [$sp+],$r99\")];
+
+  *rd = 0;
+
+  /* Start from the last call-saved register.  We know that we have a
+     simple epilogue, so we just have to find the last register in the
+     movem sequence.  */
+  for (i = 8; i >= 0; i--)
+    if (regs_ever_live[i]
+       || (i == PIC_OFFSET_TABLE_REGNUM
+           && current_function_uses_pic_offset_table))
+      break;
+
+  if (i >= 0)
+    sprintf (rd, \"movem [$sp+],$%s\", reg_names [i]);
+
+  if (regs_ever_live[CRIS_SRP_REGNUM])
+    {
+      if (*rd)
+       output_asm_insn (rd, operands);
+      return \"jump [$sp+]\";
+    }
+
+  if (*rd)
+    {
+      output_asm_insn (\"reT\", operands);
+      output_asm_insn (rd, operands);
+      return \"\";
+    }
+
+  return \"ret%#\";
+}"
+  [(set (attr "slottable")
+       (if_then_else
+        (ne (symbol_ref "regs_ever_live[CRIS_SRP_REGNUM]") (const_int 0))
+        (const_string "no")         ; If jump then not slottable.
+        (if_then_else
+         (ne (symbol_ref
+              "(regs_ever_live[0]
+                || (flag_pic != 0 && regs_ever_live[1])
+                || (PIC_OFFSET_TABLE_REGNUM == 0
+                    && cris_cfun_uses_pic_table ()))")
+             (const_int 0))
+         (const_string "no") ; ret+movem [sp+],rx: slot already filled.
+         (const_string "has_slot")))) ; If ret then need to fill a slot.
+   (set_attr "cc" "none")])
+\f
+;; Conditional branches.
+
+;; We suffer from the same overflow-bit-gets-in-the-way problem as
+;; e.g. m68k, so we have to check if overflow bit is set on all "signed"
+;; conditions.
+
+(define_insn "beq"
+  [(set (pc)
+       (if_then_else (eq (cc0)
+                         (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  ""
+  "beq %l0%#"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "bne"
+  [(set (pc)
+       (if_then_else (ne (cc0)
+                         (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  ""
+  "bne %l0%#"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "bgt"
+  [(set (pc)
+       (if_then_else (gt (cc0)
+                         (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? 0 : \"bgt %l0%#\";
+}"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "bgtu"
+  [(set (pc)
+       (if_then_else (gtu (cc0)
+                          (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  ""
+  "bhi %l0%#"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "blt"
+  [(set (pc)
+       (if_then_else (lt (cc0)
+                         (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? \"bmi %l0%#\" : \"blt %l0%#\";
+}"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "bltu"
+  [(set (pc)
+       (if_then_else (ltu (cc0)
+                          (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  ""
+  "blo %l0%#"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "bge"
+  [(set (pc)
+       (if_then_else (ge (cc0)
+                         (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? \"bpl %l0%#\" : \"bge %l0%#\";
+}"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "bgeu"
+  [(set (pc)
+       (if_then_else (geu (cc0)
+                          (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  ""
+  "bhs %l0%#"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "ble"
+  [(set (pc)
+       (if_then_else (le (cc0)
+                         (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? 0 : \"ble %l0%#\";
+}"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "bleu"
+  [(set (pc)
+       (if_then_else (leu (cc0)
+                          (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  ""
+  "bls %l0%#"
+  [(set_attr "slottable" "has_slot")])
+\f
+;; Reversed anonymous patterns to the ones above, as mandated.
+
+(define_insn "*beq_reversed"
+  [(set (pc)
+       (if_then_else (eq (cc0)
+                         (const_int 0))
+                     (pc)
+                     (label_ref (match_operand 0 "" ""))))]
+  ""
+  "bne %l0%#"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "*bne_reversed"
+  [(set (pc)
+       (if_then_else (ne (cc0)
+                         (const_int 0))
+                     (pc)
+                     (label_ref (match_operand 0 "" ""))))]
+  ""
+  "beq %l0%#"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "*bgt_reversed"
+  [(set (pc)
+       (if_then_else (gt (cc0)
+                         (const_int 0))
+                     (pc)
+                     (label_ref (match_operand 0 "" ""))))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? 0 : \"ble %l0%#\";
+}"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "*bgtu_reversed"
+  [(set (pc)
+       (if_then_else (gtu (cc0)
+                          (const_int 0))
+                     (pc)
+                     (label_ref (match_operand 0 "" ""))))]
+  ""
+  "bls %l0%#"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "*blt_reversed"
+  [(set (pc)
+       (if_then_else (lt (cc0)
+                         (const_int 0))
+                     (pc)
+                     (label_ref (match_operand 0 "" ""))))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? \"bpl %l0%#\" : \"bge %l0%#\";
+}"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "*bltu_reversed"
+  [(set (pc)
+       (if_then_else (ltu (cc0)
+                          (const_int 0))
+                     (pc)
+                     (label_ref (match_operand 0 "" ""))))]
+  ""
+  "bhs %l0%#"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "*bge_reversed"
+  [(set (pc)
+       (if_then_else (ge (cc0)
+                         (const_int 0))
+                     (pc)
+                     (label_ref (match_operand 0 "" ""))))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? \"bmi %l0%#\" : \"blt %l0%#\";
+}"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "*bgeu_reversed"
+  [(set (pc)
+       (if_then_else (geu (cc0)
+                          (const_int 0))
+                     (pc)
+                     (label_ref (match_operand 0 "" ""))))]
+  ""
+  "blo %l0%#"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "*ble_reversed"
+  [(set (pc)
+       (if_then_else (le (cc0)
+                         (const_int 0))
+                     (pc)
+                     (label_ref (match_operand 0 "" ""))))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? 0 : \"bgt %l0%#\";
+}"
+  [(set_attr "slottable" "has_slot")])
+
+(define_insn "*bleu_reversed"
+  [(set (pc)
+       (if_then_else (leu (cc0)
+                          (const_int 0))
+                     (pc)
+                     (label_ref (match_operand 0 "" ""))))]
+  ""
+  "bhi %l0%#"
+  [(set_attr "slottable" "has_slot")])
+\f
+;; Set on condition: sCC.
+
+;; Like bCC, we have to check the overflow bit for
+;; signed conditions.
+
+(define_insn "sgeu"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (geu:SI (cc0) (const_int 0)))]
+  ""
+  "shs %0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "none")])
+
+(define_insn "sltu"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ltu:SI (cc0) (const_int 0)))]
+  ""
+  "slo %0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "none")])
+
+(define_insn "seq"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (eq:SI (cc0) (const_int 0)))]
+  ""
+  "seq %0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "none")])
+
+(define_insn "sge"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ge:SI (cc0) (const_int 0)))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? \"spl %0\" : \"sge %0\";
+}"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "none")])
+
+(define_insn "sgt"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (gt:SI (cc0) (const_int 0)))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? 0 : \"sgt %0\";
+}"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "none")])
+
+(define_insn "sgtu"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (gtu:SI (cc0) (const_int 0)))]
+  ""
+  "shi %0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "none")])
+
+(define_insn "sle"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (le:SI (cc0) (const_int 0)))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? 0 : \"sle %0\";
+}"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "none")])
+
+(define_insn "sleu"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (leu:SI (cc0) (const_int 0)))]
+  ""
+  "sls %0"
+  [(set_attr "slottable" "yes")])
+
+(define_insn "slt"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (lt:SI (cc0) (const_int 0)))]
+  ""
+  "*
+{
+  return
+    (cc_prev_status.flags & CC_NO_OVERFLOW)
+    ? \"smi %0\" : \"slt %0\";
+}"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "none")])
+
+(define_insn "sne"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ne:SI (cc0) (const_int 0)))]
+  ""
+  "sne %0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "none")])
+\f
+;; Call insns.
+
+;; We need to make these patterns "expand", since the real operand is
+;; hidden in a (mem:QI ) inside operand[0] (call_value: operand[1]),
+;; and cannot be checked if it were a "normal" pattern.
+;;  Note that "call" and "call_value" are *always* called with a
+;; mem-operand for operand 0 and 1 respective.  What happens for combined
+;; instructions is a different issue.
+
+(define_expand "call"
+  [(parallel [(call (match_operand:QI 0 "cris_mem_call_operand" "")
+                   (match_operand 1 "general_operand" ""))
+             ;; 16 is the srp (can't use the symbolic name here)
+             (clobber (reg:SI 16))])]
+  ""
+  "
+{
+  rtx op0;
+
+  if (GET_CODE (operands[0]) != MEM)
+    abort ();
+
+  if (flag_pic)
+    {
+      op0 = XEXP (operands[0], 0);
+
+      /* It might be that code can be generated that jumps to 0 (or to a
+        specific address).  Don't abort on that.  At least there's a
+        test-case.  */
+      if (CONSTANT_ADDRESS_P (op0) && GET_CODE (op0) != CONST_INT)
+       {
+         if (no_new_pseudos)
+           abort ();
+
+         /* For local symbols (non-PLT), get the plain symbol reference
+            into a register.  For symbols that can be PLT, make them PLT.  */
+         if (cris_gotless_symbol (op0) || GET_CODE (op0) != SYMBOL_REF)
+           op0 = force_reg (Pmode, op0);
+         else if (cris_symbol (op0))
+           /* FIXME: Would hanging a REG_EQUIV/EQUAL on that register
+              for the symbol cause bad recombinatorial effects?  */
+           op0 = force_reg (Pmode,
+                            gen_rtx_CONST
+                            (VOIDmode,
+                             gen_rtx_UNSPEC (VOIDmode,
+                                             gen_rtvec (1, op0), 0)));
+         else
+           abort ();
+
+         operands[0] = gen_rtx_MEM (GET_MODE (operands[0]), op0);
+       }
+    }
+}")
+
+;; Accept *anything* as operand 1.  Accept operands for operand 0 in
+;; order of preference (Q includes r, but r is shorter, faster)
+
+(define_insn "*expanded_call"
+  [(call (mem:QI (match_operand:SI
+                 0 "cris_general_operand_or_plt_symbol" "r,Q>,g,S"))
+        (match_operand 1 "" ""))
+   (clobber (reg:SI 16))] ;; 16 is the srp (can't use symbolic name)
+  "! TARGET_AVOID_GOTPLT"
+  "jsr %0")
+
+;; Same as above, since can't afford wasting a constraint letter to mean
+;; "S unless TARGET_AVOID_GOTPLT".
+(define_insn "*expanded_call_no_gotplt"
+  [(call (mem:QI (match_operand:SI
+                 0 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
+        (match_operand 1 "" ""))
+   (clobber (reg:SI 16))] ;; 16 is the srp (can't use symbolic name)
+  "TARGET_AVOID_GOTPLT"
+  "jsr %0")
+
+(define_expand "call_value"
+  [(parallel [(set (match_operand 0 "" "")
+                  (call (match_operand:QI 1 "cris_mem_call_operand" "")
+                        (match_operand 2 "" "")))
+             ;; 16 is the srp (can't use symbolic name)
+             (clobber (reg:SI 16))])]
+  ""
+  "
+{
+  rtx op1;
+
+  if (GET_CODE (operands[1]) != MEM)
+    abort ();
+
+  if (flag_pic)
+    {
+      op1 = XEXP (operands[1], 0);
+
+      /* It might be that code can be generated that jumps to 0 (or to a
+        specific address).  Don't abort on that.  At least there's a
+        test-case.  */
+      if (CONSTANT_ADDRESS_P (op1) && GET_CODE (op1) != CONST_INT)
+       {
+         if (no_new_pseudos)
+           abort ();
+
+         if (cris_gotless_symbol (op1))
+           op1 = force_reg (Pmode, op1);
+         else if (cris_symbol (op1))
+           /* FIXME: Would hanging a REG_EQUIV/EQUAL on that register
+              for the symbol cause bad recombinatorial effects?  */
+           op1 = force_reg (Pmode,
+                            gen_rtx_CONST
+                            (VOIDmode,
+                             gen_rtx_UNSPEC (VOIDmode,
+                                             gen_rtvec (1, op1), 0)));
+         else
+           abort ();
+
+         operands[1] = gen_rtx_MEM (GET_MODE (operands[1]), op1);
+       }
+    }
+}")
+
+;; Accept *anything* as operand 2.  The validity other than "general" of
+;; operand 0 will be checked elsewhere.  Accept operands for operand 1 in
+;; order of preference (Q includes r, but r is shorter, faster).
+;;  We also accept a PLT symbol.  We output it as [rPIC+sym:GOTPLT] rather
+;; than requiring getting rPIC + sym:PLT into a register.
+
+(define_insn "*expanded_call_value"
+  [(set (match_operand 0 "nonimmediate_operand" "=g,g,g,g")
+       (call (mem:QI (match_operand:SI
+                      1 "cris_general_operand_or_plt_symbol" "r,Q>,g,S"))
+             (match_operand 2 "" "")))
+   (clobber (reg:SI 16))]
+  "! TARGET_AVOID_GOTPLT"
+  "Jsr %1"
+  [(set_attr "cc" "clobber")])
+
+;; Same as above, since can't afford wasting a constraint letter to mean
+;; "S unless TARGET_AVOID_GOTPLT".
+(define_insn "*expanded_call_value_no_gotplt"
+  [(set (match_operand 0 "nonimmediate_operand" "=g,g,g")
+       (call (mem:QI (match_operand:SI
+                      1 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
+             (match_operand 2 "" "")))
+   (clobber (reg:SI 16))]
+  "TARGET_AVOID_GOTPLT"
+  "Jsr %1"
+  [(set_attr "cc" "clobber")])
+
+;; Used in debugging.  No use for the direct pattern; unfilled
+;; delayed-branches are taken care of by other means.
+
+(define_insn "nop"
+  [(const_int 0)]
+  ""
+  "nop"
+  [(set_attr "cc" "none")])
+\f
+;; We expand on casesi so we can use "bound" and "add offset fetched from
+;; a table to pc" (adds.w [pc+%0.w],pc).
+
+;; Note: if you change the "parallel" (or add anything after it) in
+;; this expansion, you must change the macro ASM_OUTPUT_CASE_END
+;; accordingly, to add the default case at the end of the jump-table.
+
+(define_expand "casesi"
+  [(set (match_dup 5) (match_operand:SI 0 "general_operand" ""))
+   (set (match_dup 6)
+       (minus:SI (match_dup 5)
+                 (match_operand:SI 1 "const_int_operand" "n")))
+   (set (match_dup 7)
+       (umin:SI (match_dup 6)
+                (match_operand:SI 2 "const_int_operand" "n")))
+   (parallel
+    [(set (pc)
+         (if_then_else
+          (ltu (match_dup 7) (match_dup 2))
+          (plus:SI (sign_extend:SI
+                    (mem:HI
+                     (plus:SI (mult:SI (match_dup 7) (const_int 2))
+                              (pc))))
+                   (pc))
+          (label_ref (match_operand 4 "" ""))))
+     (use (label_ref (match_operand 3 "" "")))])]
+  ""
+  "
+{
+  operands[2] = plus_constant (operands[2], 1);
+  operands[5] = gen_reg_rtx (SImode);
+  operands[6] = gen_reg_rtx (SImode);
+  operands[7] = gen_reg_rtx (SImode);
+}")
+\f
+;; Split-patterns.  Some of them have modes unspecified.  This
+;; should always be ok; if for no other reason sparc.md has it as
+;; well.
+;;
+;; When register_operand is specified for an operand, we can get a
+;; subreg as well (Axis-990331), so don't just assume that REG_P is true
+;; for a register_operand and that REGNO can be used as is.  It is best to
+;; guard with REG_P, unless it is worth it to adjust for the subreg case.
+
+;; op [rx + 0],ry,rz
+;; The index to rx is optimized into zero, and gone.
+
+;; First, recognize bound [rx],ry,rz; where [rx] is zero-extended,
+;; and add/sub [rx],ry,rz, with zero or sign-extend on [rx].
+;; Split this into:
+;;  move ry,rz
+;;  op [rx],rz
+;; Lose if rz=ry or rx=rz.
+;; Call this op-extend-split
+
+(define_split
+  [(set (match_operand 0 "register_operand" "")
+       (match_operator
+        4 "cris_operand_extend_operator"
+        [(match_operand 1 "register_operand" "")
+         (match_operator
+          3 "cris_extend_operator"
+          [(match_operand 2 "memory_operand" "")])]))]
+  "REG_P (operands[0])
+   && REG_P (operands[1])
+   && REGNO (operands[1]) != REGNO (operands[0])
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && REG_P (XEXP (operands[2], 0))
+   && REGNO (XEXP (operands[2], 0)) != REGNO (operands[0])"
+  [(set (match_dup 0)
+       (match_dup 1))
+   (set (match_dup 0)
+       (match_op_dup
+        4 [(match_dup 0)
+           (match_op_dup 3 [(match_dup 2)])]))]
+  "")
+
+;; As op-extend-split, but recognize and split op [rz],ry,rz into
+;;  ext [rz],rz
+;;  op ry,rz
+;; Do this for plus or bound only, being commutative operations, since we
+;; have swapped the operands.
+;; Call this op-extend-split-rx=rz
+
+(define_split
+  [(set (match_operand 0 "register_operand" "")
+       (match_operator
+        4 "cris_plus_or_bound_operator"
+        [(match_operand 1 "register_operand" "")
+         (match_operator
+          3 "cris_extend_operator"
+          [(match_operand 2 "memory_operand" "")])]))]
+  "REG_P (operands[0])
+   && REG_P (operands[1])
+   && REGNO (operands[1]) != REGNO (operands[0])
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && REG_P (XEXP (operands[2], 0))
+   && REGNO (XEXP (operands[2], 0)) == REGNO (operands[0])"
+  [(set (match_dup 0)
+       (match_op_dup 3 [(match_dup 2)]))
+   (set (match_dup 0)
+       (match_op_dup
+        4 [(match_dup 0)
+           (match_dup 1)]))]
+  "")
+
+;; As the op-extend-split, but swapped operands, and only for
+;; plus or bound, being the commutative extend-operators.  FIXME: Why is
+;; this needed?  Is it?
+;; Call this op-extend-split-swapped
+
+(define_split
+  [(set (match_operand 0 "register_operand" "")
+       (match_operator
+        4 "cris_plus_or_bound_operator"
+        [(match_operator
+          3 "cris_extend_operator"
+          [(match_operand 2 "memory_operand" "")])
+         (match_operand 1 "register_operand" "")]))]
+  "REG_P (operands[0])
+   && REG_P (operands[1])
+   && REGNO (operands[1]) != REGNO (operands[0])
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && REG_P (XEXP (operands[2], 0))
+   && REGNO (XEXP (operands[2], 0)) != REGNO (operands[0])"
+  [(set (match_dup 0)
+       (match_dup 1))
+   (set (match_dup 0)
+       (match_op_dup
+        4 [(match_dup 0)
+           (match_op_dup 3 [(match_dup 2)])]))]
+  "")
+
+;; As op-extend-split-rx=rz, but swapped operands, only for plus or
+;; bound.  Call this op-extend-split-swapped-rx=rz.
+
+(define_split
+  [(set (match_operand 0 "register_operand" "")
+       (match_operator
+        4 "cris_plus_or_bound_operator"
+        [(match_operator
+          3 "cris_extend_operator"
+          [(match_operand 2 "memory_operand" "")])
+         (match_operand 1 "register_operand" "")]))]
+  "REG_P (operands[0])
+   && REG_P (operands[1])
+   && REGNO (operands[1]) != REGNO (operands[0])
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && REG_P (XEXP (operands[2], 0))
+   && REGNO (XEXP (operands[2], 0)) == REGNO (operands[0])"
+  [(set (match_dup 0)
+       (match_op_dup 3 [(match_dup 2)]))
+   (set (match_dup 0)
+       (match_op_dup
+        4 [(match_dup 0)
+           (match_dup 1)]))]
+  "")
+
+;; As op-extend-split, but the mem operand is not extended.
+;;
+;; op [rx],ry,rz changed into
+;;  move ry,rz
+;;  op [rx],rz
+;; lose if ry=rz or rx=rz
+;; Call this op-extend.
+
+(define_split
+  [(set (match_operand 0 "register_operand" "")
+       (match_operator
+        3 "cris_orthogonal_operator"
+        [(match_operand 1 "register_operand" "")
+         (match_operand 2 "memory_operand" "")]))]
+  "REG_P (operands[0])
+   && REG_P (operands[1])
+   && REGNO (operands[1]) != REGNO (operands[0])
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && REG_P (XEXP (operands[2], 0))
+   && REGNO (XEXP (operands[2], 0)) != REGNO (operands[0])"
+  [(set (match_dup 0)
+       (match_dup 1))
+   (set (match_dup 0)
+       (match_op_dup
+        3 [(match_dup 0)
+           (match_dup 2)]))]
+  "")
+
+;; As op-extend-split-rx=rz, non-extended.
+;; Call this op-split-rx=rz
+
+(define_split
+  [(set (match_operand 0 "register_operand" "")
+       (match_operator
+        3 "cris_commutative_orth_op"
+        [(match_operand 2 "memory_operand" "")
+         (match_operand 1 "register_operand" "")]))]
+  "REG_P (operands[0])
+   && REG_P (operands[1])
+   && REGNO (operands[1]) != REGNO (operands[0])
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && REG_P (XEXP (operands[2], 0))
+   && REGNO (XEXP (operands[2], 0)) != REGNO (operands[0])"
+  [(set (match_dup 0)
+       (match_dup 1))
+   (set (match_dup 0)
+       (match_op_dup
+        3 [(match_dup 0)
+           (match_dup 2)]))]
+  "")
+
+;; As op-extend-split-swapped, nonextended.
+;; Call this op-split-swapped.
+
+(define_split
+  [(set (match_operand 0 "register_operand" "")
+       (match_operator
+        3 "cris_commutative_orth_op"
+        [(match_operand 1 "register_operand" "")
+         (match_operand 2 "memory_operand" "")]))]
+  "REG_P (operands[0]) && REG_P (operands[1])
+   && REGNO (operands[1]) != REGNO (operands[0])
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && REG_P (XEXP (operands[2], 0))
+   && REGNO (XEXP (operands[2], 0)) == REGNO (operands[0])"
+  [(set (match_dup 0)
+       (match_dup 2))
+   (set (match_dup 0)
+       (match_op_dup
+        3 [(match_dup 0)
+           (match_dup 1)]))]
+  "")
+
+;; As op-extend-split-swapped-rx=rz, non-extended.
+;; Call this op-split-swapped-rx=rz.
+
+(define_split
+  [(set (match_operand 0 "register_operand" "")
+       (match_operator
+        3 "cris_orthogonal_operator"
+        [(match_operand 2 "memory_operand" "")
+         (match_operand 1 "register_operand" "")]))]
+  "REG_P (operands[0]) && REG_P (operands[1])
+   && REGNO (operands[1]) != REGNO (operands[0])
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && REG_P (XEXP (operands[2], 0))
+   && REGNO (XEXP (operands[2], 0)) == REGNO (operands[0])"
+  [(set (match_dup 0)
+       (match_dup 2))
+   (set (match_dup 0)
+       (match_op_dup
+        3 [(match_dup 0)
+           (match_dup 1)]))]
+  "")
+\f
+;; Splits for all cases in side-effect insns where (possibly after reload
+;; and register allocation) rx and ry in [rx=ry+i] are equal.
+
+;; move.S1 [rx=rx+rz.S2],ry
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+          (mem (plus:SI
+                (mult:SI (match_operand:SI 1 "register_operand" "")
+                         (match_operand:SI 2 "const_int_operand" ""))
+                (match_operand:SI 3 "register_operand" ""))))
+     (set (match_operand:SI 4 "register_operand" "")
+          (plus:SI (mult:SI (match_dup 1)
+                            (match_dup 2))
+                   (match_dup 3)))])]
+  "REG_P (operands[3]) && REG_P (operands[4])
+   && REGNO (operands[3]) == REGNO (operands[4])"
+  [(set (match_dup 4) (plus:SI (mult:SI (match_dup 1) (match_dup 2))
+                               (match_dup 3)))
+   (set (match_dup 0) (match_dup 5))]
+  "operands[5] = gen_rtx_MEM (GET_MODE (operands[0]), operands[3]);")
+
+;; move.S1 [rx=rx+i],ry
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+          (mem
+           (plus:SI (match_operand:SI 1 "cris_bdap_operand" "")
+                    (match_operand:SI 2 "cris_bdap_operand" ""))))
+     (set (match_operand:SI 3 "register_operand" "")
+          (plus:SI (match_dup 1)
+                   (match_dup 2)))])]
+  "(rtx_equal_p (operands[3], operands[1])
+    || rtx_equal_p (operands[3], operands[2]))"
+  [(set (match_dup 3) (plus:SI (match_dup 1) (match_dup 2)))
+   (set (match_dup 0) (match_dup 4))]
+  "operands[4] = gen_rtx_MEM (GET_MODE (operands[0]), operands[3]);")
+
+;; move.S1 ry,[rx=rx+rz.S2]
+
+(define_split
+  [(parallel
+    [(set (mem (plus:SI
+                (mult:SI (match_operand:SI 0 "register_operand" "")
+                         (match_operand:SI 1 "const_int_operand" ""))
+                (match_operand:SI 2 "register_operand" "")))
+          (match_operand 3 "register_operand" ""))
+     (set (match_operand:SI 4 "register_operand" "")
+          (plus:SI (mult:SI (match_dup 0)
+                            (match_dup 1))
+                   (match_dup 2)))])]
+  "REG_P (operands[2]) && REG_P (operands[4])
+   && REGNO (operands[4]) == REGNO (operands[2])"
+  [(set (match_dup 4) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
+                               (match_dup 2)))
+   (set (match_dup 5) (match_dup 3))]
+  "operands[5] = gen_rtx_MEM (GET_MODE (operands[3]), operands[4]);")
+
+;; move.S1 ry,[rx=rx+i]
+
+(define_split
+  [(parallel
+    [(set (mem
+          (plus:SI (match_operand:SI 0 "cris_bdap_operand" "")
+                   (match_operand:SI 1 "cris_bdap_operand" "")))
+          (match_operand 2 "register_operand" ""))
+     (set (match_operand:SI 3 "register_operand" "")
+          (plus:SI (match_dup 0)
+                  (match_dup 1)))])]
+  "(rtx_equal_p (operands[3], operands[0])
+    || rtx_equal_p (operands[3], operands[1]))"
+  [(set (match_dup 3) (plus:SI (match_dup 0) (match_dup 1)))
+   (set (match_dup 5) (match_dup 2))]
+  "operands[5] = gen_rtx_MEM (GET_MODE (operands[2]), operands[3]);")
+
+;; clear.d ry,[rx=rx+rz.S2]
+
+(define_split
+  [(parallel
+    [(set (mem:SI (plus:SI
+                   (mult:SI (match_operand:SI 0 "register_operand" "")
+                            (match_operand:SI 1 "const_int_operand" ""))
+                   (match_operand:SI 2 "register_operand" "")))
+          (const_int 0))
+     (set (match_operand:SI 3 "register_operand" "")
+          (plus:SI (mult:SI (match_dup 0)
+                            (match_dup 1))
+                   (match_dup 2)))])]
+  "REG_P (operands[2]) && REG_P (operands[3])
+   && REGNO (operands[3]) == REGNO (operands[2])"
+  [(set (match_dup 3) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
+                               (match_dup 2)))
+   (set (mem:SI (match_dup 3)) (const_int 0))]
+  "")
+
+;; clear.w ry,[rx=rx+rz.S2]
+
+(define_split
+  [(parallel
+    [(set (mem:HI (plus:SI
+                   (mult:SI (match_operand:SI 0 "register_operand" "")
+                            (match_operand:SI 1 "const_int_operand" ""))
+                   (match_operand:SI 2 "register_operand" "")))
+          (const_int 0))
+     (set (match_operand:SI 3 "register_operand" "")
+          (plus:SI (mult:SI (match_dup 0)
+                            (match_dup 1))
+                   (match_dup 2)))])]
+  "REG_P (operands[2]) && REG_P (operands[3])
+   && REGNO (operands[3]) == REGNO (operands[2])"
+  [(set (match_dup 3) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
+                               (match_dup 2)))
+   (set (mem:HI (match_dup 3)) (const_int 0))]
+  "")
+
+;; clear.b ry,[rx=rx+rz.S2]
+
+(define_split
+  [(parallel
+    [(set (mem:QI (plus:SI
+                   (mult:SI (match_operand:SI 0 "register_operand" "")
+                            (match_operand:SI 1 "const_int_operand" ""))
+                   (match_operand:SI 2 "register_operand" "")))
+          (const_int 0))
+     (set (match_operand:SI 3 "register_operand" "")
+          (plus:SI (mult:SI (match_dup 0)
+                            (match_dup 1))
+                   (match_dup 2)))])]
+  "REG_P (operands[2]) && REG_P (operands[3])
+   && REGNO (operands[3]) == REGNO (operands[2])"
+  [(set (match_dup 3) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
+                               (match_dup 2)))
+   (set (mem:QI (match_dup 3)) (const_int 0))]
+  "")
+
+;; clear.d ry,[rx=rx+i]
+
+(define_split
+  [(parallel
+    [(set (mem:SI
+          (plus:SI (match_operand:SI 0 "cris_bdap_operand" "")
+                   (match_operand:SI 1 "cris_bdap_operand" "")))
+          (const_int 0))
+     (set (match_operand:SI 2 "register_operand" "")
+          (plus:SI (match_dup 0)
+                   (match_dup 1)))])]
+  "(rtx_equal_p (operands[0], operands[2])
+    || rtx_equal_p (operands[2], operands[1]))"
+  [(set (match_dup 2) (plus:SI (match_dup 0) (match_dup 1)))
+   (set (mem:SI (match_dup 2)) (const_int 0))]
+  "")
+
+;; clear.w ry,[rx=rx+i]
+
+(define_split
+  [(parallel
+    [(set (mem:HI
+          (plus:SI (match_operand:SI 0 "cris_bdap_operand" "")
+                   (match_operand:SI 1 "cris_bdap_operand" "")))
+          (const_int 0))
+     (set (match_operand:SI 2 "register_operand" "")
+          (plus:SI (match_dup 0)
+                   (match_dup 1)))])]
+  "(rtx_equal_p (operands[0], operands[2])
+    || rtx_equal_p (operands[2], operands[1]))"
+  [(set (match_dup 2) (plus:SI (match_dup 0) (match_dup 1)))
+   (set (mem:HI (match_dup 2)) (const_int 0))]
+  "")
+
+;; clear.b ry,[rx=rx+i]
+
+(define_split
+  [(parallel
+    [(set (mem:QI
+          (plus:SI (match_operand:SI 0 "cris_bdap_operand" "")
+                   (match_operand:SI 1 "cris_bdap_operand" "")))
+          (const_int 0))
+     (set (match_operand:SI 2 "register_operand" "")
+          (plus:SI (match_dup 0)
+                   (match_dup 1)))])]
+  "(rtx_equal_p (operands[0], operands[2])
+    || rtx_equal_p (operands[2], operands[1]))"
+  [(set (match_dup 2) (plus:SI (match_dup 0) (match_dup 1)))
+   (set (mem:QI (match_dup 2)) (const_int 0))]
+  "")
+
+;; mov(s|u).S1 [rx=rx+rz.S2],ry
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+         (match_operator
+           5 "cris_extend_operator"
+           [(mem (plus:SI
+                  (mult:SI (match_operand:SI 1 "register_operand" "")
+                           (match_operand:SI 2 "const_int_operand" ""))
+                  (match_operand:SI 3 "register_operand" "")))]))
+     (set (match_operand:SI 4 "register_operand" "")
+          (plus:SI (mult:SI (match_dup 1)
+                            (match_dup 2))
+                   (match_dup 3)))])]
+  "REG_P (operands[3])
+   && REG_P (operands[4])
+   && REGNO (operands[3]) == REGNO (operands[4])"
+  [(set (match_dup 4) (plus:SI (mult:SI (match_dup 1) (match_dup 2))
+                               (match_dup 3)))
+   (set (match_dup 0) (match_op_dup 5 [(match_dup 6)]))]
+  "operands[6] = gen_rtx_MEM (GET_MODE (XEXP (operands[5],0)),
+                          operands[4]);")
+
+;; mov(s|u).S1 [rx=rx+i],ry
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+         (match_operator
+           4 "cris_extend_operator"
+           [(mem (plus:SI
+                  (match_operand:SI 1 "cris_bdap_operand" "")
+                  (match_operand:SI 2 "cris_bdap_operand" "")))]))
+     (set (match_operand:SI 3 "register_operand" "")
+          (plus:SI (match_dup 1)
+                   (match_dup 2)))])]
+  "(rtx_equal_p (operands[1], operands[3])
+    || rtx_equal_p (operands[2], operands[3]))"
+  [(set (match_dup 3) (plus:SI (match_dup 1) (match_dup 2)))
+   (set (match_dup 0) (match_op_dup 4 [(match_dup 5)]))]
+  "operands[5] = gen_rtx_MEM (GET_MODE (XEXP (operands[4], 0)),
+                         operands[3]);")
+
+;; op.S1 [rx=rx+i],ry
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+         (match_operator
+           5 "cris_orthogonal_operator"
+           [(match_operand 1 "register_operand" "")
+            (mem (plus:SI
+                  (match_operand:SI 2 "cris_bdap_operand" "")
+                  (match_operand:SI 3 "cris_bdap_operand" "")))]))
+     (set (match_operand:SI 4 "register_operand" "")
+          (plus:SI (match_dup 2)
+                   (match_dup 3)))])]
+  "(rtx_equal_p (operands[4], operands[2])
+    || rtx_equal_p (operands[4], operands[3]))"
+  [(set (match_dup 4) (plus:SI (match_dup 2) (match_dup 3)))
+   (set (match_dup 0) (match_op_dup 5 [(match_dup 1) (match_dup 6)]))]
+  "operands[6] = gen_rtx_MEM (GET_MODE (operands[0]), operands[4]);")
+
+;; op.S1 [rx=rx+rz.S2],ry
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+         (match_operator
+           6 "cris_orthogonal_operator"
+           [(match_operand 1 "register_operand" "")
+            (mem (plus:SI
+                  (mult:SI (match_operand:SI 2 "register_operand" "")
+                           (match_operand:SI 3 "const_int_operand" ""))
+                  (match_operand:SI 4 "register_operand" "")))]))
+     (set (match_operand:SI 5 "register_operand" "")
+          (plus:SI (mult:SI (match_dup 2)
+                            (match_dup 3))
+                  (match_dup 4)))])]
+  "REG_P (operands[4])
+   && REG_P (operands[5])
+   && REGNO (operands[5]) == REGNO (operands[4])"
+  [(set (match_dup 5) (plus:SI (mult:SI (match_dup 2) (match_dup 3))
+                               (match_dup 4)))
+   (set (match_dup 0) (match_op_dup 6 [(match_dup 1) (match_dup 7)]))]
+  "operands[7] = gen_rtx_MEM (GET_MODE (operands[0]), operands[5]);")
+
+;; op.S1 [rx=rx+rz.S2],ry (swapped)
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+         (match_operator
+           6 "cris_commutative_orth_op"
+           [(mem (plus:SI
+                  (mult:SI (match_operand:SI 2 "register_operand" "")
+                           (match_operand:SI 3 "const_int_operand" ""))
+                  (match_operand:SI 4 "register_operand" "")))
+            (match_operand 1 "register_operand" "")]))
+     (set (match_operand:SI 5 "register_operand" "")
+          (plus:SI (mult:SI (match_dup 2)
+                            (match_dup 3))
+                   (match_dup 4)))])]
+  "REG_P (operands[4])
+   && REG_P (operands[5])
+   && REGNO (operands[5]) == REGNO (operands[4])"
+  [(set (match_dup 5) (plus:SI (mult:SI (match_dup 2) (match_dup 3))
+                              (match_dup 4)))
+   (set (match_dup 0) (match_op_dup 6 [(match_dup 7) (match_dup 1)]))]
+  "operands[7] = gen_rtx_MEM (GET_MODE (operands[0]), operands[5]);")
+
+;; op.S1 [rx=rx+i],ry (swapped)
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+         (match_operator
+           5 "cris_commutative_orth_op"
+           [(mem
+             (plus:SI (match_operand:SI 2 "cris_bdap_operand" "")
+                      (match_operand:SI 3 "cris_bdap_operand" "")))
+            (match_operand 1 "register_operand" "")]))
+     (set (match_operand:SI 4 "register_operand" "")
+         (plus:SI (match_dup 2)
+                   (match_dup 3)))])]
+  "(rtx_equal_p (operands[4], operands[2])
+    || rtx_equal_p (operands[4], operands[3]))"
+  [(set (match_dup 4) (plus:SI (match_dup 2) (match_dup 3)))
+   (set (match_dup 0) (match_op_dup 5 [(match_dup 6) (match_dup 1)]))]
+  "operands[6] = gen_rtx_MEM (GET_MODE (operands[0]), operands[4]);")
+
+;; op(s|u).S1 [rx=rx+rz.S2],ry
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+         (match_operator
+           6 "cris_operand_extend_operator"
+           [(match_operand 1 "register_operand" "")
+            (match_operator
+             7 "cris_extend_operator"
+             [(mem (plus:SI
+                    (mult:SI (match_operand:SI 2 "register_operand" "")
+                             (match_operand:SI 3 "const_int_operand" ""))
+                    (match_operand:SI 4 "register_operand" "")))])]))
+     (set (match_operand:SI 5 "register_operand" "")
+          (plus:SI (mult:SI (match_dup 2)
+                            (match_dup 3))
+                   (match_dup 4)))])]
+  "REG_P (operands[4])
+   && REG_P (operands[5])
+   && REGNO (operands[5]) == REGNO (operands[4])"
+  [(set (match_dup 5) (plus:SI (mult:SI (match_dup 2) (match_dup 3))
+                              (match_dup 4)))
+   (set (match_dup 0) (match_op_dup 6 [(match_dup 1) (match_dup 8)]))]
+  "operands[8] = gen_rtx (GET_CODE (operands[7]), GET_MODE (operands[7]),
+                         gen_rtx_MEM (GET_MODE (XEXP (operands[7], 0)),
+                                  operands[5]));")
+
+;; op(s|u).S1 [rx=rx+i],ry
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+         (match_operator
+           5 "cris_operand_extend_operator"
+           [(match_operand 1 "register_operand" "")
+            (match_operator
+             6 "cris_extend_operator"
+             [(mem
+               (plus:SI (match_operand:SI 2 "cris_bdap_operand" "")
+                        (match_operand:SI 3 "cris_bdap_operand" "")
+                        ))])]))
+     (set (match_operand:SI 4 "register_operand" "")
+          (plus:SI (match_dup 2)
+                   (match_dup 3)))])]
+  "(rtx_equal_p (operands[4], operands[2])
+    || rtx_equal_p (operands[4], operands[3]))"
+  [(set (match_dup 4) (plus:SI (match_dup 2) (match_dup 3)))
+   (set (match_dup 0) (match_op_dup 5 [(match_dup 1) (match_dup 7)]))]
+  "operands[7] = gen_rtx (GET_CODE (operands[6]), GET_MODE (operands[6]),
+                          gen_rtx_MEM (GET_MODE (XEXP (operands[6], 0)),
+                                   operands[4]));")
+
+;; op(s|u).S1 [rx=rx+rz.S2],ry (swapped, plus or bound)
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+         (match_operator
+           7 "cris_plus_or_bound_operator"
+           [(match_operator
+             6 "cris_extend_operator"
+             [(mem (plus:SI
+                    (mult:SI (match_operand:SI 2 "register_operand" "")
+                             (match_operand:SI 3 "const_int_operand" ""))
+                    (match_operand:SI 4 "register_operand" "")))])
+            (match_operand 1 "register_operand" "")]))
+     (set (match_operand:SI 5 "register_operand" "")
+          (plus:SI (mult:SI (match_dup 2)
+                            (match_dup 3))
+                   (match_dup 4)))])]
+  "REG_P (operands[4]) && REG_P (operands[5])
+   && REGNO (operands[5]) == REGNO (operands[4])"
+  [(set (match_dup 5) (plus:SI (mult:SI (match_dup 2) (match_dup 3))
+                              (match_dup 4)))
+   (set (match_dup 0) (match_op_dup 6 [(match_dup 8) (match_dup 1)]))]
+  "operands[8] = gen_rtx (GET_CODE (operands[6]), GET_MODE (operands[6]),
+                         gen_rtx_MEM (GET_MODE (XEXP (operands[6], 0)),
+                                  operands[5]));")
+
+;; op(s|u).S1 [rx=rx+i],ry (swapped, plus or bound)
+
+(define_split
+  [(parallel
+    [(set (match_operand 0 "register_operand" "")
+         (match_operator
+           6 "cris_plus_or_bound_operator"
+           [(match_operator
+             5 "cris_extend_operator"
+            [(mem (plus:SI
+                   (match_operand:SI 2 "cris_bdap_operand" "")
+                   (match_operand:SI 3 "cris_bdap_operand" "")))])
+            (match_operand 1 "register_operand" "")]))
+     (set (match_operand:SI 4 "register_operand" "")
+          (plus:SI (match_dup 2)
+                   (match_dup 3)))])]
+  "(rtx_equal_p (operands[4], operands[2])
+    || rtx_equal_p (operands[4], operands[3]))"
+  [(set (match_dup 4) (plus:SI (match_dup 2) (match_dup 3)))
+   (set (match_dup 0) (match_op_dup 6 [(match_dup 7) (match_dup 1)]))]
+  "operands[7] = gen_rtx (GET_CODE (operands[5]), GET_MODE (operands[5]),
+                         gen_rtx_MEM (GET_MODE (XEXP (operands[5], 0)),
+                                  operands[4]));")
+\f
+;; Splits for addressing prefixes that have no side-effects, so we can
+;; fill a delay slot.  Never split if we lose something, though.
+
+;; If we have a
+;;  move [indirect_ref],rx
+;; where indirect ref = {const, [r+], [r]}, it costs as much as
+;;  move indirect_ref,rx
+;;  move [rx],rx
+;; Take care not to allow indirect_ref = register.
+
+;; We're not allowed to generate copies of registers with different mode
+;; until after reload; copying pseudos upsets reload.  CVS as of
+;; 2001-08-24, unwind-dw2-fde.c, _Unwind_Find_FDE ICE in
+;; cselib_invalidate_regno.
+
+(define_split
+  [(set (match_operand 0 "register_operand" "")
+       (match_operand 1 "indirect_operand" ""))]
+  "reload_completed
+   && REG_P (operands[0])
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && (GET_CODE (XEXP (operands[1], 0)) == MEM
+       || CONSTANT_P (XEXP (operands[1], 0)))"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 0) (match_dup 3))]
+  "operands[2] = gen_rtx_REG (Pmode, REGNO (operands[0]));
+   operands[3] = gen_rtx_MEM (GET_MODE (operands[0]), operands[2]);
+   operands[4] = XEXP (operands[1], 0);")
+
+;; As the above, but MOVS and MOVU.
+
+(define_split
+  [(set (match_operand 0 "register_operand" "")
+       (match_operator
+        4 "cris_extend_operator"
+        [(match_operand 1 "indirect_operand" "")]))]
+  "reload_completed
+   && REG_P (operands[0])
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+   && (GET_CODE (XEXP (operands[1], 0)) == MEM
+       || CONSTANT_P (XEXP (operands[1], 0)))"
+  [(set (match_dup 2) (match_dup 5))
+   (set (match_dup 0) (match_op_dup 4 [(match_dup 3)]))]
+  "operands[2] = gen_rtx_REG (Pmode, REGNO (operands[0]));
+   operands[3] = gen_rtx_MEM (GET_MODE (XEXP (operands[4], 0)), operands[2]);
+   operands[5] = XEXP (operands[1], 0);")
+\f
+;; Various peephole optimizations.
+;;
+;; Watch out: when you exchange one set of instructions for another, the
+;; condition codes setting must be the same, or you have to CC_INIT or
+;; whatever is appropriate, in the pattern before you emit the
+;; assembly text.  This is best done here, not in cris_notice_update_cc,
+;; to keep changes local to their cause.
+;;
+;; Do not add patterns that you do not know will be matched.
+;; Please also add a self-contained test-case.
+
+;; We have trouble with and:s and shifts.  Maybe something is broken in
+;; gcc?  Or it could just be that bitfield insn expansion is a bit
+;; suboptimal when not having extzv insns.
+
+(define_peephole
+  [(set (match_operand 0 "register_operand" "=r")
+       (ashiftrt:SI (match_dup 0)
+                    (match_operand:SI 1 "const_int_operand" "n")))
+   (set (match_dup 0)
+       (and:SI (match_dup 0)
+               (match_operand 2 "const_int_operand" "n")))]
+  "INTVAL (operands[2]) > 31
+   && INTVAL (operands[2]) < 255
+   && INTVAL (operands[1]) > 23"
+
+;; The m flag should be ignored, because this will be a *byte* "and"
+;; operation.
+
+  "*
+{
+  cc_status.flags |= CC_NOT_NEGATIVE;
+
+  return \"lsrq %1,%0\;and.b %2,%0\";
+}")
+
+(define_peephole
+  [(set (match_operand 0 "register_operand" "=r")
+       (ashiftrt:SI (match_dup 0)
+                    (match_operand:SI 1 "const_int_operand" "n")))
+   (set (match_dup 0)
+       (and:SI (match_dup 0)
+               (match_operand 2 "const_int_operand" "n")))]
+  "INTVAL (operands[2]) > 31
+   && INTVAL (operands[2]) < 65535
+   && INTVAL (operands[2]) != 255
+   && INTVAL (operands[1]) > 15"
+
+;; The m flag should be ignored, because this will be a *word* "and"
+;; operation.
+
+  "*
+{
+  cc_status.flags |= CC_NOT_NEGATIVE;
+
+  return \"lsrq %1,%0\;and.w %2,%0\";
+}")
+
+(define_peephole
+  [(set (match_operand 0 "register_operand" "=r")
+       (lshiftrt:SI (match_dup 0)
+                    (match_operand:SI 1 "const_int_operand" "n")))
+   (set (match_dup 0)
+       (and:SI (match_dup 0)
+               (match_operand 2 "const_int_operand" "n")))]
+  "INTVAL (operands[2]) > 31
+   && INTVAL (operands[2]) < 255
+   && INTVAL (operands[1]) > 23"
+
+;; The m flag should be ignored, because this will be a *byte* "and"
+;; operation.
+
+  "*
+{
+  cc_status.flags |= CC_NOT_NEGATIVE;
+
+  return \"lsrq %1,%0\;and.b %2,%0\";
+}")
+
+(define_peephole
+  [(set (match_operand 0 "register_operand" "=r")
+       (lshiftrt:SI (match_dup 0)
+                    (match_operand:SI 1 "const_int_operand" "n")))
+   (set (match_dup 0)
+       (and:SI (match_dup 0)
+               (match_operand 2 "const_int_operand" "n")))]
+  "INTVAL (operands[2]) > 31 && INTVAL (operands[2]) < 65535
+   && INTVAL (operands[2]) != 255
+   && INTVAL (operands[1]) > 15"
+
+;; The m flag should be ignored, because this will be a *word* "and"
+;; operation.
+
+  "*
+{
+  cc_status.flags |= CC_NOT_NEGATIVE;
+
+  return \"lsrq %1,%0\;and.w %2,%0\";
+}")
+\f
+
+;; Change
+;;  add.d n,rx
+;;  move [rx],ry
+;; into
+;;  move [rx=rx+n],ry
+;; when -128 <= n <= 127.
+;; This will reduce the size of the assembler code for n = [-128..127],
+;; and speed up accordingly.
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_operand:SI 1 "register_operand" "0")
+                (match_operand:SI 2 "const_int_operand" "n")))
+   (set (match_operand 3 "register_operand" "=r")
+       (mem (match_dup 0)))]
+  "GET_MODE (operands[3]) != DImode
+    && REGNO (operands[3]) != REGNO (operands[0])
+    && (BASE_P (operands[1]) || BASE_P (operands[2]))
+    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
+    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+    && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)"
+  "move.%s3 [%0=%1%S2],%3")
+
+;; Vice versa: move ry,[rx=rx+n]
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_operand:SI 1 "register_operand" "0")
+                (match_operand:SI 2 "const_int_operand" "n")))
+   (set (mem (match_dup 0))
+       (match_operand 3 "register_operand" "=r"))]
+  "GET_MODE (operands[3]) != DImode
+    && REGNO (operands[3]) != REGNO (operands[0])
+    && (BASE_P (operands[1]) || BASE_P (operands[2]))
+    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
+    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+    && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)"
+  "move.%s3 %3,[%0=%1%S2]"
+  [(set_attr "cc" "none")])
+\f
+;; As above, change:
+;;  add.d n,rx
+;;  op.d [rx],ry
+;; into:
+;;  op.d [rx=rx+n],ry
+;; Saves when n = [-128..127].
+;;
+;; Splitting and joining combinations for side-effect modes are slightly
+;; out of hand.  They probably will not save the time they take typing in,
+;; not to mention the bugs that creep in.  FIXME: Get rid of as many of
+;; the splits and peepholes as possible.
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_operand:SI 1 "register_operand" "0")
+                (match_operand:SI 2 "const_int_operand" "n")))
+   (set (match_operand 3 "register_operand" "=r")
+       (match_operator 4 "cris_orthogonal_operator"
+                          [(match_dup 3)
+                           (mem (match_dup 0))]))]
+  "GET_MODE (operands[3]) != DImode
+    && REGNO (operands[0]) != REGNO (operands[3])
+    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
+    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+    && INTVAL (operands[2]) >= -128
+    && INTVAL (operands[2]) <= 127"
+  "%x4.%s3 [%0=%1%S2],%3")
+
+;; Sometimes, for some reason the pattern
+;;  move x,rx
+;;  add y,rx
+;;  move [rx],rz
+;; will occur.  Solve this, and likewise for to-memory.
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (match_operand:SI 1 "cris_bdap_biap_operand" "r,>Ri,r,>Ri"))
+   (set (match_dup 0)
+       (plus:SI (match_operand:SI 2 "cris_bdap_biap_operand" "0,0,r>Ri,r")
+                (match_operand:SI 3 "cris_bdap_biap_operand" "r>Ri,r,0,0")))
+   (set (match_operand 4 "register_operand" "=r,r,r,r")
+       (mem (match_dup 0)))]
+  "(rtx_equal_p (operands[2], operands[0])
+    || rtx_equal_p (operands[3], operands[0]))
+   && cris_side_effect_mode_ok (PLUS, operands, 0,
+                                (REG_S_P (operands[1])
+                                 ? 1
+                                 : (rtx_equal_p (operands[2], operands[0])
+                                    ? 3 : 2)),
+                                (! REG_S_P (operands[1])
+                                 ? 1
+                                 : (rtx_equal_p (operands[2], operands[0])
+                                    ? 3 : 2)),
+                                -1, 4)"
+  "@
+   move.%s4 [%0=%1%S3],%4
+   move.%s4 [%0=%3%S1],%4
+   move.%s4 [%0=%1%S2],%4
+   move.%s4 [%0=%2%S1],%4")
+
+;; As above but to memory.
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (match_operand:SI 1 "cris_bdap_biap_operand" "r,>Ri,r,>Ri"))
+   (set (match_dup 0)
+       (plus:SI (match_operand:SI 2 "cris_bdap_biap_operand" "0,0,r>Ri,r")
+                (match_operand:SI 3 "cris_bdap_biap_operand" "r>Ri,r,0,0")))
+   (set (mem (match_dup 0))
+       (match_operand 4 "register_operand" "=r,r,r,r"))]
+  "(rtx_equal_p (operands[2], operands[0])
+    || rtx_equal_p (operands[3], operands[0]))
+   && cris_side_effect_mode_ok (PLUS, operands, 0,
+                                (REG_S_P (operands[1])
+                                 ? 1
+                                 : (rtx_equal_p (operands[2], operands[0])
+                                    ? 3 : 2)),
+                                (! REG_S_P (operands[1])
+                                   ? 1
+                                 : (rtx_equal_p (operands[2], operands[0])
+                                    ? 3 : 2)),
+                                -1, 4)"
+  "@
+   move.%s4 %4,[%0=%1%S3]
+   move.%s4 %4,[%0=%3%S1]
+   move.%s4 %4,[%0=%1%S2]
+   move.%s4 %4,[%0=%2%S1]"
+  [(set_attr "cc" "none")])
+
+
+;; As the move from-memory above, but with an operation.
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (match_operand:SI 1 "cris_bdap_biap_operand" "r,>Ri,r,>Ri"))
+   (set (match_dup 0)
+       (plus:SI (match_operand:SI 2 "cris_bdap_biap_operand" "0,0,r>Ri,r")
+                (match_operand:SI 3 "cris_bdap_biap_operand" "r>Ri,r,0,0")))
+   (set (match_operand 4 "register_operand" "=r,r,r,r")
+       (match_operator 5 "cris_orthogonal_operator"
+                       [(match_dup 3)
+                        (mem (match_dup 0))]))]
+  "(rtx_equal_p (operands[2], operands[0])
+    || rtx_equal_p (operands[3], operands[0]))
+   && cris_side_effect_mode_ok (PLUS, operands, 0,
+                                (REG_S_P (operands[1])
+                                 ? 1
+                                 : (rtx_equal_p (operands[2], operands[0])
+                                    ? 3 : 2)),
+                                (! REG_S_P (operands[1])
+                                 ? 1
+                                 : (rtx_equal_p (operands[2], operands[0])
+                                    ? 3 : 2)),
+                                -1, 4)"
+  "@
+   %x5.%s4 [%0=%1%S3],%4
+   %x5.%s4 [%0=%3%S1],%4
+   %x5.%s4 [%0=%1%S2],%4
+   %x5.%s4 [%0=%2%S1],%4")
+
+;; Same, but with swapped operands (and commutative operation).
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (match_operand:SI 1 "cris_bdap_biap_operand" "r,>Ri,r,>Ri"))
+   (set (match_dup 0)
+       (plus:SI (match_operand:SI 2 "cris_bdap_biap_operand" "0,0,r>Ri,r")
+                (match_operand:SI 3 "cris_bdap_biap_operand" "r>Ri,r,0,0")))
+   (set (match_operand 4 "register_operand" "=r,r,r,r")
+       (match_operator 5 "cris_commutative_orth_op"
+                       [(mem (match_dup 0))
+                        (match_dup 3)]))]
+  "(rtx_equal_p (operands[2], operands[0])
+    || rtx_equal_p (operands[3], operands[0]))
+   && cris_side_effect_mode_ok (PLUS, operands, 0,
+                          (REG_S_P (operands[1])
+                           ? 1
+                           : (rtx_equal_p (operands[2], operands[0])
+                              ? 3 : 2)),
+                          (! REG_S_P (operands[1])
+                           ? 1
+                           : (rtx_equal_p (operands[2], operands[0])
+                              ? 3 : 2)),
+                          -1, 4)"
+  "@
+   %x5.%s4 [%0=%1%S3],%4
+   %x5.%s4 [%0=%3%S1],%4
+   %x5.%s4 [%0=%1%S2],%4
+   %x5.%s4 [%0=%2%S1],%4")
+
+;; Another spotted bad code:
+;;   move rx,ry
+;;   move [ry],ry
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (match_operand:SI 1 "register_operand" "r"))
+   (set (match_operand 2 "register_operand" "=r")
+       (mem (match_dup 0)))]
+  "REGNO (operands[0]) == REGNO (operands[2])
+   && GET_MODE_SIZE (GET_MODE (operands[2])) <= UNITS_PER_WORD"
+  "move.%s2 [%1],%0"
+  [(set_attr "slottable" "yes")])
+
+;; And a simple variant with extended operand.
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (match_operand:SI 1 "register_operand" "r"))
+   (set (match_operand 2 "register_operand" "=r")
+       (match_operator 3 "cris_extend_operator" [(mem (match_dup 0))]))]
+  "REGNO (operands[0]) == REGNO (operands[2])
+   && GET_MODE_SIZE (GET_MODE (operands[2])) <= UNITS_PER_WORD"
+  "mov%e3.%m3 [%1],%0"
+  [(set_attr "slottable" "yes")])
+\f
+;; Here are all peepholes that have a saved testcase.
+;; Do not add new peepholes without testcases.
+
+;; peep-1:
+;;   move.d [r10+16],r9
+;;   and.d r12,r9
+;; change to
+;;   and.d [r10+16],r12,r9
+;; With generalization of the operation, the size and the addressing mode.
+;;  This seems to be the result of a quirk in register allocation
+;; missing the three-operand cases when having different predicates.
+;; Maybe that it matters that it is a commutative operation.
+;;  This pattern helps that situation, but there's still the increased
+;; register pressure.
+;;  Note that adding the noncommutative variant did not show any matches
+;; in ipps and cc1, so it's not here.
+
+(define_peephole
+  [(set (match_operand 0 "register_operand" "=r,r,r,r")
+       (mem (plus:SI
+             (match_operand:SI 1 "cris_bdap_biap_operand" "r,r>Ri,r,r>Ri")
+             (match_operand:SI 2 "cris_bdap_biap_operand" "r>Ri,r,r>Ri,r"))))
+   (set (match_dup 0)
+       (match_operator 5 "cris_commutative_orth_op"
+                       [(match_operand 3 "register_operand" "0,0,r,r")
+                        (match_operand 4 "register_operand" "r,r,0,0")]))]
+  "(rtx_equal_p (operands[3], operands[0])
+    || rtx_equal_p (operands[4], operands[0]))
+   && ! rtx_equal_p (operands[3], operands[4])
+   && (REG_S_P (operands[1]) || REG_S_P (operands[2]))
+   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD"
+  "@
+   %x5.%s0 [%1%S2],%4,%0
+   %x5.%s0 [%2%S1],%4,%0
+   %x5.%s0 [%1%S2],%3,%0
+   %x5.%s0 [%2%S1],%3,%0")
+
+;; peep-2:
+;;  I cannot tell GCC (2.1, 2.7.2) how to correctly reload an instruction
+;; that looks like
+;;   and.b some_byte,const,reg_32
+;; where reg_32 is the destination of the "three-address" code optimally.
+;; It should be:
+;;   movu.b some_byte,reg_32
+;;   and.b const,reg_32
+;; but is turns into:
+;;   move.b some_byte,reg_32
+;;   and.d const,reg_32
+;; Fix it here.
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (match_operand:SI 1 "nonimmediate_operand" "rm"))
+   (set (match_operand:SI 2 "register_operand" "=0")
+       (and:SI (match_dup 0)
+               (match_operand:SI 3 "const_int_operand" "n")))]
+
+   ;; Since the size of the memory access could be made different here,
+   ;; don't do this for a mem-volatile access.
+
+  "REGNO (operands[2]) == REGNO (operands[0])
+   && INTVAL (operands[3]) <= 65535 && INTVAL (operands[3]) >= 0
+   && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'I')
+   && (GET_CODE (operands[1]) != MEM || ! MEM_VOLATILE_P (operands[1]))"
+  "*
+{
+  if (CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'O'))
+    return \"movu.%z3 %1,%0\;andq %b3,%0\";
+
+  cc_status.flags |= CC_NOT_NEGATIVE;
+
+  return \"movu.%z3 %1,%0\;and.%z3 %3,%0\";
+}")
+
+;; peep-3
+
+(define_peephole
+  [(set (match_operand 0 "register_operand" "=r")
+       (match_operand 1 "nonimmediate_operand" "rm"))
+   (set (match_operand:SI 2 "register_operand" "=r")
+       (and:SI (subreg:SI (match_dup 0) 0)
+               (match_operand 3 "const_int_operand" "n")))]
+
+   ;; Since the size of the memory access could be made different here,
+   ;; don't do this for a mem-volatile access.
+
+  "REGNO (operands[0]) == REGNO (operands[2])
+   && INTVAL (operands[3]) > 0
+   && INTVAL (operands[3]) <= 65535
+   && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'I')
+   && (GET_CODE (operands[1]) != MEM || ! MEM_VOLATILE_P (operands[1]))"
+  "*
+{
+  if (CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'O'))
+    return \"movu.%z3 %1,%0\;andq %b3,%0\";
+
+  cc_status.flags |= CC_NOT_NEGATIVE;
+
+  return \"movu.%z3 %1,%0\;and.%z3 %3,%0\";
+}")
+\f
+;; Local variables:
+;; mode:emacs-lisp
+;; comment-start: ";; "
+;; eval: (set-syntax-table (copy-sequence (syntax-table)))
+;; eval: (modify-syntax-entry ?[ "(]")
+;; eval: (modify-syntax-entry ?] ")[")
+;; eval: (modify-syntax-entry ?{ "(}")
+;; eval: (modify-syntax-entry ?} "){")
+;; eval: (setq indent-tabs-mode t)
+;; End:
diff --git a/gcc/config/cris/cris_abi_symbol.c b/gcc/config/cris/cris_abi_symbol.c
new file mode 100644 (file)
index 0000000..a30d205
--- /dev/null
@@ -0,0 +1,56 @@
+/* Define symbol to recognize CRIS ABI version 2, for a.out use.
+   Contributed by Axis Communications.
+   Written by Hans-Peter Nilsson <hp@axis.se>, c:a 1992.
+
+   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file 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 this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+   As a special exception, if you link this library with files, some of
+   which are compiled with GCC, this library does not by itself cause
+   the resulting object or executable to be covered by the GNU General
+   Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file or object might be covered by the GNU General
+   Public License.  */
+
+#include "config.h"
+
+#ifdef __AOUT__
+
+/* ELF support was not released before the ABI was changed, so we
+   restrict this awkwardness to a.out.  This symbol is for gdb to
+   recognize, so it can debug both old and new programs successfully.  */
+__asm__ (".global " CRIS_ABI_VERSION_SYMBOL_STRING);
+__asm__ (".set " CRIS_ABI_VERSION_SYMBOL_STRING ",0");
+
+#else  /* not __AOUT__ */
+
+/* The file must not be empty (declaration/definition-wise) according to
+   ISO, IIRC. */
+extern int _Dummy;
+
+#endif /* not __AOUT__ */
diff --git a/gcc/config/cris/linux.h b/gcc/config/cris/linux.h
new file mode 100644 (file)
index 0000000..b02e19e
--- /dev/null
@@ -0,0 +1,134 @@
+/* Definitions for GCC.  Part of the machine description for CRIS.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Contributed by Axis Communications.  Written by Hans-Peter Nilsson.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+
+/* After the first "Node:" comment comes all preprocessor directives and
+   attached declarations described in the info files, the "Using and
+   Porting GCC" manual (uapgcc), in the same order as found in the "Target
+   macros" section in the gcc-2.9x CVS edition of 2000-03-17.  FIXME: Not
+   really, but needs an update anyway.
+
+   There is no generic copy-of-uapgcc comment, you'll have to see uapgcc
+   for that.  If applicable, there is a CRIS-specific comment.  The order
+   of macro definitions follow the order in the manual.  Every section in
+   the manual (node in the info pages) has an introductory `Node:
+   <subchapter>' comment.  If no macros are defined for a section, only
+   the section-comment is present.  */
+
+/* This file defines the macros for cris-axis-linux-gnu that are not
+   covered by cris.h, elfos.h and (config/)linux.h.  */
+
+
+/* Node: Instruction Output */
+
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
+
+/* Node: Driver */
+/* These macros are CRIS-specific, but used in target driver macros.  */
+
+#undef CRIS_CPP_SUBTARGET_SPEC
+#define CRIS_CPP_SUBTARGET_SPEC \
+  "-D__linux__ -D__unix__  -D__ELF__\
+   %{pthread:-D_REENTRANT}\
+   %{fPIC|fpic: -D__PIC__ -D__pic__}\
+   %{!fleading-underscore:-fno-leading-underscore -D__NO_UNDERSCORES__}\
+   %{!march=*:%{!cpu=*:-D__arch_v10 -D__CRIS_arch_version=10}}\
+   %{!ansi:%{!std=*:%{!undef:-Dlinux -Dunix}\
+     -Asystem(unix) -Asystem(posix) -Acpu(cris) -Amachine(cris)}}"
+
+#undef CRIS_CC1_SUBTARGET_SPEC
+#define CRIS_CC1_SUBTARGET_SPEC \
+ "%{!march=*:%{!cpu=*:-march=v10}}"
+
+#undef CRIS_ASM_SUBTARGET_SPEC
+#define CRIS_ASM_SUBTARGET_SPEC \
+ "--em=criself\
+  %{!fleading-underscore:--no-underscore}\
+  %{fPIC|fpic: --pic}"
+
+/* Provide a legacy -mlinux option.  */
+#undef CRIS_SUBTARGET_SWITCHES
+#define CRIS_SUBTARGET_SWITCHES                                                \
+ {"linux",                              0, ""},                        \
+ {"gotplt",     -TARGET_MASK_AVOID_GOTPLT, ""},                        \
+ {"no-gotplt",   TARGET_MASK_AVOID_GOTPLT,                             \
+  N_("Together with -fpic and -fPIC, do not use GOTPLT references")},
+
+#undef CRIS_SUBTARGET_DEFAULT
+#define CRIS_SUBTARGET_DEFAULT                 \
+  (TARGET_MASK_SVINTO                          \
+   + TARGET_MASK_ETRAX4_ADD                    \
+   + TARGET_MASK_ALIGN_BY_32                   \
+   + TARGET_MASK_ELF                           \
+   + TARGET_MASK_LINUX)
+
+#undef CRIS_DEFAULT_CPU_VERSION
+#define CRIS_DEFAULT_CPU_VERSION CRIS_CPU_NG
+
+#undef CRIS_SUBTARGET_VERSION
+#define CRIS_SUBTARGET_VERSION " - cris-axis-linux-gnu"
+
+
+/* Redefine what was in svr4.h.  Include order madness makes it less
+   useful to include (config/)linux.h after cris.h.  (config/)linux.h
+   includes svr4.h which undef:s lots of supposedly arch-specific macros
+   carefully defined by cris.h.  */
+#undef LIB_SPEC
+#define LIB_SPEC "%{!shared:%{!symbolic:-lc}}"
+
+/* We need an -rpath-link to ld.so.1, and presumably to each directory
+   specified with -B.  */
+#undef CRIS_LINK_SUBTARGET_SPEC
+#define CRIS_LINK_SUBTARGET_SPEC \
+ "-mcrislinux\
+  -rpath-link include/asm/../..%s\
+  %{shared} %{static}\
+  %{symbolic:-Bdynamic} %{shlib:-Bdynamic} %{static:-Bstatic}\
+  %{!shared:%{!static:%{rdynamic:-export-dynamic}}}\
+  %{O2|O3: --gc-sections}"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+ "%{!shared:\
+   %{pg:gcrt1.o%s}\
+   %{!pg:\
+    %{p:gcrt1.o%s}\
+    %{!p:\
+     %{profile:gcrt1.o%s}\
+     %{!profile:crt1.o%s}}}}\
+  crti.o%s\
+  %{!shared:crtbegin.o%s}\
+  %{shared:crtbeginS.o%s}"
+
+
+/* Node: Sections */
+
+/* GNU/Linux has crti and crtn and does not need the
+   FORCE_INIT_SECTION_ALIGN trick in cris.h.  */
+#undef FORCE_INIT_SECTION_ALIGN
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/gcc/config/cris/mulsi3.asm b/gcc/config/cris/mulsi3.asm
new file mode 100644 (file)
index 0000000..3c482e7
--- /dev/null
@@ -0,0 +1,227 @@
+;; This code used to be expanded through interesting expansions in
+;; the machine description, compiled from this code:
+;;
+;; #ifdef L_mulsi3
+;; long __Mul (unsigned long a, unsigned long b) __attribute__ ((__const__));
+;; 
+;; /* This must be compiled with the -mexpand-mul flag, to synthesize the
+;;    multiplication from the mstep instructions.  The check for
+;;    smaller-size multiplication pays off in the order of .5-10%;
+;;    estimated median 1%, depending on application.
+;;     FIXME: It can be further optimized if we go to assembler code, as
+;;    gcc 2.7.2 adds a few unnecessary instructions and does not put the
+;;    basic blocks in optimal order.  */
+;; long
+;; __Mul (unsigned long a, unsigned long b)
+;; {
+;; #if defined (__CRIS_arch_version) && __CRIS_arch_version >= 10
+;;   /* In case other code is compiled without -march=v10, they will
+;;     contain calls to __Mul, regardless of flags at link-time.  The
+;;     "else"-code below will work, but is unnecessarily slow.  This
+;;     sometimes cuts a few minutes off from simulation time by just
+;;     returning a "mulu.d".  */
+;;   return a * b;
+;; #else
+;;   unsigned long min;
+;; 
+;;   /* Get minimum via the bound insn.  */
+;;   min = a < b ? a : b;
+;; 
+;;   /* Can we omit computation of the high part?      */
+;;   if (min > 65535)
+;;     /* No.  Perform full multiplication.  */
+;;     return a * b;
+;;   else
+;;     {
+;;      /* Check if both operands are within 16 bits.  */
+;;      unsigned long max;
+;; 
+;;      /* Get maximum, by knowing the minimum.
+;;         This will partition a and b into max and min.
+;;         This is not currently something GCC understands,
+;;         so do this trick by asm.  */
+;;      __asm__ ("xor %1,%0\n\txor %2,%0"
+;;               : "=r" (max)
+;;               :  "r" (b), "r" (a), "0" (min));
+;; 
+;;     if (max > 65535)
+;;      /* Make GCC understand that only the low part of "min" will be
+;;         used.  */
+;;      return max * (unsigned short) min;
+;;     else
+;;      /* Only the low parts of both operands are necessary.  */
+;;      return ((unsigned short) max) * (unsigned short) min;
+;;     }
+;; #endif /* not __CRIS_arch_version >= 10 */
+;; }
+;; #endif /* L_mulsi3 */
+;;
+;; That approach was abandoned since the caveats outweighted the
+;; benefits.  The expand-multiplication machinery is also removed, so you
+;; can't do this anymore.
+;;
+;; For doubters of there being any benefits, some where: insensitivity to:
+;; - ABI changes (mostly for experimentation)
+;; - assembler syntax differences (mostly debug format).
+;; - insn scheduling issues.
+;; Most ABI experiments will presumably happen with arches with mul insns,
+;; so that argument doesn't really hold anymore, and it's unlikely there
+;; being new arch variants needing insn scheduling and not having mul
+;; insns.
+
+;; ELF and a.out have different syntax for local labels: the "wrong"
+;; one may not be omitted from the object.
+#undef L
+#ifdef __AOUT__
+# define L(x) x
+#else
+# define L(x) .x
+#endif
+
+       .global ___Mul
+       .type   ___Mul,@function
+___Mul:
+#if defined (__CRIS_arch_version) && __CRIS_arch_version >= 10
+       ret
+       mulu.d $r11,$r10
+#else
+       move.d $r10,$r12
+       move.d $r11,$r9
+       bound.d $r12,$r9
+       cmpu.w 65535,$r9
+       bls L(L3)
+       move.d $r12,$r13
+
+       movu.w $r11,$r9
+       lslq 16,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       mstep $r9,$r13
+       clear.w $r10
+       test.d $r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       movu.w $r12,$r12
+       move.d $r11,$r9
+       clear.w $r9
+       test.d $r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       mstep $r12,$r9
+       add.w $r9,$r10
+       lslq 16,$r10
+       ret
+       add.d $r13,$r10
+
+L(L3):
+       move.d $r9,$r10
+       xor $r11,$r10
+       xor $r12,$r10
+       cmpu.w 65535,$r10
+       bls L(L5)
+       movu.w $r9,$r13
+
+       movu.w $r13,$r13
+       move.d $r10,$r9
+       lslq 16,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       mstep $r13,$r9
+       clear.w $r10
+       test.d $r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       mstep $r13,$r10
+       lslq 16,$r10
+       ret
+       add.d $r9,$r10
+
+L(L5):
+       movu.w $r9,$r9
+       lslq 16,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       mstep $r9,$r10
+       ret
+       mstep $r9,$r10
+#endif
+L(Lfe1):
+       .size   ___Mul,L(Lfe1)-___Mul
diff --git a/gcc/config/cris/t-aout b/gcc/config/cris/t-aout
new file mode 100644 (file)
index 0000000..a21052e
--- /dev/null
@@ -0,0 +1,12 @@
+LIB2FUNCS_STATIC_EXTRA = \
+ tmpabi_symbol.c $(srcdir)/config/cris/mulsi3.asm
+
+MULTILIB_OPTIONS = melinux
+MULTILIB_DIRNAMES = elinux
+MULTILIB_EXTRA_OPTS = mbest-lib-options
+
+INSTALL_LIBGCC = install-multilib
+LIBGCC = stmp-multilib
+
+tmpabi_symbol.c: $(srcdir)/config/cris/cris_abi_symbol.c
+       cp $(srcdir)/config/cris/cris_abi_symbol.c $@
diff --git a/gcc/config/cris/t-cris b/gcc/config/cris/t-cris
new file mode 100644 (file)
index 0000000..5e7edf4
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# t-cris
+#
+# The Makefile fragment to include when compiling gcc et al for CRIS.
+#
+#
+# The makefile macros etc. are included in the order found in the
+# section "Target Fragment" in the gcc info-files (or the paper copy) of
+# "Using and Porting GCC"
+#
+# Don't run fixproto
+STMP_FIXPROTO =
+
+LIB2FUNCS_EXTRA = _udivsi3.c _divsi3.c _umodsi3.c _modsi3.c
+CRIS_LIB1CSRC = $(srcdir)/config/cris/arit.c
+
+FPBIT = tmplibgcc_fp_bit.c
+DPBIT = dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+       echo '#define FLOAT_BIT_ORDER_MISMATCH' > dp-bit.c
+       cat $(srcdir)/config/fp-bit.c           >> dp-bit.c
+
+# Use another name to avoid confusing SUN make, if support for
+# it is reinstated elsewhere.  Prefixed with "tmplibgcc" means
+# "make clean" will wipe it.  We define a few L_ thingies
+# because we can't select them individually through FPBIT_FUNCS;
+# see above.
+tmplibgcc_fp_bit.c: $(srcdir)/config/fp-bit.c
+       echo '#define FLOAT_BIT_ORDER_MISMATCH' >  $@
+       echo '#define FLOAT'                    >> $@
+       cat $(srcdir)/config/fp-bit.c           >> $@
+
+# The fixed-point arithmetic code is in one file, arit.c,
+# similar to libgcc2.c (or the old libgcc1.c).  We need to
+# "split it up" with one file per define.
+$(LIB2FUNCS_EXTRA): $(CRIS_LIB1CSRC)
+       name=`echo $@ | sed -e 's,.*/,,' | sed -e 's,.c$$,,'`; \
+       echo "#define L$$name" > tmp-$@ \
+       && echo '#include "$<"' >> tmp-$@ \
+       && mv -f tmp-$@ $@
+
+TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc
diff --git a/gcc/config/cris/t-elfmulti b/gcc/config/cris/t-elfmulti
new file mode 100644 (file)
index 0000000..f4e4fce
--- /dev/null
@@ -0,0 +1,16 @@
+LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/cris/mulsi3.asm
+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o
+MULTILIB_OPTIONS = march=v10
+MULTILIB_DIRNAMES = v10
+MULTILIB_MATCHES = \
+               march?v10=mcpu?etrax100lx \
+               march?v10=mcpu?ng \
+               march?v10=march?etrax100lx \
+               march?v10=march?ng \
+               march?v10=march?v11 \
+               march?v10=mcpu?v11 \
+               march?v10=mcpu?v10
+MULTILIB_EXTRA_OPTS = mbest-lib-options
+INSTALL_LIBGCC = install-multilib
+LIBGCC = stmp-multilib
+CRTSTUFF_T_CFLAGS = $(LIBGCC2_CFLAGS) -moverride-best-lib-options
diff --git a/gcc/config/cris/t-linux b/gcc/config/cris/t-linux
new file mode 100644 (file)
index 0000000..43c3acd
--- /dev/null
@@ -0,0 +1,6 @@
+TARGET_LIBGCC2_CFLAGS += -fPIC
+CRTSTUFF_T_CFLAGS_S = $(TARGET_LIBGCC2_CFLAGS)
+
+# Override t-slibgcc-elf-ver to export some libgcc symbols with
+# the symbol versions that glibc used.
+SHLIB_MAPFILES += $(srcdir)/config/libgcc-glibc.ver
index 90cc301..b4fbbae 100644 (file)
@@ -1787,6 +1787,45 @@ can also be obtained from:
 </p>
 <hr>
 @end html
+@heading @anchor{cris}CRIS
+
+CRIS is the CPU architecture in Axis Communications ETRAX system-on-a-chip
+series.  These are used in embedded applications.
+
+@ifnothtml
+@xref{CRIS Options,, CRIS Options, gcc, Using and Porting the GNU Compiler
+Collection (GCC)},
+@end ifnothtml
+@ifhtml
+See ``CRIS Options'' in the main manual
+@end ifhtml
+for a list of CRIS-specific options.
+
+There are a few different CRIS targets:
+@table @code
+@item cris-axis-aout
+Old target.  Includes a multilib for the @samp{elinux} a.out-based
+target.  No multilibs for newer architecture variants.
+@item cris-axis-elf
+Mainly for monolithic embedded systems.  Includes a multilib for the
+@samp{v10} core used in @samp{ETRAX 100 LX}.
+@item cris-axis-linux-gnu
+A GNU/Linux port for the CRIS architecture, currently targeting
+@samp{ETRAX 100 LX} by default.
+@end table
+
+For @code{cris-axis-aout} and @code{cris-axis-elf} you need binutils 2.11
+or newer.  For @code{cris-axis-linux-gnu} you need binutils 2.12 or newer.
+
+Pre-packaged tools can be obtained from
+@uref{ftp://ftp.axis.com/pub/axis/tools/cris/compiler-kit/}.  More
+information about this platform is available at
+@uref{http://developer.axis.com/}.
+
+@html
+</p>
+<hr>
+@end html
 @heading @anchor{dos}DOS
 
 Please have a look at our @uref{binaries.html,,binaries page}.
index 0588c1a..cab5005 100644 (file)
@@ -588,6 +588,15 @@ in the following sections.
 -msmall-exec  -mno-small-exec  -mmvcle -mno-mvcle @gol
 -m64 -m31 -mdebug -mno-debug}
 
+@emph{CRIS Options}
+@gccoptlist{
+-mcpu=@var{cpu} -march=@var{cpu} -mtune=@var{cpu} @gol
+-mmax-stack-frame=@var{n} -melinux-stacksize=@var{n} @gol
+-metrax4 -metrax100 -mpdebug -mcc-init -mno-side-effects @gol
+-mstack-align -mdata-align -mconst-align @gol
+-m32-bit -m16-bit -m8-bit -mno-prologue-epilogue -mno-gotplt @gol
+-melf -maout -melinux -mlinux -sim -sim2}
+
 @item Code Generation Options
 @xref{Code Gen Options,,Options for Code Generation Conventions}.
 @gccoptlist{
@@ -5096,6 +5105,7 @@ that macro, which enables you to change the defaults.
 * IA-64 Options::
 * D30V Options::
 * S/390 and zSeries Options::
+* CRIS Options::
 @end menu
 
 @node M680x0 Options
@@ -9464,6 +9474,143 @@ The default is to not print debug information.
 
 @end table
 
+@node CRIS Options
+@subsection CRIS Options
+@cindex CRIS Options
+
+These options are defined specifically for the CRIS ports.
+
+@table @gcctabopt
+@item -march=@var{architecture-type}
+@itemx -mcpu=@var{architecture-type}
+@opindex march
+@opindex mcpu
+Generate code for the specified architecture.  The choices for
+@var{architecture-type} are @samp{v3}, @samp{v8} and @samp{v10} for
+respectively ETRAX@w{ }4, ETRAX@w{ }100, and ETRAX@w{ }100@w{ }LX.
+Default is @samp{v0} except for cris-axis-linux-gnu, where the default is
+@samp{v10}.
+
+@item -mtune=@var{architecture-type}
+@opindex mtune
+Tune to @var{architecture-type} everything applicable about the generated
+code, except for the ABI and the set of available instructions.  The
+choices for @var{architecture-type} are the same as for
+@option{-march=@var{architecture-type}}.
+
+@item -mmax-stack-frame=@var{n}
+@opindex mmax-stack-frame
+Warn when the stack frame of a function exceeds @var{n} bytes.
+
+@item -melinux-stacksize=@var{n}
+@opindex melinux-stacksize
+Only available with the @samp{cris-axis-aout} target.  Arranges for
+indications in the program to the kernel loader that the stack of the
+program should be set to @var{n} bytes.
+
+@item -metrax4
+@itemx -metrax100
+@opindex metrax4
+@opindex metrax100
+The options @option{-metrax4} and @option{-metrax100} are synonyms for
+@option{-march=v3} and @option{-march=v8} respectively.
+
+@item -mpdebug
+@opindex mpdebug
+Enable CRIS-specific verbose debug-related information in the assembly
+code.  This option also has the effect to turn off the @samp{#NO_APP}
+formatted-code indicator to the assembler at the beginning of the
+assembly file.
+
+@item -mcc-init
+@opindex mcc-init
+Do not use condition-code results from previous instruction; always emit
+compare and test instructions before use of condition codes.
+
+@item -mno-side-effects
+@opindex mno-side-effects
+Do not emit instructions with side-effects in addressing modes other than
+post-increment.
+
+@item -mstack-align
+@itemx -mno-stack-align
+@itemx -mdata-align
+@itemx -mno-data-align
+@itemx -mconst-align
+@itemx -mno-const-align
+@opindex mstack-align
+@opindex mno-stack-align
+@opindex mdata-align
+@opindex mno-data-align
+@opindex mconst-align
+@opindex mno-const-align
+These options (no-options) arranges (eliminate arrangements) for the
+stack-frame, individual data and constants to be aligned for the maximum
+single data access size for the chosen CPU model.  The default is to
+arrange for 32-bit alignment.  ABI details such as structure layout are
+not affected by these options.
+
+@item -m32-bit
+@itemx -m16-bit
+@itemx -m8-bit
+@opindex m32-bit
+@opindex m16-bit
+@opindex m8-bit
+Similar to the stack- data- and const-align options above, these options
+arrange for stack-frame, writable data and constants to all be 32-bit,
+16-bit or 8-bit aligned.  The default is 32-bit alignment.
+
+@item -mno-prologue-epilogue
+@itemx -mprologue-epilogue
+@opindex mno-prologue-epilogue
+@opindex mprologue-epilogue
+With @option{-mno-prologue-epilogue}, the normal function prologue and
+epilogue that sets up the stack-frame are omitted and no return
+instructions or return sequences are generated in the code.  Use this
+option only together with visual inspection of the compiled code: no
+warnings or errors are generated when call-saved registers must be saved,
+or storage for local variable needs to be allocated.
+
+@item -mno-gotplt
+@itemx -mgotplt
+@opindex mno-gotplt
+@opindex mgotplt
+With @option{-fpic} and @option{-fPIC}, don't generate (do generate)
+instruction sequences that load addresses for functions from the PLT part
+of the GOT rather than (traditional on other architectures) calls to the
+PLT.  The default is @option{-mgotplt}.
+
+@item -maout
+@opindex maout
+Legacy no-op option only recognized with the cris-axis-aout target.
+
+@item -melf
+@opindex melf
+Legacy no-op option only recognized with the cris-axis-elf and
+cris-axis-linux-gnu targets.
+
+@item -melinux
+@opindex melinux
+Only recognized with the cris-axis-aout target, where it selects a
+GNU/linux-like multilib, include files and instruction set for
+@option{-march=v8}.
+
+@item -mlinux
+@opindex mlinux
+Legacy no-op option only recognized with the cris-axis-linux-gnu target.
+
+@item -sim
+@opindex sim
+This option, recognized for the cris-axis-aout and cris-axis-elf arranges
+to link with input-output functions from a simulator library.  Code,
+initialized data and zero-initialized data are allocated consecutively.
+
+@item -sim2
+@opindex sim2
+Like @option{-sim}, but pass linker options to locate initialized data at
+0x40000000 and zero-initialized data at 0x80000000.
+@end table
+
 
 @node Code Gen Options
 @section Options for Code Generation Conventions