+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
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
;;
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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));
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */
--- /dev/null
+;; 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:
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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:
+ */
--- /dev/null
+;; 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
--- /dev/null
+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 $@
--- /dev/null
+#
+# 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
--- /dev/null
+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
--- /dev/null
+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
</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}.
-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{
* IA-64 Options::
* D30V Options::
* S/390 and zSeries Options::
+* CRIS Options::
@end menu
@node M680x0 Options
@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