This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

CRIS port, part 3: config.gcc and config/cris; core port


This used to be a "multi-target" port, combining a.out, generic
ELF and GNU/Linux in one.  I gave up that approach and the port
became simpler.  I'll just have to cope with using a
shell-script around the driver...

cris--axis-elf:
 Standard generic ELF port, including multilib to core
 with extra instructions (mainly multiplication).

cris-axis-aout:
 Legacy port, including multilib to MMU-less uCLinux
 a.out-based port.  Note that dbxelf.h isn't actually
 ELF-specific.

cris-axis-linux-gnu:
 Standard GNU/Linux port.

Todo: still a few anachronisms to clean up; change peephole to
peephole2 and use the initial-value machinery for e.g. the PIC
register and the return address register.  Nothing worse than
most other ports, though.

Ok to commit?

Part 3, gcc/config.gcc, gcc/config/cris:

	* 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.

Index: config.gcc
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config.gcc,v
retrieving revision 1.91
diff -p -c -r1.91 config.gcc
*** config.gcc	2001/09/18 21:51:52	1.91
--- config.gcc	2001/09/29 13:49:14
*************** clipper-intergraph-clix*)
*** 657,662 ****
--- 657,683 ----
  	extra_parts="crtbegin.o crtend.o"
  	install_headers_dir=install-headers-cpio
  	;;
+ cris-*-aout)
+ 	tm_file="dbxelf.h cris/cris.h cris/aout.h"
+ 	gas=yes
+ 	tmake_file="cris/t-cris cris/t-aout"
+ 	;;
+ cris-*-elf | cris-*-none)
+ 	tm_file="elfos.h cris/cris.h"
+ 	tmake_file="cris/t-cris cris/t-elfmulti"
+ 	gas=yes
+ 	;;
+ cris-*-linux*)
+ 	tm_file="linux.h cris/cris.h cris/linux.h"
+ 	tmake_file="cris/t-cris t-slibgcc-elf-ver cris/t-linux"
+ 	extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ 	case x${enable_threads} in
+ 	x | xyes | xpthreads | xposix)
+ 		thread_file=posix
+ 		;;
+ 	esac
+ 	gas=yes
+ 	;;
  d30v-*)
  	float_format=i64
  	;;

diff -cprN nothing/cris-protos.h cris/cris-protos.h
*** nothing/cris-protos.h	Thu Jan  1 01:00:00 1970
--- cris/cris-protos.h	Sat Sep 29 16:27:46 2001
***************
*** 0 ****
--- 1,75 ----
+ /* Definitions for GCC.  Part of the machine description for CRIS.
+    Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+    Contributed by Axis Communications.
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING.  If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+ 
+ /* Prototypes for the CRIS port.  */
+ 
+ #if defined(FILE) || defined(stdin) || defined(stdout) || defined(getc) || defined(putc)
+ #define STDIO_INCLUDED
+ #endif
+ 
+ extern void cris_conditional_register_usage PARAMS ((void));
+ extern int cris_simple_epilogue PARAMS ((void));
+ #ifdef RTX_CODE
+ extern const char *cris_op_str PARAMS ((rtx));
+ extern int cris_eligible_for_epilogue_delay PARAMS ((rtx));
+ extern void cris_notice_update_cc PARAMS ((rtx, rtx));
+ extern int cris_address_cost PARAMS ((rtx));
+ extern void cris_print_operand PARAMS ((FILE *, rtx, int));
+ extern void cris_print_operand_address PARAMS ((FILE *, rtx));
+ extern int cris_side_effect_mode_ok PARAMS ((enum rtx_code, rtx *, int, int,
+                                              int, int, int));
+ extern rtx cris_return_addr_rtx PARAMS ((int, rtx));
+ extern rtx cris_split_movdx PARAMS ((rtx *));
+ extern int cris_legitimate_pic_operand PARAMS ((rtx));
+ extern int cris_gotless_symbol PARAMS ((rtx));
+ extern int cris_got_symbol PARAMS ((rtx));
+ extern int cris_symbol PARAMS ((rtx));
+ extern void cris_output_addr_const PARAMS ((FILE *, rtx));
+ extern int cris_cfun_uses_pic_table PARAMS ((void));
+ extern void cris_target_asm_named_section
+   PARAMS ((const char *, unsigned int));
+ 
+ # ifdef TREE_CODE
+ extern rtx cris_expand_builtin_va_arg PARAMS ((tree, tree));
+ extern void cris_encode_section_info PARAMS ((tree));
+ # endif
+ #endif /* RTX_CODE */
+ 
+ #ifdef STDIO_INCLUDED
+ # ifdef TREE_CODE
+ extern void cris_asm_output_mi_thunk PARAMS ((FILE *, tree, int, tree));
+ # endif
+ #endif
+ 
+ #ifdef GCC_C_PRAGMA_H
+ extern void cris_pragma_expand_mul PARAMS ((cpp_reader *));
+ #endif
+ 
+ /* Need one that returns an int; usable in expressions. */
+ extern int cris_fatal PARAMS ((char *));
+ 
+ extern void cris_override_options PARAMS ((void));
+ 
+ extern int cris_initial_elimination_offset PARAMS ((int, int));
+ 
+ extern void cris_init_expanders PARAMS ((void));
+ 
+ extern int cris_delay_slots_for_epilogue PARAMS ((void));
diff -cprN nothing/cris.c cris/cris.c
*** nothing/cris.c	Thu Jan  1 01:00:00 1970
--- cris/cris.c	Sat Sep 29 16:27:45 2001
***************
*** 0 ****
--- 1,3043 ----
+ /* Definitions for GCC.  Part of the machine description for CRIS.
+    Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+    Contributed by Axis Communications.  Written by Hans-Peter Nilsson.
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING.  If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+ 
+ #include "config.h"
+ #include "system.h"
+ #include "rtl.h"
+ #include "regs.h"
+ #include "hard-reg-set.h"
+ #include "real.h"
+ #include "insn-config.h"
+ #include "conditions.h"
+ #include "output.h"
+ #include "insn-attr.h"
+ #include "flags.h"
+ #include "tree.h"
+ #include "expr.h"
+ #include "except.h"
+ #include "function.h"
+ #include "toplev.h"
+ #include "recog.h"
+ #include "tm_p.h"
+ #include "debug.h"
+ #include "target.h"
+ #include "target-def.h"
+ 
+ /* Usable when we have an amount to add or subtract, and want the
+    optimal size of the insn.  */
+ #define ADDITIVE_SIZE_MODIFIER(size) \
+  ((size) <= 63 ? "q" : (size) <= 255 ? "u.b" : (size) <= 65535 ? "u.w" : ".d")
+ 
+ #define ASSERT_PLT_UNSPEC(x)					\
+   do								\
+     {								\
+       if (XEXP (x, 1) != NULL_RTX				\
+ 	  || (GET_CODE (XVECEXP (x, 0, 0)) != SYMBOL_REF	\
+ 	      && GET_CODE (XVECEXP (x, 0, 0)) != LABEL_REF))	\
+ 	abort ();						\
+     } while (0)
+ 
+ /* Per-function machine data.  */
+ struct machine_function
+  {
+    int needs_return_address_on_stack;
+  };
+ 
+ /* Fix for reg_overlap_mentioned_p.  */
+ static int cris_reg_overlap_mentioned_p PARAMS ((rtx, rtx));
+ 
+ /* This little fix suppresses the 'u' or 's' when '%e' in assembly
+    pattern.  */
+ static char cris_output_insn_is_bound = 0;
+ 
+ /* This one suppresses printing out the "rPIC+" in
+    "rPIC+sym:GOTOFF+offset" when doing PIC.  For a PLT symbol, it
+    suppresses outputting it as [rPIC+sym:GOTPLT] and outputs similarly
+    just the "sym:GOTOFF" part.  */
+ static int cris_pic_sympart_only = 0;
+ 
+ static void
+ cris_print_base PARAMS ((rtx, FILE *));
+ 
+ static void
+ cris_print_index PARAMS ((rtx, FILE *));
+ 
+ static void
+ cris_init_machine_status PARAMS ((struct function *));
+ 
+ static int
+ cris_initial_frame_pointer_offset PARAMS ((void));
+ 
+ static int
+ saved_regs_mentioned PARAMS ((rtx));
+ 
+ static void cris_target_asm_function_prologue
+   PARAMS ((FILE *, HOST_WIDE_INT));
+ static void cris_target_asm_function_epilogue
+   PARAMS ((FILE *, HOST_WIDE_INT));
+ 
+ /* The function cris_target_asm_function_epilogue puts the last insn to
+    output here.  Used in delay_slots_for_epilogue and function_epilogue.  */
+ static char save_last[80];
+ 
+ /* This is the argument from the "-max-stack-stackframe=" option.  */
+ const char *cris_max_stackframe_str;
+ 
+ /* This is the argument from the "-march=" option.  */
+ const char *cris_cpu_str;
+ 
+ /* This is the argument from the "-mtune=" option.  */
+ const char *cris_tune_str;
+ 
+ /* This is the argument from the "-melinux-stacksize=" option.  */
+ const char *cris_elinux_stacksize_str;
+ 
+ /* This is the parsed result of the "-max-stack-stackframe=" option.  If
+    it (still) is zero, then there was no such option given.  */
+ int cris_max_stackframe = 0;
+ 
+ /* This is the parsed result of the "-march=" option, if given.  */
+ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION;
+ 
+ #undef TARGET_ASM_FUNCTION_PROLOGUE
+ #define TARGET_ASM_FUNCTION_PROLOGUE cris_target_asm_function_prologue
+ 
+ #undef TARGET_ASM_FUNCTION_EPILOGUE
+ #define TARGET_ASM_FUNCTION_EPILOGUE cris_target_asm_function_epilogue
+ 
+ struct gcc_target targetm = TARGET_INITIALIZER;
+ 
+ /* Predicate functions.  */
+ 
+ /* This checks a part of an address, the one that is not a plain register
+    for an addressing mode using BDAP.
+    Allowed operands is either:
+    a) a register
+    b) a CONST operand (but not a symbol when generating PIC)
+    c) a [r] or [r+] in SImode, or sign-extend from HI or QI.  */
+ 
+ int
+ cris_bdap_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+ {
+   register enum rtx_code code = GET_CODE (op);
+ 
+   if (mode != SImode && (mode != VOIDmode || GET_MODE (op) != VOIDmode))
+     return 0;
+ 
+   /* Just return whether this is a simple register or constant.  */
+   if (register_operand (op, mode)
+       || (CONSTANT_P (op) && !(flag_pic && cris_symbol (op))))
+     return 1;
+ 
+   /* Is it a [r] or possibly a [r+]?  */
+   if (code == MEM)
+     {
+       rtx tem = XEXP (op, 0);
+ 
+       if (mode == SImode
+ 	  && (register_operand (tem, SImode)
+ 	      || (GET_CODE (tem) == POST_INC
+ 		  && register_operand (XEXP (tem, 0), SImode))))
+ 	return 1;
+       else
+ 	return 0;
+     }
+ 
+   /* Perhaps a sign-extended mem: [r].(b|w) or [r+].(b|w)?  */
+   if (code == SIGN_EXTEND)
+     {
+       rtx tem = XEXP (op, 0);
+ 
+       if (GET_CODE (tem) != MEM)
+ 	return 0;
+ 
+       tem = XEXP (tem, 0);
+       if (mode == SImode
+ 	  && (register_operand (tem, SImode)
+ 	      || (GET_CODE (tem) == POST_INC
+ 		  && register_operand (XEXP (tem, 0), SImode))))
+ 	return 1;
+       else
+ 	return 0;
+     }
+ 
+   return 0;
+ }
+ 
+ /* This is similar to cris_bdap_operand:
+    It checks a part of an address, the one that is not a plain register
+    for an addressing mode using BDAP *or* BIAP.
+    Allowed operands is either:
+    a) a register
+    b) a CONST operand (but not a symbol when generating PIC)
+    c) a mult of (1, 2 or 4) and a register
+    d) a [r] or [r+] in SImode, or sign-extend from HI or QI.  */
+ 
+ int
+ cris_bdap_biap_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+ {
+   register enum rtx_code code = GET_CODE (op);
+   rtx reg;
+   rtx val;
+ 
+   /* Check for bdap operand.  */
+   if (cris_bdap_operand (op, mode))
+     return 1;
+ 
+   if (mode != SImode && (mode != VOIDmode || GET_MODE (op) != VOIDmode))
+     return 0;
+ 
+   /* Check that we're looking at a BIAP operand.  */
+   if (code != MULT)
+     return 0;
+ 
+   /* Canonicalize register and multiplicand.  */
+   if (GET_CODE (XEXP (op, 0)) == CONST_INT)
+     {
+       val = XEXP (op, 0);
+       reg = XEXP (op, 1);
+     }
+   else
+     {
+       val = XEXP (op, 1);
+       reg = XEXP (op, 0);
+     }
+ 
+   /* Check that the operands are correct after canonicalization.  */
+   if (! register_operand (reg, SImode) || GET_CODE (val) != CONST_INT)
+     return 0;
+ 
+   /* Check that the multiplicand has a valid value.  */
+   if ((code == MULT
+        && (INTVAL (val) == 1 || INTVAL (val) == 2 || INTVAL (val) == 4)))
+     return 1;
+ 
+   return 0;
+ }
+ 
+ /* Check if MODE is same as mode for X, and X is PLUS, MINUS, IOR or
+    AND or UMIN.  */
+ 
+ int
+ cris_orthogonal_operator (x, mode)
+      rtx x;
+      enum machine_mode mode;
+ {
+   enum rtx_code code = GET_CODE (x);
+ 
+   if (mode == VOIDmode)
+     mode = GET_MODE (x);
+ 
+   return (GET_MODE (x) == mode
+ 	  && (code == PLUS || code == MINUS
+ 	      || code == IOR || code == AND || code == UMIN));
+ }
+ 
+ /* Check if MODE is same as mode for X, and X is PLUS, IOR or AND or
+    UMIN.  */
+ 
+ int
+ cris_commutative_orth_op (x, mode)
+      rtx x;
+      enum machine_mode mode;
+ {
+   enum rtx_code code = GET_CODE (x);
+ 
+   if (mode == VOIDmode)
+     mode = GET_MODE (x);
+ 
+   return (GET_MODE (x) == mode &&
+ 	  (code == PLUS
+ 	   || code == IOR || code == AND || code == UMIN));
+ }
+ 
+ /* Check if MODE is same as mode for X, and X is PLUS or MINUS or UMIN.  */
+ 
+ int
+ cris_operand_extend_operator (x, mode)
+      rtx x;
+      enum machine_mode mode;
+ {
+   enum rtx_code code = GET_CODE (x);
+ 
+   if (mode == VOIDmode)
+     mode = GET_MODE (x);
+ 
+   return (GET_MODE (x) == mode
+ 	  && (code == PLUS || code == MINUS || code == UMIN));
+ }
+ 
+ /* Check to see if MODE is same as mode for X, and X is SIGN_EXTEND or
+    ZERO_EXTEND.  */
+ 
+ int
+ cris_extend_operator (x, mode)
+      rtx x;
+      enum machine_mode mode;
+ {
+   enum rtx_code code = GET_CODE (x);
+ 
+   if (mode == VOIDmode)
+     mode = GET_MODE (x);
+ 
+   return
+     (GET_MODE (x) == mode && (code == SIGN_EXTEND || code == ZERO_EXTEND));
+ }
+ 
+ /* Check to see if MODE is same as mode for X, and X is PLUS or BOUND.  */
+ 
+ int
+ cris_plus_or_bound_operator (x, mode)
+      rtx x;
+      enum machine_mode mode;
+ {
+   enum rtx_code code = GET_CODE (x);
+ 
+   if (mode == VOIDmode)
+     mode = GET_MODE (x);
+ 
+   return
+     (GET_MODE (x) == mode && (code == UMIN || code == PLUS));
+ }
+ 
+ /* Since with -fPIC, not all symbols are valid PIC symbols or indeed
+    general_operands, we have to have a predicate that matches it for the
+    "movsi" expander.  */
+ 
+ int
+ cris_general_operand_or_symbol (op, mode)
+      rtx op;
+      enum machine_mode mode;
+ {
+   return general_operand (op, mode)
+     || (CONSTANT_P (op) && cris_symbol (op));
+ }
+ 
+ /* Since a PIC symbol without a GOT entry is not a general_operand, we
+    have to have a predicate that matches it.  We use this in the expanded
+    "movsi" anonymous pattern for PIC symbols.  */
+ 
+ int
+ cris_general_operand_or_gotless_symbol (op, mode)
+      rtx op;
+      enum machine_mode mode;
+ {
+   return general_operand (op, mode)
+     || (CONSTANT_P (op) && cris_gotless_symbol (op));
+ }
+ 
+ /* Since a PLT symbol is not a general_operand, we have to have a
+    predicate that matches it when we need it.  We use this in the expanded
+    "call" and "call_value" anonymous patterns.  */
+ 
+ int
+ cris_general_operand_or_plt_symbol (op, mode)
+      rtx op;
+      enum machine_mode mode;
+ {
+   return general_operand (op, mode)
+     || (GET_CODE (op) == CONST
+ 	&& GET_CODE (XEXP (op, 0)) == UNSPEC
+ 	&& !TARGET_AVOID_GOTPLT);
+ }
+ 
+ /* This matches a (MEM (general_operand)) or
+    (MEM (cris_general_operand_or_symbol)).  The second one isn't a valid
+    memory_operand, so we need this predicate to recognize call
+    destinations before we change them to a PLT operand (by wrapping in
+    UNSPEC 0).  */
+ 
+ int
+ cris_mem_call_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+ {
+   rtx xmem;
+ 
+   if (GET_CODE (op) != MEM)
+     return 0;
+ 
+   if (memory_operand (op, mode))
+     return 1;
+ 
+   xmem = XEXP (op, 0);
+ 
+   return cris_general_operand_or_symbol (xmem, GET_MODE (op));
+ }
+ 
+ /* The CONDITIONAL_REGISTER_USAGE worker.   */
+ 
+ void
+ cris_conditional_register_usage ()
+ {
+   /* FIXME: This isn't nice.  We should be able to use that register for
+      something else if the PIC table isn't needed.  */
+   if (flag_pic)
+     fixed_regs[PIC_OFFSET_TABLE_REGNUM]
+       = call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+ }
+ 
+ /* Return current_function_uses_pic_offset_table.  For use in cris.md,
+    since some generated files do not include function.h.  */
+ 
+ int
+ cris_cfun_uses_pic_table ()
+ {
+   return current_function_uses_pic_offset_table;
+ }
+ 
+ /* Given an rtx, return the text string corresponding to the CODE of X.
+    Intended for use in the assembly language output section of a
+    define_insn.  */
+ 
+ const char *
+ cris_op_str (x)
+      rtx x;
+ {
+   cris_output_insn_is_bound = 0;
+   switch (GET_CODE (x))
+     {
+     case PLUS:
+       return "add";
+       break;
+ 
+     case MINUS:
+       return "sub";
+       break;
+ 
+     case MULT:
+       return "mul";
+       break;
+ 
+     case DIV:
+       return "div";
+       break;
+ 
+     case AND:
+       return "and";
+       break;
+ 
+     case IOR:
+       return "or";
+       break;
+ 
+     case XOR:
+       return "xor";
+       break;
+ 
+     case NOT:
+       return "not";
+       break;
+ 
+     case ASHIFT:
+       return "lsl";
+       break;
+ 
+     case LSHIFTRT:
+       return "lsr";
+       break;
+ 
+     case ASHIFTRT:
+       return "asr";
+       break;
+ 
+     case UMIN:
+       /* Used to control the sign/zero-extend character for the 'e' modifier.
+ 	 BOUND has none.  */
+       cris_output_insn_is_bound = 1;
+       return "bound";
+       break;
+ 
+     default:
+       return "Unknown operator";
+       break;
+   }
+ }
+ 
+ /* Print an index part of an address to file.  */
+ 
+ static void
+ cris_print_index (index, file)
+      rtx index;
+      FILE * file;
+ {
+   rtx inner = XEXP (index, 0);
+ 
+   /* Make the index "additive" unless we'll output a negative number, in
+      which case the sign character is free (as in free beer).  */
+   if (GET_CODE (index) != CONST_INT || INTVAL (index) >= 0)
+     putc ('+', file);
+ 
+   if (REG_P (index))
+     fprintf (file, "$%s.b", reg_names[REGNO (index)]);
+   else if (CONSTANT_P (index))
+     cris_output_addr_const (file, index);
+   else if (GET_CODE (index) == MULT)
+     {
+       fprintf (file, "$%s.",
+ 	       reg_names[REGNO (XEXP (index, 0))]);
+ 
+       putc (INTVAL (XEXP (index, 1)) == 2 ? 'w' : 'd', file);
+     }
+   else if (GET_CODE (index) == SIGN_EXTEND &&
+ 	   GET_CODE (inner) == MEM)
+     {
+       rtx inner_inner = XEXP (inner, 0);
+ 
+       if (GET_CODE (inner_inner) == POST_INC)
+ 	{
+ 	  fprintf (file, "[$%s+].",
+ 		   reg_names[REGNO (XEXP (inner_inner, 0))]);
+ 	  putc (GET_MODE (inner) == HImode ? 'w' : 'b', file);
+ 	}
+       else
+ 	{
+ 	  fprintf (file, "[$%s].", reg_names[REGNO (inner_inner)]);
+ 
+ 	  putc (GET_MODE (inner) == HImode ? 'w' : 'b', file);
+ 	}
+     }
+   else if (GET_CODE (index) == MEM)
+     {
+       if (GET_CODE (inner) == POST_INC)
+ 	fprintf (file, "[$%s+].d", reg_names[REGNO (XEXP (inner, 0))]);
+       else
+ 	fprintf (file, "[$%s].d", reg_names[REGNO (inner)]);
+     }
+   else
+     fatal_insn ("Unexpected index-type in cris_print_index", index);
+ }
+ 
+ /* Print a base rtx of an address to file.  */
+ 
+ static void
+ cris_print_base (base, file)
+      rtx base;
+      FILE *file;
+ {
+   if (REG_P (base))
+     fprintf (file, "$%s", reg_names[REGNO (base)]);
+   else if (GET_CODE (base) == POST_INC)
+     fprintf (file, "$%s+", reg_names[REGNO (XEXP (base, 0))]);
+   else
+     fatal_insn ("Unexpected base-type in cris_print_base", base);
+ }
+ 
+ /* Usable as a guard in expressions.  */
+ 
+ int
+ cris_fatal (arg)
+      char *arg;
+ {
+   internal_error (arg);
+ 
+   /* We'll never get here; this is just to appease compilers.  */
+   return 0;
+ }
+ 
+ /* Textual function prologue.  */
+ 
+ static void
+ cris_target_asm_function_prologue (file, size)
+      FILE *file;
+      HOST_WIDE_INT size;
+ {
+   int regno;
+ 
+   /* Shorten the used name for readability.  */
+   int cfoa_size = current_function_outgoing_args_size;
+   int last_movem_reg = -1;
+   int doing_dwarf = dwarf2out_do_frame ();
+   int framesize;
+   int faked_args_size = 0;
+   int cfa_write_offset = 0;
+   char *cfa_label = NULL;
+   int return_address_on_stack
+     = regs_ever_live[CRIS_SRP_REGNUM]
+     || cfun->machine->needs_return_address_on_stack != 0;
+ 
+   /* Don't do anything if no prologues or epilogues are wanted.  */
+   if (!TARGET_PROLOGUE_EPILOGUE)
+     return;
+ 
+   if (size < 0)
+     abort ();
+ 
+   /* Align the size to what's best for the CPU model.  */
+   if (TARGET_STACK_ALIGN)
+     size = TARGET_ALIGN_BY_32 ? (size + 3) & ~3 : (size + 1) & ~1;
+ 
+   if (current_function_pretend_args_size)
+     {
+       int pretend = current_function_pretend_args_size;
+       for (regno = CRIS_FIRST_ARG_REG + CRIS_MAX_ARGS_IN_REGS - 1;
+ 	   pretend > 0;
+ 	   regno--, pretend -= 4)
+ 	{
+ 	  fprintf (file, "\tpush $%s\n", reg_names[regno]);
+ 	  faked_args_size += 4;
+ 	}
+     }
+ 
+   framesize = faked_args_size;
+ 
+   if (doing_dwarf)
+     {
+       /* FIXME: Slightly redundant calculation, as we do the same in
+ 	 pieces below.  This offset must be the total adjustment of the
+ 	 stack-pointer.  We can then def_cfa call at the end of this
+ 	 function with the current implementation of execute_cfa_insn, but
+ 	 that wouldn't really be clean.  */
+ 
+       int cfa_offset
+ 	= faked_args_size
+ 	+ (return_address_on_stack ? 4 : 0)
+ 	+ (frame_pointer_needed ? 4 : 0);
+ 
+       int cfa_reg;
+ 
+       if (frame_pointer_needed)
+ 	cfa_reg = FRAME_POINTER_REGNUM;
+       else
+ 	{
+ 	  cfa_reg = STACK_POINTER_REGNUM;
+ 	  cfa_offset += cris_initial_frame_pointer_offset ();
+ 	}
+ 
+       cfa_label = dwarf2out_cfi_label ();
+       dwarf2out_def_cfa (cfa_label, cfa_reg, cfa_offset);
+ 
+       cfa_write_offset = - faked_args_size - 4;
+     }
+ 
+   /* Save SRP if not a leaf function.  */
+   if (return_address_on_stack)
+     {
+       fprintf (file, "\tPush $srp\n");
+       framesize += 4;
+ 
+       if (doing_dwarf)
+ 	{
+ 	  dwarf2out_return_save (cfa_label, cfa_write_offset);
+ 	  cfa_write_offset -= 4;
+ 	}
+     }
+ 
+   /* Set up frame pointer if needed.  */
+   if (frame_pointer_needed)
+     {
+       fprintf (file, "\tpush $%s\n\tmove.d $sp,$%s\n",
+ 	       reg_names[FRAME_POINTER_REGNUM],
+ 	       reg_names[FRAME_POINTER_REGNUM]);
+       framesize += 4;
+ 
+       if (doing_dwarf)
+ 	{
+ 	  dwarf2out_reg_save (cfa_label, FRAME_POINTER_REGNUM,
+ 			      cfa_write_offset);
+ 	  cfa_write_offset -= 4;
+ 	}
+     }
+ 
+   /* Local vars are located above saved regs.  */
+   cfa_write_offset -= size;
+ 
+   /* Get a contiguous sequence of registers, starting with r0, that need
+      to be saved. */
+   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+     {
+       if ((((regs_ever_live[regno]
+ 	     && !call_used_regs[regno])
+ 	    || (regno == PIC_OFFSET_TABLE_REGNUM
+ 		&& (current_function_uses_pic_offset_table
+ 		    /* It is saved anyway, if there would be a gap.  */
+ 		    || (flag_pic
+ 			&& regs_ever_live[regno + 1]
+ 			&& !call_used_regs[regno + 1]))))
+ 	   && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed)
+ 	   && regno != CRIS_SRP_REGNUM)
+ 	  || (current_function_calls_eh_return
+ 	      && (regno == EH_RETURN_DATA_REGNO (0)
+ 		  || regno == EH_RETURN_DATA_REGNO (1)
+ 		  || regno == EH_RETURN_DATA_REGNO (2)
+ 		  || regno == EH_RETURN_DATA_REGNO (3))))
+ 	{
+ 	  /* Check if movem may be used for registers so far.  */
+ 	  if (regno == last_movem_reg + 1)
+ 	    /* Yes, update next expected register.  */
+ 	    last_movem_reg++;
+ 	  else
+ 	    {
+ 	      /* We cannot use movem for all registers.  We have to flush
+ 		 any movem:ed registers we got so far.  */
+ 	      if (last_movem_reg != -1)
+ 		{
+ 		  /* It is a win to use a side-effect assignment for
+ 		     64 <= size <= 128.  But side-effect on movem was
+ 		     not usable for CRIS v0..3.  Also only do it if
+ 		     side-effects insns are allowed.  */
+ 		  if ((last_movem_reg + 1) * 4 + size >= 64
+ 		      && (last_movem_reg + 1) * 4 + size <= 128
+ 		      && cris_cpu_version >= CRIS_CPU_SVINTO
+ 		      && TARGET_SIDE_EFFECT_PREFIXES)
+ 		    fprintf (file, "\tmovem $%s,[$sp=$sp-%d]\n",
+ 			     reg_names[last_movem_reg],
+ 			     (last_movem_reg + 1) * 4 + size);
+ 		  else
+ 		    {
+ 		      /* Avoid printing multiple subsequent sub:s for sp.  */
+ 		      fprintf (file, "\tsub%s %d,$sp\n",
+ 			       ADDITIVE_SIZE_MODIFIER ((last_movem_reg + 1)
+ 						       * 4 + size),
+ 			       (last_movem_reg + 1) * 4 + size);
+ 
+ 		      fprintf (file, "\tmovem $%s,[$sp]\n",
+ 			       reg_names[last_movem_reg]);
+ 		    }
+ 
+ 		  framesize += (last_movem_reg + 1) * 4 + size;
+ 
+ 		  if (TARGET_PDEBUG)
+ 		    fprintf (file, "; frame %d, #regs %d, bytes %d args %d\n",
+ 			     size,
+ 			     last_movem_reg + 1,
+ 			     (last_movem_reg + 1) * 4,
+ 			     current_function_args_size);
+ 
+ 		  last_movem_reg = -1;
+ 		  size = 0;
+ 		}
+ 	      else if (size > 0)
+ 		{
+ 		  /* Local vars on stack, but there are no movem:s.
+ 		     Just allocate space.  */
+ 		  fprintf (file, "\tSub%s %d,$sp\n",
+ 			   ADDITIVE_SIZE_MODIFIER (size),
+ 			   size);
+ 		  framesize += size;
+ 		  size = 0;
+ 		}
+ 
+ 	      fprintf (file, "\tPush $%s\n", reg_names[regno]);
+ 	      framesize += 4;
+ 	    }
+ 
+ 	  if (doing_dwarf)
+ 	    {
+ 	      /* Registers are stored lowest numbered at highest address,
+ 		 which matches the loop order; we just need to update the
+ 		 write-offset.  */
+ 	      dwarf2out_reg_save (cfa_label, regno, cfa_write_offset);
+ 	      cfa_write_offset -= 4;
+ 	    }
+ 	}
+     }
+ 
+   /* Check after, if we can movem all registers.  This is the normal
+      case.  */
+   if (last_movem_reg != -1)
+     {
+       /* Side-effect assignment on movem was not supported for CRIS v0..3,
+ 	 and don't do it if we're asked not to.
+ 
+ 	 The movem is already accounted for, for unwind.  */
+ 
+       if ((last_movem_reg + 1) * 4 + size >= 64
+ 	  && (last_movem_reg + 1) * 4 + size <= 128
+ 	  && cris_cpu_version >= CRIS_CPU_SVINTO
+ 	  && TARGET_SIDE_EFFECT_PREFIXES)
+ 	fprintf (file, "\tmovem $%s,[$sp=$sp-%d]\n",
+ 		 reg_names[last_movem_reg],
+ 		 (last_movem_reg+1) * 4 + size);
+       else
+ 	{
+ 	  /* Avoid printing multiple subsequent sub:s for sp.  FIXME:
+ 	     Clean up the conditional expression. */
+ 	  fprintf (file, "\tsub%s %d,$sp\n",
+ 		   ADDITIVE_SIZE_MODIFIER ((last_movem_reg + 1) * 4 + size),
+ 		   (last_movem_reg + 1) * 4 + size);
+ 	  /* To be compatible with v0..v3 means we do not use an assignment
+ 	     addressing mode with movem.  We normally don't need that
+ 	     anyway.  It would only be slightly more efficient for 64..128
+ 	     bytes frame size.  */
+ 	  fprintf (file, "\tmovem $%s,[$sp]\n", reg_names[last_movem_reg]);
+ 	}
+ 
+       framesize += (last_movem_reg + 1) * 4 + size;
+ 
+       if (TARGET_PDEBUG)
+ 	fprintf (file, "; frame %d, #regs %d, bytes %d args %d\n",
+ 		 size,
+ 		 last_movem_reg + 1,
+ 		 (last_movem_reg + 1) * 4,
+ 		 current_function_args_size);
+ 
+       /* We have to put outgoing argument space after regs.  */
+       if (cfoa_size)
+ 	{
+ 	  /* This does not need to be accounted for, for unwind.  */
+ 
+ 	  fprintf (file, "\tSub%s %d,$sp\n",
+ 		   ADDITIVE_SIZE_MODIFIER (cfoa_size),
+ 		   cfoa_size);
+ 	  framesize += cfoa_size;
+ 	}
+     }
+   else if ((size + cfoa_size) > 0)
+     {
+       /* This does not need to be accounted for, for unwind.  */
+ 
+       /* Local vars on stack, and we could not use movem.  Add a sub here.  */
+       fprintf (file, "\tSub%s %d,$sp\n",
+ 	       ADDITIVE_SIZE_MODIFIER (size + cfoa_size),
+ 	       cfoa_size + size);
+       framesize += size + cfoa_size;
+     }
+ 
+   /* Set up the PIC register.  */
+   if (current_function_uses_pic_offset_table)
+     asm_fprintf (file, "\tmove.d $pc,$%s\n\tsub.d .:GOTOFF,$%s\n",
+ 		 reg_names[PIC_OFFSET_TABLE_REGNUM],
+ 		 reg_names[PIC_OFFSET_TABLE_REGNUM]);
+ 
+   if (TARGET_PDEBUG)
+     fprintf (file,
+ 	     "; parm #%d @ %d; frame %d, FP-SP is %d; leaf: %s%s; fp %s, outg: %d arg %d\n",
+ 	     CRIS_MAX_ARGS_IN_REGS + 1, FIRST_PARM_OFFSET (0),
+ 	     get_frame_size (),
+ 	     cris_initial_frame_pointer_offset (),
+ 	     leaf_function_p () ? "yes" : "no",
+ 	     return_address_on_stack ? "no" :"yes",
+ 	     frame_pointer_needed ? "yes" : "no",
+ 	     cfoa_size, current_function_args_size);
+ 
+   if (cris_max_stackframe && framesize > cris_max_stackframe)
+     warning ("Stackframe too big: %d bytes", framesize);
+ }
+ 
+ /* Return nonzero if there are regs mentioned in the insn that are not all
+    in the call_used regs.  This is part of the decision whether an insn
+    can be put in the epilogue.  */
+ 
+ static int
+ saved_regs_mentioned (x)
+      rtx x;
+ {
+   int i;
+   const char *fmt;
+   RTX_CODE code;
+ 
+   /* Mainly stolen from refers_to_regno_p in rtlanal.c. */
+ 
+   code = GET_CODE (x);
+ 
+   switch (code)
+     {
+     case REG:
+       i = REGNO (x);
+       return !call_used_regs[i];
+ 
+     case SUBREG:
+       /* If this is a SUBREG of a hard reg, we can see exactly which
+ 	 registers are being modified.  Otherwise, handle normally.  */
+       i = REGNO (SUBREG_REG (x));
+       return !call_used_regs[i];
+ 
+     default:
+       ;
+     }
+ 
+   fmt = GET_RTX_FORMAT (code);
+   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+     {
+       if (fmt[i] == 'e')
+ 	{
+ 	  if (saved_regs_mentioned (XEXP (x, i)))
+ 	    return 1;
+ 	}
+       else if (fmt[i] == 'E')
+ 	{
+ 	  int j;
+ 	  for (j = XVECLEN (x, i) - 1; j >=0; j--)
+ 	    if (saved_regs_mentioned (XEXP (x, i)))
+ 	      return 1;
+ 	}
+     }
+ 
+   return 0;
+ }
+ 
+ /* Figure out if the insn may be put in the epilogue.  */
+ 
+ int
+ cris_eligible_for_epilogue_delay (insn)
+      rtx insn;
+ {
+   /* First of all, it must be as slottable as for a delayed branch insn.  */
+   if (get_attr_slottable (insn) != SLOTTABLE_YES)
+     return 0;
+ 
+   /* It must not refer to the stack pointer (may be valid for some cases
+      that I can't think of).  */
+   if (reg_mentioned_p (stack_pointer_rtx, PATTERN (insn)))
+     return 0;
+ 
+   /* The frame pointer will be restored in the epilogue, before the
+      "ret", so it can't be referred to.  */
+   if (frame_pointer_needed
+       && reg_mentioned_p (frame_pointer_rtx, PATTERN (insn)))
+     return 0;
+ 
+   /* All saved regs are restored before the delayed insn.
+      This means that we cannot have any instructions that mention the
+      registers that are restored by the epilogue.  */
+   if (saved_regs_mentioned (PATTERN (insn)))
+     return 0;
+ 
+   /* It seems to be ok.  */
+   return 1;
+ }
+ 
+ /* Return the number of delay-slots in the epilogue: return 1 if it
+    contains "ret", else 0.  */
+ 
+ int
+ cris_delay_slots_for_epilogue ()
+ {
+   /* Check if we use a return insn, which we only do for leaf functions.
+      Else there is no slot to fill.  */
+   if (regs_ever_live[CRIS_SRP_REGNUM]
+       || cfun->machine->needs_return_address_on_stack != 0)
+     return 0;
+ 
+   /* By calling function_epilogue with the same parameters as from gcc
+      we can get info about if the epilogue can fill the delay-slot by itself.
+      If it is filled from the epilogue, then the corresponding string
+      is in save_last.
+       This depends on that the "size" argument to function_epilogue
+      always is get_frame_size.
+      FIXME:  Kludgy.  At least make it a separate function that is not
+      misnamed or abuses the stream parameter.  */
+   cris_target_asm_function_epilogue (NULL, get_frame_size ());
+ 
+   if (*save_last)
+     return 1;
+   return 0;
+ }
+ 
+ /* Textual function epilogue.  When file is NULL, it serves doubly as
+    a test for whether the epilogue can fill any "ret" delay-slots by
+    itself by storing the delay insn in save_last.  */
+ 
+ static void
+ cris_target_asm_function_epilogue (file, size)
+      FILE *file;
+      HOST_WIDE_INT size;
+ {
+   int regno;
+   int last_movem_reg = -1;
+   rtx insn = get_last_insn ();
+   int argspace_offset = current_function_outgoing_args_size;
+   int pretend =	 current_function_pretend_args_size;
+   int return_address_on_stack
+     = regs_ever_live[CRIS_SRP_REGNUM]
+     || cfun->machine->needs_return_address_on_stack != 0;
+ 
+   save_last[0] = 0;
+ 
+   if (file && !TARGET_PROLOGUE_EPILOGUE)
+     return;
+ 
+   if (TARGET_PDEBUG && file)
+     fprintf (file, ";;\n");
+ 
+   /* Align byte count of stack frame.  */
+   if (TARGET_STACK_ALIGN)
+     size = TARGET_ALIGN_BY_32 ? (size + 3) & ~3 : (size + 1) & ~1;
+ 
+   /* If the last insn was a BARRIER, we don't have to write any code,
+      then all returns were covered by "return" insns.  */
+   if (GET_CODE (insn) == NOTE)
+     insn = prev_nonnote_insn (insn);
+   if (insn
+       && (GET_CODE (insn) == BARRIER
+ 	  /* We must make sure that the insn really is a "return" and
+ 	     not a conditional branch.  Try to match the return exactly,
+ 	     and if it doesn't match, assume it is a conditional branch
+ 	     (and output an epilogue).  */
+ 	  || (GET_CODE (insn) == JUMP_INSN
+ 	      && GET_CODE (PATTERN (insn)) == RETURN)))
+     {
+       if (TARGET_PDEBUG && file)
+ 	fprintf (file, ";;;;;\n");
+       return;
+     }
+ 
+   /* Check how many saved regs we can movem.  They start at r0 and must
+      be contiguous.  */
+   for (regno = 0;
+        regno < FIRST_PSEUDO_REGISTER;
+        regno++)
+     if ((((regs_ever_live[regno]
+ 	   && !call_used_regs[regno])
+ 	  || (regno == PIC_OFFSET_TABLE_REGNUM
+ 	      && (current_function_uses_pic_offset_table
+ 		  /* It is saved anyway, if there would be a gap.  */
+ 		  || (flag_pic
+ 		      && regs_ever_live[regno + 1]
+ 		      && !call_used_regs[regno + 1]))))
+ 	 && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed)
+ 	 && regno != CRIS_SRP_REGNUM)
+ 	|| (current_function_calls_eh_return
+ 	    && (regno == EH_RETURN_DATA_REGNO (0)
+ 		|| regno == EH_RETURN_DATA_REGNO (1)
+ 		|| regno == EH_RETURN_DATA_REGNO (2)
+ 		|| regno == EH_RETURN_DATA_REGNO (3))))
+ 
+       {
+ 	if (regno == last_movem_reg + 1)
+ 	  last_movem_reg++;
+ 	else
+ 	  break;
+       }
+ 
+   for (regno = FIRST_PSEUDO_REGISTER - 1;
+        regno > last_movem_reg;
+        regno--)
+     if ((((regs_ever_live[regno]
+ 	   && !call_used_regs[regno])
+ 	  || (regno == PIC_OFFSET_TABLE_REGNUM
+ 	      && (current_function_uses_pic_offset_table
+ 		  /* It is saved anyway, if there would be a gap.  */
+ 		  || (flag_pic
+ 		      && regs_ever_live[regno + 1]
+ 		      && !call_used_regs[regno + 1]))))
+ 	 && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed)
+ 	 && regno != CRIS_SRP_REGNUM)
+ 	|| (current_function_calls_eh_return
+ 	    && (regno == EH_RETURN_DATA_REGNO (0)
+ 		|| regno == EH_RETURN_DATA_REGNO (1)
+ 		|| regno == EH_RETURN_DATA_REGNO (2)
+ 		|| regno == EH_RETURN_DATA_REGNO (3))))
+       {
+ 	if (argspace_offset)
+ 	  {
+ 	    /* There is an area for outgoing parameters located before
+ 	       the saved registers.  We have to adjust for that.  */
+ 	    if (file)
+ 	      fprintf (file, "\tAdd%s %d,$sp\n",
+ 		       ADDITIVE_SIZE_MODIFIER (argspace_offset),
+ 		       argspace_offset);
+ 
+ 	    /* Make sure we only do this once.  */
+ 	    argspace_offset = 0;
+ 	  }
+ 
+ 	/* Flush previous non-movem:ed registers.  */
+ 	if (*save_last && file)
+ 	  fprintf (file, save_last);
+ 	sprintf (save_last, "\tPop $%s\n");
+       }
+ 
+   if (last_movem_reg != -1)
+     {
+       if (argspace_offset)
+ 	{
+ 	  /* Adjust for the outgoing parameters area, if that's not
+ 	     handled yet.  */
+ 	  if (*save_last && file)
+ 	    {
+ 	      fprintf (file, save_last);
+ 	      *save_last = 0;
+ 	    }
+ 	
+ 	  if (file)
+ 	    fprintf (file, "\tAdd%s %d,$sp\n",
+ 		     ADDITIVE_SIZE_MODIFIER (argspace_offset),
+ 		     argspace_offset);
+ 	  argspace_offset = 0;
+ 	}
+       /* Flush previous non-movem:ed registers.  */
+       else if (*save_last && file)
+ 	fprintf (file, save_last);
+       sprintf (save_last, "\tmovem [$sp+],$%s\n", reg_names[last_movem_reg]);
+     }
+ 
+   /* Restore frame pointer if necessary.  */
+   if (frame_pointer_needed)
+     {
+       if (*save_last && file)
+ 	fprintf (file, save_last);
+ 
+       if (file)
+ 	fprintf (file, "\tmove.d $%s,$sp\n",
+ 		 reg_names[FRAME_POINTER_REGNUM]);
+       sprintf (save_last, "\tPop $%s\n",
+ 	       reg_names[FRAME_POINTER_REGNUM]);
+     }
+   else
+     {
+       /* If there was no frame-pointer to restore sp from, we must
+ 	 explicitly deallocate local variables.  */
+ 
+       /* Handle space for outgoing parameters that hasn't been handled
+ 	 yet.  */
+       size += argspace_offset;
+ 
+       if (size)
+ 	{
+ 	  if (*save_last && file)
+ 	    fprintf (file, save_last);
+ 
+ 	  sprintf (save_last, "\tadd%s %d,$sp\n",
+ 		   ADDITIVE_SIZE_MODIFIER (size), size);
+ 	}
+ 
+       /* If the size was not in the range for a "quick", we must flush
+ 	 it here.  */
+       if (size > 63)
+ 	{
+ 	  if (file)
+ 	    fprintf (file, save_last);
+ 	  *save_last = 0;
+ 	}
+     }
+ 
+   /* If this function has no pushed register parameters
+      (stdargs/varargs), and if it is not a leaf function, then we can
+      just jump-return here.  */
+   if (return_address_on_stack && pretend == 0)
+     {
+       if (*save_last && file)
+ 	fprintf (file, save_last);
+       *save_last = 0;
+ 
+       if (file)
+ 	{
+ 	  if (current_function_calls_eh_return)
+ 	    {
+ 	      /* The installed EH-return address is in *this* frame, so we
+ 		 need to pop it before we return.  */
+ 	      fprintf (file, "\tpop $srp\n", reg_names[CRIS_STACKADJ_REG]);
+ 	      fprintf (file, "\tret\n");
+ 	      fprintf (file, "\tadd.d $%s,$sp\n", reg_names[CRIS_STACKADJ_REG]);
+ 	    }
+ 	  else
+ 	    fprintf (file, "\tJump [$sp+]\n");
+ 
+ 	  /* Do a sanity check to avoid generating invalid code.  */
+ 	  if (current_function_epilogue_delay_list)
+ 	    internal_error ("Allocated but unused delay list in epilogue");
+ 	}
+       return;
+     }
+ 
+   /* Rather than add current_function_calls_eh_return conditions
+      everywhere in the following code (and not be able to test it
+      thoroughly), assert the assumption that all usage of
+      __builtin_eh_return are handled above.  */
+   if (current_function_calls_eh_return)
+     internal_error ("Unexpected function type needing stack adjustment for\
+  __builtin_eh_return");
+ 
+   /* If we pushed some register parameters, then adjust the stack for
+      them.  */
+   if (pretend)
+     {
+       /* Since srp is stored on the way, we need to restore it first. */
+       if (return_address_on_stack)
+ 	{
+ 	  if (*save_last && file)
+ 	    fprintf (file, save_last);
+ 	  *save_last = 0;
+ 
+ 	  if (file)
+ 	    fprintf (file, "\tpop $srp\n");
+ 	}
+ 
+       if (*save_last && file)
+ 	fprintf (file, save_last);
+ 
+       sprintf (save_last, "\tadd%s %d,$sp\n",
+ 	       ADDITIVE_SIZE_MODIFIER (pretend), pretend);
+     }
+ 
+   /* Here's where we have a delay-slot we need to fill. */
+   if (file && current_function_epilogue_delay_list)
+     {
+       /* If gcc has allocated an insn for the epilogue delay slot, but
+ 	 things were arranged so we now thought we could do it
+ 	 ourselves, don't forget to flush that insn.  */
+       if (*save_last)
+ 	fprintf (file, save_last);
+ 
+       fprintf (file, "\tRet\n");
+ 
+       /* Output the delay-slot-insn the mandated way.  */
+       final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
+ 		       file, 1, -2, 1);
+     }
+   else if (file)
+     {
+       fprintf (file, "\tRet\n");
+ 
+       /* If the GCC did not do it, we have to use whatever insn we have,
+ 	 or a nop.  */
+       if (*save_last)
+ 	fprintf (file, save_last);
+       else
+ 	fprintf (file, "\tnOp\n");
+     }
+ }
+ 
+ /* The PRINT_OPERAND worker.  */
+ 
+ void
+ cris_print_operand (file, x, code)
+      FILE *file;
+      rtx x;
+      int code;
+ {
+   rtx operand = x;
+ 
+   /* Size-strings corresponding to MULT expressions.  */
+   static const char *mults[] = { "BAD:0", ".b", ".w", "BAD:3", ".d" };
+ 
+   /* New code entries should just be added to the switch below.  If
+      handling is finished, just return.  If handling was just a
+      modification of the operand, the modified operand should be put in
+      "operand", and then do a break to let default handling
+      (zero-modifier) output the operand.  */
+ 
+   switch (code)
+     {
+     case 'b':
+       /* Print the unsigned supplied integer as if it was signed
+ 	 and < 0, i.e print 255 or 65535 as -1, 254, 65534 as -2, etc.  */
+       if (GET_CODE (x) != CONST_INT
+ 	  || ! CONST_OK_FOR_LETTER_P (INTVAL (x), 'O'))
+ 	fatal_insn ("Internal: Invalid operand with 'b'", x);
+       fprintf (file, "%d", INTVAL (x)| (INTVAL (x) <= 255 ? ~255 : ~65535));
+       return;
+ 
+     case 'x':
+       /* Print assembler code for operator.  */
+       fprintf (file, "%s", cris_op_str (operand));
+       return;
+ 
+     case 'v':
+       /* Print the operand without the PIC register.  */
+       if (! flag_pic || ! cris_gotless_symbol (x))
+ 	fatal_insn ("Internal: Invalid operand with 'v'", x);
+       cris_pic_sympart_only++;
+       cris_output_addr_const (file, x);
+       cris_pic_sympart_only--;
+       return;
+ 
+     case 'P':
+       /* Print the PIC register.  Applied to a GOT-less PIC symbol for
+          sanity.  */
+       if (! flag_pic || ! cris_gotless_symbol (x))
+ 	fatal_insn ("Internal: Invalid operand with 'P'", x);
+       fprintf (file, "$%s", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+       return;
+ 
+     case 'p':
+       /* Adjust a power of two to its log2.  */
+       if (GET_CODE (x) != CONST_INT || exact_log2 (INTVAL (x)) < 0 )
+ 	fatal_insn ("Internal: Invalid operand with 'p'", x);
+       fprintf (file, "%d", exact_log2 (INTVAL (x)));
+       return;
+ 
+     case 's':
+       /* For an integer, print 'b' or 'w' if <= 255 or <= 65535
+ 	 respectively.  This modifier also terminates the inhibiting
+          effects of the 'x' modifier.  */
+       cris_output_insn_is_bound = 0;
+       if (GET_MODE (x) == VOIDmode && GET_CODE (x) == CONST_INT)
+ 	{
+ 	  if (INTVAL (x) >= 0)
+ 	    {
+ 	      if (INTVAL (x) <= 255)
+ 		putc ('b', file);
+ 	      else if (INTVAL (x) <= 65535)
+ 		putc ('w', file);
+ 	      else
+ 		putc ('d', file);
+ 	    }
+ 	  else
+ 	    putc ('d', file);
+ 	  return;
+ 	}
+ 
+       /* For a non-integer, print the size of the operand.  */
+       putc ((GET_MODE (x) == SImode || GET_MODE (x) == SFmode)
+ 	    ? 'd' : GET_MODE (x) == HImode ? 'w'
+ 	    : GET_MODE (x) == QImode ? 'b'
+ 	    /* If none of the above, emit an erroneous size letter.  */
+ 	    : 'X',
+ 	    file);
+       return;
+ 
+     case 'z':
+       /* Const_int: print b for -127 <= x <= 255,
+ 	 w for -32768 <= x <= 65535, else abort.  */
+       if (GET_CODE (x) != CONST_INT
+ 	  || INTVAL (x) < -32768 || INTVAL (x) > 65535)
+ 	fatal_insn ("Internal: Invalid operand with 'z'", x);
+       putc (INTVAL (x) >= -128 && INTVAL (x) <= 255 ? 'b' : 'w', file);
+       return;
+ 
+     case '#':
+       /* Output a 'nop' if there's nothing for the delay slot.
+ 	 This method stolen from the sparc files.  */
+       if (dbr_sequence_length () == 0)
+ 	fputs ("\n\tnop", file);
+       return;
+ 
+     case 'H':
+       /* Print high (most significant) part of something.  */
+       switch (GET_CODE (operand))
+ 	{
+ 	case CONST_INT:
+ 	  /* Sign-extension from a normal int to a long long.  */
+ 	  fprintf (file, INTVAL (operand) < 0 ? "-1" : "0");
+ 	  return;
+ 
+ 	case CONST_DOUBLE:
+ 	  /* High part of a long long constant.  */
+ 	  if (GET_MODE (operand) == VOIDmode)
+ 	    {
+ 	      fprintf (file, "0x%x", CONST_DOUBLE_HIGH (x));
+ 	      return;
+ 	    }
+ 	  else
+ 	    fatal_insn ("Internal: Invalid operand with 'H'", x);
+ 
+ 	case REG:
+ 	  /* Print reg + 1.  Check that there's not an attempt to print
+ 	     high-parts of registers like stack-pointer or higher.  */
+ 	  if (REGNO (operand) > STACK_POINTER_REGNUM - 2)
+ 	    internal_error ("Internal: Bad register: %d", REGNO (operand));
+ 	  fprintf (file, "$%s", reg_names[REGNO (operand) + 1]);
+ 	  return;
+ 
+ 	case MEM:
+ 	  /* Adjust memory address to high part.  */
+ 	  {
+ 	    rtx adj_mem = operand;
+ 	    int size
+ 	      = GET_MODE_BITSIZE (GET_MODE (operand)) / BITS_PER_UNIT;
+ 
+ 	    /* Adjust so we can use two SImode in DImode.
+ 	       Calling adj_offsettable_operand will make sure it is an
+ 	       offsettable address.  Don't do this for a postincrement
+ 	       though; it should remain as it was.  */
+ 	    if (GET_CODE (XEXP (adj_mem, 0)) != POST_INC)
+ 	      adj_mem
+ 		= adjust_address (adj_mem, GET_MODE (adj_mem), size / 2);
+ 
+ 	    output_address (XEXP (adj_mem, 0));
+ 	    return;
+ 	  }
+ 
+ 	default:
+ 	  fatal_insn ("Internal: Invalid operand for 'H'", x);
+ 	}
+ 
+     case 'L':
+       /* Strip the MEM expression.  */
+       operand = XEXP (operand, 0);
+       break;
+ 
+     case 'e':
+       /* Print 's' if operand is SIGN_EXTEND or 'u' if ZERO_EXTEND unless
+ 	 cris_output_insn_is_bound is nonzero.  */
+       if (GET_CODE (operand) != SIGN_EXTEND
+ 	  && GET_CODE (operand) != ZERO_EXTEND
+ 	  && GET_CODE (operand) != CONST_INT)
+ 	fatal_insn ("Internal: Invalid operand with 'e'", x);
+ 
+       if (cris_output_insn_is_bound)
+ 	{
+ 	  cris_output_insn_is_bound = 0;
+ 	  return;
+ 	}
+ 
+       putc (GET_CODE (operand) == SIGN_EXTEND
+ 	    || (GET_CODE (operand) == CONST_INT && INTVAL (operand) < 0)
+ 	    ? 's' : 'u', file);
+       return;
+ 
+     case 'm':
+       /* Print the size letter of the inner element.  We can do it by
+ 	 calling ourselves with the 's' modifier.  */
+       if (GET_CODE (operand) != SIGN_EXTEND && GET_CODE (operand) != ZERO_EXTEND)
+ 	fatal_insn ("Internal: Invalid operand with 'm'", x);
+       cris_print_operand (file, XEXP (operand, 0), 's');
+       return;
+ 
+     case 'M':
+       /* Print the least significant part of operand.  */
+       if (GET_CODE (operand) == CONST_DOUBLE)
+ 	{
+ 	  fprintf (file, "0x%x", CONST_DOUBLE_LOW (x));
+ 	  return;
+ 	}
+       /* If not a CONST_DOUBLE, the least significant part equals the
+ 	 normal part, so handle it normally.  */
+       break;
+ 
+     case 'A':
+       /* When emitting an add for the high part of a DImode constant, we
+ 	 want to use addq for 0 and adds.w for -1.  */
+       if (GET_CODE (operand) != CONST_INT)
+ 	fatal_insn ("Internal: Invalid operand with 'A' output modifier", x);
+       fprintf (file, INTVAL (operand) < 0 ? "adds.w" : "addq");
+       return;
+ 
+     case 'D':
+       /* When emitting an sub for the high part of a DImode constant, we
+ 	 want to use subq for 0 and subs.w for -1.  */
+       if (GET_CODE (operand) != CONST_INT)
+ 	fatal_insn ("Internal: Invalid operand with 'D' output modifier", x);
+       fprintf (file, INTVAL (operand) < 0 ? "subs.w" : "subq");
+       return;
+ 
+     case 'S':
+       /* Print the operand as the index-part of an address.
+ 	 Easiest way out is to use cris_print_index.  */
+       cris_print_index (operand, file);
+       return;
+ 
+     case 'T':
+       /* Print the size letter for an operand to a MULT, which must be a
+ 	 const_int with a suitable value.  */
+       if (GET_CODE (operand) != CONST_INT || INTVAL (operand) > 4)
+ 	fatal_insn ("Internal: Invalid operand with 'T'", x);
+ 
+       fprintf (file, "%s", mults[INTVAL (operand)]);
+       return;
+ 
+     case 0:
+       /* No code, print as usual. */
+       break;
+ 
+     default:
+       {
+ #define BADFORMAT "Internal: Invalid operand for '%c'"
+ 	char s[sizeof BADFORMAT];
+ 	sprintf (s, BADFORMAT, code);
+ 	fatal_insn (s, x);
+       }
+     }
+ 
+   /* Print an operand as without a modifier letter. */
+   switch (GET_CODE (operand))
+     {
+     case REG:
+       if (REGNO (operand) > 15)
+ 	internal_error ("Internal: Bad register: %d", REGNO (operand));
+       fprintf (file, "$%s", reg_names[REGNO (operand)]);
+       return;
+ 
+     case MEM:
+       output_address (XEXP (operand, 0));
+       return;
+ 
+     case CONST_DOUBLE:
+       if (GET_MODE (operand) == VOIDmode)
+ 	/* A long long constant.  */
+ 	output_addr_const (file, operand);
+       else
+ 	{
+ 	  /* Only single precision is allowed as plain operands the
+ 	     moment.  FIXME:  REAL_VALUE_FROM_CONST_DOUBLE isn't
+ 	     documented.  */
+ 	  REAL_VALUE_TYPE r;
+ 	  long l;
+ 
+ 	  /* FIXME:  Perhaps check overflow of the "single".  */
+ 	  REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
+ 	  REAL_VALUE_TO_TARGET_SINGLE (r, l);
+ 
+ 	  fprintf (file, "0x%lx", l);
+ 	}
+       return;
+ 
+     case UNSPEC:
+       ASSERT_PLT_UNSPEC (operand);
+       /* Fall through.  */
+ 
+     case CONST:
+       cris_output_addr_const (file, operand);
+       return;
+ 
+     case MULT:
+     case ASHIFT:
+       {
+ 	/* For a (MULT (reg X) const_int) we output "rX.S".  */
+ 	int i = GET_CODE (XEXP (operand, 1)) == CONST_INT
+ 	  ? INTVAL (XEXP (operand, 1)) : INTVAL (XEXP (operand, 0));
+ 	rtx reg = GET_CODE (XEXP (operand, 1)) == CONST_INT
+ 	  ? XEXP (operand, 0) : XEXP (operand, 1);
+ 
+ 	if (GET_CODE (reg) != REG
+ 	    || (GET_CODE (XEXP (operand, 0)) != CONST_INT
+ 		&& GET_CODE (XEXP (operand, 1)) != CONST_INT))
+ 	  fatal_insn ("Can't print operand", x);
+ 
+ 	cris_print_base (reg, file);
+ 	fprintf (file, ".%c",
+ 		 i == 0 || (i == 1 && GET_CODE (operand) == MULT) ? 'b'
+ 		 : i == 4 ? 'd'
+ 		 : (i == 2 && GET_CODE (operand) == MULT) || i == 1 ? 'w'
+ 		 : 'd');
+ 	return;
+       }
+ 
+     default:
+       /* No need to handle all strange variants, let output_addr_const
+ 	 do it for us.  */
+       if (CONSTANT_P (operand))
+ 	{
+ 	  cris_output_addr_const (file, operand);
+ 	  return;
+ 	}
+ 
+       fatal_insn ("Internal: Cannot decode operand", x);
+     }
+ }
+ 
+ /* The PRINT_OPERAND_ADDRESS worker.  */
+ 
+ void
+ cris_print_operand_address (file, x)
+      FILE *file;
+      rtx x;
+ {
+   /* All these were inside MEM:s so output indirection characters.  */
+   putc ('[', file);
+ 
+   if (CONSTANT_ADDRESS_P (x))
+     cris_output_addr_const (file, x);
+   else if (BASE_OR_AUTOINCR_P (x))
+     cris_print_base (x, file);
+   else if (GET_CODE (x) == PLUS)
+     {
+       rtx x1, x2;
+ 
+       x1 = XEXP (x, 0);
+       x2 = XEXP (x, 1);
+       if (BASE_P (x1))
+ 	{
+ 	  cris_print_base (x1, file);
+ 	  cris_print_index (x2, file);
+ 	}
+       else if (BASE_P (x2))
+ 	{
+ 	  cris_print_base (x2, file);
+ 	  cris_print_index (x1, file);
+ 	}
+       else
+ 	fatal_insn ("Internal: This is not a recognized address", x);
+     }
+   else if (GET_CODE (x) == MEM)
+     {
+       /* A DIP.  Output more indirection characters.  */
+       putc ('[', file);
+       cris_print_base (XEXP (x, 0), file);
+       putc (']', file);
+     }
+   else
+     fatal_insn ("Internal: This is not a recognized address", x);
+ 
+   putc (']', file);
+ }
+ 
+ /* The RETURN_ADDR_RTX worker.
+    We mark that the return address is used, either by EH or
+    __builtin_return_address, for use by the function prologue and
+    epilogue.  FIXME: This isn't optimal; we just use the mark in the
+    prologue and epilogue to say that the return address is to be stored
+    in the stack frame.  We could return SRP for leaf-functions and use the
+    initial-value machinery.  */
+ 
+ rtx
+ cris_return_addr_rtx (count, frameaddr)
+      int count;
+      rtx frameaddr ATTRIBUTE_UNUSED;
+ {
+   cfun->machine->needs_return_address_on_stack = 1;
+ 
+   /* The return-address is stored just above the saved frame-pointer (if
+      present).  Apparently we can't eliminate from the frame-pointer in
+      that direction, so use the incoming args (maybe pretended) pointer.  */
+   return count == 0
+     ? gen_rtx_MEM (Pmode, plus_constant (virtual_incoming_args_rtx, -4))
+     : NULL_RTX;
+ }
+ 
+ /* This used to be the INITIAL_FRAME_POINTER_OFFSET worker; now only
+    handles FP -> SP elimination offset.  */
+ 
+ static int
+ cris_initial_frame_pointer_offset ()
+ {
+   int regno;
+ 
+   /* Initial offset is 0 if we dont have a frame pointer.  */
+   int offs = 0;
+ 
+   /* And 4 for each register pushed.  */
+   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+     if ((((regs_ever_live[regno]
+ 	   && !call_used_regs[regno])
+ 	  || (regno == PIC_OFFSET_TABLE_REGNUM
+ 	      && (current_function_uses_pic_offset_table
+ 		  /* It is saved anyway, if there would be a gap.  */
+ 		  || (flag_pic
+ 		      && regs_ever_live[regno + 1]
+ 		      && !call_used_regs[regno + 1]))))
+ 	 && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed)
+ 	 && regno != CRIS_SRP_REGNUM)
+ 	|| (current_function_calls_eh_return
+ 	    && (regno == EH_RETURN_DATA_REGNO (0)
+ 		|| regno == EH_RETURN_DATA_REGNO (1)
+ 		|| regno == EH_RETURN_DATA_REGNO (2)
+ 		|| regno == EH_RETURN_DATA_REGNO (3))))
+       offs += 4;
+ 
+   /* And then, last, we add the locals allocated.  */
+   offs += get_frame_size ();
+ 
+   /* And more; the accumulated args size.  */
+   offs += current_function_outgoing_args_size;
+ 
+   /* Then round it off, in case we use aligned stack.  */
+   if (TARGET_STACK_ALIGN)
+     offs = TARGET_ALIGN_BY_32 ? (offs + 3) & ~3 : (offs + 1) & ~1;
+ 
+   return offs;
+ }
+ 
+ /* The INITIAL_ELIMINATION_OFFSET worker.
+    Calculate the difference between imaginary registers such as frame
+    pointer and the stack pointer.  Used to eliminate the frame pointer
+    and imaginary arg pointer.  */
+ 
+ int
+ cris_initial_elimination_offset (fromreg, toreg)
+      int fromreg;
+      int toreg;
+ {
+   int fp_sp_offset
+     = cris_initial_frame_pointer_offset ();
+ 
+   /* We should be able to use regs_ever_live and related prologue
+      information here, or alpha should not as well.  */
+   int return_address_on_stack
+     = regs_ever_live[CRIS_SRP_REGNUM]
+     || cfun->machine->needs_return_address_on_stack != 0;
+ 
+   /* Here we act as if the frame-pointer is needed.  */
+   int ap_fp_offset = 4 + (return_address_on_stack ? 4 : 0);
+ 
+   if (fromreg == ARG_POINTER_REGNUM
+       && toreg == FRAME_POINTER_REGNUM)
+     return ap_fp_offset;
+ 
+   /* Between the frame pointer and the stack are only "normal" stack
+      variables and saved registers.  */
+   if (fromreg == FRAME_POINTER_REGNUM
+       && toreg == STACK_POINTER_REGNUM)
+     return fp_sp_offset;
+ 
+   /* We need to balance out the frame pointer here. */
+   if (fromreg == ARG_POINTER_REGNUM
+       && toreg == STACK_POINTER_REGNUM)
+     return ap_fp_offset + fp_sp_offset - 4;
+ 
+   abort ();
+ }
+ 
+ /*  This function looks into the pattern to see how this insn affects
+     condition codes.
+ 
+     Used when to eliminate test insns before a condition-code user,
+     such as a "scc" insn or a conditional branch.  This includes
+     checking if the entities that cc was updated by, are changed by the
+     operation.
+ 
+     Currently a jumble of the old peek-inside-the-insn and the newer
+     check-cc-attribute methods.  */
+ 
+ void
+ cris_notice_update_cc (exp, insn)
+      rtx exp;
+      rtx insn;
+ {
+   /* Check if user specified "-mcc-init" as a bug-workaround.  FIXME:
+      TARGET_CCINIT does not work; we must set CC_REVERSED as below.
+      Several test-cases will otherwise fail, for example
+      gcc.c-torture/execute/20000217-1.c -O0 and -O1.  */
+   if (TARGET_CCINIT)
+     {
+       CC_STATUS_INIT;
+       return;
+     }
+ 
+   /* Slowly, we're converting to using attributes to control the setting
+      of condition-code status.  */
+   switch (get_attr_cc (insn))
+     {
+     case CC_NONE:
+       /* Even if it is "none", a setting may clobber a previous
+ 	 cc-value, so check.  */
+       if (GET_CODE (exp) == SET)
+ 	{
+ 	  if (cc_status.value1
+ 	      && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+ 					     cc_status.value1))
+ 	    cc_status.value1 = 0;
+ 
+ 	  if (cc_status.value2
+ 	      && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+ 					     cc_status.value2))
+ 	    cc_status.value2 = 0;
+ 	}
+       return;
+ 
+     case CC_CLOBBER:
+       CC_STATUS_INIT;
+       break;
+ 
+     case CC_NORMAL:
+       /* Which means, for:
+ 	 (set (cc0) (...)):
+ 	 CC is (...).
+ 
+ 	 (set (reg) (...)):
+ 	 CC is (reg) and (...) - unless (...) is 0, then CC does not change.
+ 	 CC_NO_OVERFLOW unless (...) is reg or mem.
+ 
+ 	 (set (mem) (...)):
+ 	 CC does not change.
+ 
+ 	 (set (pc) (...)):
+ 	 CC does not change.
+ 
+ 	 (parallel
+ 	  (set (reg1) (mem (bdap/biap)))
+ 	  (set (reg2) (bdap/biap))):
+ 	 CC is (reg1) and (mem (reg2))
+ 
+ 	 (parallel
+ 	  (set (mem (bdap/biap)) (reg1)) [or 0]
+ 	  (set (reg2) (bdap/biap))):
+ 	 CC does not change.
+ 
+ 	 (where reg and mem includes strict_low_parts variants thereof)
+ 
+ 	 For all others, assume CC is clobbered.
+ 	 Note that we do not have to care about setting CC_NO_OVERFLOW,
+ 	 since the overflow flag is set to 0 (i.e. right) for
+ 	 instructions where it does not have any sane sense, but where
+ 	 other flags have meanings.  (This includes shifts; the carry is
+ 	 not set by them).
+ 
+ 	 Note that there are other parallel constructs we could match,
+ 	 but we don't do that yet.  */
+ 
+       if (GET_CODE (exp) == SET)
+ 	{
+ 	  /* FIXME: Check when this happens.  It looks like we should
+ 	     actually do a CC_STATUS_INIT here to be safe.  */
+ 	  if (SET_DEST (exp) == pc_rtx)
+ 	    return;
+ 
+ 	  /* Record CC0 changes, so we do not have to output multiple
+ 	     test insns. */
+ 	  if (SET_DEST (exp) == cc0_rtx)
+ 	    {
+ 	      cc_status.value1 = SET_SRC (exp);
+ 	      cc_status.value2 = 0;
+ 
+ 	      /* Handle flags for the special btstq on one bit. */
+ 	      if (GET_CODE (SET_SRC (exp)) == ZERO_EXTRACT
+ 		  && XEXP (SET_SRC (exp), 1) == const1_rtx)
+ 		{
+ 		  if (GET_CODE (XEXP (SET_SRC (exp), 0)) == CONST_INT)
+ 		    /* Using cmpq.  */
+ 		    cc_status.flags = CC_INVERTED;
+ 		  else
+ 		    /* A one-bit btstq.  */
+ 		    cc_status.flags = CC_Z_IN_NOT_N;
+ 		}
+ 	      else
+ 		cc_status.flags = 0;
+ 
+ 	      if (GET_CODE (SET_SRC (exp)) == COMPARE)
+ 		{
+ 		  if (!REG_P (XEXP (SET_SRC (exp), 0))
+ 		      && XEXP (SET_SRC (exp), 1) != const0_rtx)
+ 		    /* For some reason gcc will not canonicalize compare
+ 		       operations, reversing the sign by itself if
+ 		       operands are in wrong order. */
+ 		    /* (But NOT inverted; eq is still eq.) */
+ 		    cc_status.flags = CC_REVERSED;
+ 
+ 		  /* This seems to be overlooked by gcc.  FIXME: Check again.
+ 		     FIXME:  Is it really safe?  */
+ 		  cc_status.value2
+ 		    = gen_rtx_MINUS (GET_MODE (SET_SRC (exp)),
+ 				     XEXP (SET_SRC (exp), 0),
+ 				     XEXP (SET_SRC (exp), 1));
+ 		}
+ 	      return;
+ 	    }
+ 	  else if (REG_P (SET_DEST (exp))
+ 		   || (GET_CODE (SET_DEST (exp)) == STRICT_LOW_PART
+ 		       && REG_P (XEXP (SET_DEST (exp), 0))))
+ 	    {
+ 	      /* A register is set; normally CC is set to show that no
+ 		 test insn is needed.  Catch the exceptions. */
+ 
+ 	      /* If not to cc0, then no "set"s in non-natural mode give
+ 		 ok cc0...  */
+ 	      if (GET_MODE_SIZE (GET_MODE (SET_DEST (exp))) > UNITS_PER_WORD
+ 		  || GET_MODE_CLASS (GET_MODE (SET_DEST (exp))) == MODE_FLOAT)
+ 		{
+ 		  /* ... except add:s and sub:s in DImode. */
+ 		  if (GET_MODE (SET_DEST (exp)) == DImode
+ 		      && (GET_CODE (SET_SRC (exp)) == PLUS
+ 			  || GET_CODE (SET_SRC (exp)) == MINUS))
+ 		    {
+ 		      cc_status.flags = 0;
+ 		      cc_status.value1 = SET_DEST (exp);
+ 		      cc_status.value2 = SET_SRC (exp);
+ 
+ 		      if (cris_reg_overlap_mentioned_p (cc_status.value1,
+ 							cc_status.value2))
+ 			cc_status.value2 = 0;
+ 
+ 		      /* Add and sub may set V, which gets us
+ 			 unoptimizable results in "gt" and "le" condition
+ 			 codes.  */
+ 		      cc_status.flags |= CC_NO_OVERFLOW;
+ 
+ 		      return;
+ 		    }
+ 		}
+ 	      else if (SET_SRC (exp) == const0_rtx)
+ 		{
+ 		  /* There's no CC0 change when clearing a register or
+ 		     memory.  Just check for overlap.  */
+ 		  if ((cc_status.value1
+ 		       && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+ 							cc_status.value1)))
+ 		    cc_status.value1 = 0;
+ 
+ 		  if ((cc_status.value2
+ 		       && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+ 							cc_status.value2)))
+ 		    cc_status.value2 = 0;
+ 
+ 		  return;
+ 		}
+ 	      else
+ 		{
+ 		  cc_status.flags = 0;
+ 		  cc_status.value1 = SET_DEST (exp);
+ 		  cc_status.value2 = SET_SRC (exp);
+ 
+ 		  if (cris_reg_overlap_mentioned_p (cc_status.value1,
+ 						    cc_status.value2))
+ 		    cc_status.value2 = 0;
+ 
+ 		  /* Some operations may set V, which gets us
+ 		     unoptimizable results in "gt" and "le" condition
+ 		     codes.  */
+ 		  if (GET_CODE (SET_SRC (exp)) == PLUS
+ 		      || GET_CODE (SET_SRC (exp)) == MINUS
+ 		      || GET_CODE (SET_SRC (exp)) == NEG)
+ 		    cc_status.flags |= CC_NO_OVERFLOW;
+ 
+ 		  return;
+ 		}
+ 	    }
+ 	  else if (GET_CODE (SET_DEST (exp)) == MEM
+ 		   || (GET_CODE (SET_DEST (exp)) == STRICT_LOW_PART
+ 		       && GET_CODE (XEXP (SET_DEST (exp), 0)) == MEM))
+ 	    {
+ 	      /* When SET to MEM, then CC is not changed (except for
+ 		 overlap).  */
+ 	      if ((cc_status.value1
+ 		   && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+ 						    cc_status.value1)))
+ 		cc_status.value1 = 0;
+ 
+ 	      if ((cc_status.value2
+ 		   && cris_reg_overlap_mentioned_p (SET_DEST (exp),
+ 						    cc_status.value2)))
+ 		cc_status.value2 = 0;
+ 
+ 	      return;
+ 	    }
+ 	}
+       else if (GET_CODE (exp) == PARALLEL)
+ 	{
+ 	  if (GET_CODE (XVECEXP (exp, 0, 0)) == SET
+ 	      && GET_CODE (XVECEXP (exp, 0, 1)) == SET
+ 	      && REG_P (XEXP (XVECEXP (exp, 0, 1), 0)))
+ 	    {
+ 	      if (REG_P (XEXP (XVECEXP (exp, 0, 0), 0))
+ 		  && GET_CODE (XEXP (XVECEXP (exp, 0, 0), 1)) == MEM)
+ 		{
+ 		  /* For "move.S [rx=ry+o],rz", say CC reflects
+ 		     value1=rz and value2=[rx] */
+ 		  cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0);
+ 		  cc_status.value2
+ 		    = gen_rtx_MEM (GET_MODE (XEXP (XVECEXP (exp, 0, 0), 0)),
+ 				   XEXP (XVECEXP (exp, 0, 1), 0));
+ 		  cc_status.flags = 0;
+ 
+ 		  /* Huh?  A side-effect cannot change the destination
+ 		     register.  */
+ 		  if (cris_reg_overlap_mentioned_p (cc_status.value1,
+ 						    cc_status.value2))
+ 		    internal_error ("Internal: sideeffect-insn affecting main effect");
+ 		  return;
+ 		}
+ 	      else if ((REG_P (XEXP (XVECEXP (exp, 0, 0), 1))
+ 			|| XEXP (XVECEXP (exp, 0, 0), 1) == const0_rtx)
+ 		       && GET_CODE (XEXP (XVECEXP (exp, 0, 0), 0)) == MEM)
+ 		{
+ 		  /* For "move.S rz,[rx=ry+o]" and "clear.S [rx=ry+o]",
+ 		     say flags are not changed, except for overlap.  */
+ 		  if ((cc_status.value1
+ 		       && cris_reg_overlap_mentioned_p (XEXP
+ 							(XVECEXP
+ 							 (exp, 0, 0), 0),
+ 							cc_status.value1))
+ 		      || (cc_status.value2
+ 			  && cris_reg_overlap_mentioned_p (XEXP
+ 							   (XVECEXP
+ 							    (exp, 0, 1), 0),
+ 							   cc_status.value2)))
+ 		    CC_STATUS_INIT;
+ 		  return;
+ 		}
+ 	    }
+ 	}
+       break;
+ 
+     default:
+       /* Unknown cc_attr value.  */
+       abort ();
+     }
+ 
+   CC_STATUS_INIT;
+ }
+ 
+ /* Return != 0 if the return sequence for the current function is short,
+    like "ret" or "jump [sp+]".  Prior to reloading, we can't tell how
+    many registers must be saved, so return 0 then.  */
+ 
+ int
+ cris_simple_epilogue ()
+ {
+   int regno;
+   int reglimit = STACK_POINTER_REGNUM;
+   int lastreg = -1;
+ 
+   if (! reload_completed
+       || frame_pointer_needed
+       || get_frame_size () != 0
+       || current_function_pretend_args_size
+       || current_function_args_size
+       || current_function_outgoing_args_size
+       || current_function_calls_eh_return
+ 
+       /* If we're not supposed to emit prologue and epilogue, we must
+ 	 not emit return-type instructions.  */
+       || !TARGET_PROLOGUE_EPILOGUE)
+     return 0;
+ 
+   /* We allow a "movem [sp+],rN" to sit in front if the "jump [sp+]" or
+      in the delay-slot of the "ret".  */
+   for (regno = 0; regno < reglimit; regno++)
+     if ((regs_ever_live[regno] && ! call_used_regs[regno])
+ 	|| (regno == PIC_OFFSET_TABLE_REGNUM
+ 	    && (current_function_uses_pic_offset_table
+ 		/* It is saved anyway, if there would be a gap.  */
+ 		|| (flag_pic
+ 		    && regs_ever_live[regno + 1]
+ 		    && !call_used_regs[regno + 1]))))
+       {
+ 	if (lastreg != regno - 1)
+ 	  return 0;
+ 	lastreg = regno;
+       }
+ 
+   return 1;
+ }
+ 
+ /* The ADDRESS_COST worker.  */
+ 
+ int
+ cris_address_cost (x)
+      rtx x;
+ {
+   /* The metric to use for the cost-macros is unclear.
+      The metric used here is (the number of cycles needed) / 2,
+      where we consider equal a cycle for a word of code and a cycle to
+      read memory.  */
+ 
+   /* The cheapest addressing modes get 0, since nothing extra is needed.  */
+   if (BASE_OR_AUTOINCR_P (x))
+     return 0;
+ 
+   /* An indirect mem must be a DIP.  This means two bytes extra for code,
+      and 4 bytes extra for memory read, i.e.  (2 + 4) / 2.  */
+   if (GET_CODE (x) == MEM)
+     return (2 + 4) / 2;
+ 
+   /* Assume (2 + 4) / 2 for a single constant; a dword, since it needs
+      an extra DIP prefix and 4 bytes of constant in most cases.
+      For PIC and a symbol with a GOT entry, we double the cost since we
+      add a [rPIC+...] offset.  A GOT-less symbol uses a BDAP prefix
+      equivalent to the DIP prefix for non-PIC, hence the same cost.  */
+   if (CONSTANT_P (x))
+     return flag_pic && cris_got_symbol (x) ? 2 * (2 + 4) / 2 : (2 + 4) / 2;
+ 
+   /* Handle BIAP and BDAP prefixes.  */
+   if (GET_CODE (x) == PLUS)
+     {
+       rtx tem1 = XEXP (x, 0);
+       rtx tem2 = XEXP (x, 1);
+ 
+     /* A BIAP is 2 extra bytes for the prefix insn, nothing more.  We
+        recognize the typical MULT which is always in tem1 because of
+        insn canonicalization.  */
+     if ((GET_CODE (tem1) == MULT && BIAP_INDEX_P (tem1))
+ 	|| REG_P (tem1))
+       return 2 / 2;
+ 
+     /* A BDAP (quick) is 2 extra bytes.  Any constant operand to the
+        PLUS is always found in tem2.  */
+     if (GET_CODE (tem2) == CONST_INT
+ 	&& INTVAL (tem2) < 128 && INTVAL (tem2) >= -128)
+       return 2 / 2;
+ 
+     /* A BDAP -32768 .. 32767 is like BDAP quick, but with 2 extra
+        bytes.  */
+     if (GET_CODE (tem2) == CONST_INT
+ 	&& CONST_OK_FOR_LETTER_P (INTVAL (tem2), 'L'))
+       return (2 + 2) / 2;
+ 
+     /* A BDAP with some other constant is 2 bytes extra.  */
+     if (CONSTANT_P (tem2))
+       return (2 + 2 + 2) / 2;
+ 
+     /* BDAP with something indirect should have a higher cost than
+        BIAP with register.   FIXME: Should it cost like a MEM or more?  */
+     /* Don't need to check it, it's the only one left.
+        FIXME:  There was a REG test missing, perhaps there are others.
+        Think more.  */
+     return (2 + 2 + 2) / 2;
+   }
+ 
+   /* What else?  Return a high cost.  It matters only for valid
+      addressing modes.  */
+   return 10;
+ }
+ 
+ /* Check various objections to the side-effect.  Used in the test-part
+    of an anonymous insn describing an insn with a possible side-effect.
+    Returns nonzero if the implied side-effect is ok.
+ 
+    code     : PLUS or MULT
+    ops	    : An array of rtx:es. lreg, rreg, rval,
+ 	      The variables multop and other_op are indexes into this,
+ 	      or -1 if they are not applicable.
+    lreg     : The register that gets assigned in the side-effect.
+    rreg     : One register in the side-effect expression
+    rval     : The other register, or an int.
+    multop   : An integer to multiply rval with.
+    other_op : One of the entities of the main effect,
+ 	      whose mode we must consider.  */
+ 
+ int
+ cris_side_effect_mode_ok (code, ops, lreg, rreg, rval, multop, other_op)
+      enum rtx_code code;
+      rtx *ops;
+      int lreg, rreg, rval, multop, other_op;
+ {
+   /* Find what value to multiply with, for rx =ry + rz * n.  */
+   int mult = multop < 0 ? 1 : INTVAL (ops[multop]);
+ 
+   rtx reg_rtx = ops[rreg];
+   rtx val_rtx = ops[rval];
+ 
+   /* The operands may be swapped.  Canonicalize them in reg_rtx and
+      val_rtx, where reg_rtx always is a reg (for this constraint to
+      match).  */
+   if (! BASE_P (reg_rtx))
+     reg_rtx = val_rtx, val_rtx = ops[rreg];
+ 
+   /* Don't forget to check that reg_rtx really is a reg.  If it isn't,
+      we have no business.  */
+   if (! BASE_P (reg_rtx))
+     return 0;
+ 
+   /* Don't do this when -mno-split.  */
+   if (!TARGET_SIDE_EFFECT_PREFIXES)
+     return 0;
+ 
+   /* The mult expression may be hidden in lreg.  FIXME:  Add more
+      commentary about that.  */
+   if (GET_CODE (val_rtx) == MULT)
+     {
+       mult = INTVAL (XEXP (val_rtx, 1));
+       val_rtx = XEXP (val_rtx, 0);
+       code = MULT;
+     }
+ 
+   /* First check the "other operand".  */
+   if (other_op >= 0)
+     {
+       if (GET_MODE_SIZE (GET_MODE (ops[other_op])) > UNITS_PER_WORD)
+ 	return 0;
+ 
+       /* Check if the lvalue register is the same as the "other
+ 	 operand".  If so, the result is undefined and we shouldn't do
+ 	 this.  FIXME:  Check again.  */
+       if ((BASE_P (ops[lreg])
+ 	   && BASE_P (ops[other_op])
+ 	   && REGNO (ops[lreg]) == REGNO (ops[other_op]))
+ 	  || rtx_equal_p (ops[other_op], ops[lreg]))
+       return 0;
+     }
+ 
+   /* Do not accept frame_pointer_rtx as any operand.  */
+   if (ops[lreg] == frame_pointer_rtx || ops[rreg] == frame_pointer_rtx
+       || ops[rval] == frame_pointer_rtx
+       || (other_op >= 0 && ops[other_op] == frame_pointer_rtx))
+     return 0;
+ 
+   if (code == PLUS
+       && ! BASE_P (val_rtx))
+     {
+ 
+       /* Do not allow rx = rx + n if a normal add or sub with same size
+ 	 would do.  */
+       if (rtx_equal_p (ops[lreg], reg_rtx)
+ 	  && GET_CODE (val_rtx) == CONST_INT
+ 	  && (INTVAL (val_rtx) <= 63 && INTVAL (val_rtx) >= -63))
+ 	return 0;
+ 
+       /* Check allowed cases, like [r(+)?].[bwd] and const.
+ 	 A symbol is not allowed with PIC.  */
+       if (CONSTANT_P (val_rtx))
+ 	return flag_pic == 0 || cris_symbol (val_rtx) == 0;
+ 
+       if (GET_CODE (val_rtx) == MEM
+ 	  && BASE_OR_AUTOINCR_P (XEXP (val_rtx, 0)))
+ 	return 1;
+ 
+       if (GET_CODE (val_rtx) == SIGN_EXTEND
+ 	  && GET_CODE (XEXP (val_rtx, 0)) == MEM
+ 	  && BASE_OR_AUTOINCR_P (XEXP (XEXP (val_rtx, 0), 0)))
+ 	return 1;
+ 
+       /* If we got here, it's not a valid addressing mode.  */
+       return 0;
+     }
+   else if (code == MULT
+ 	   || (code == PLUS && BASE_P (val_rtx)))
+     {
+       /* Do not allow rx = rx + ry.S, since it doesn't give better code.  */
+       if (rtx_equal_p (ops[lreg], reg_rtx)
+ 	  || (mult == 1 && rtx_equal_p (ops[lreg], val_rtx)))
+ 	return 0;
+ 
+       /* Do not allow bad multiply-values.  */
+       if (mult != 1 && mult != 2 && mult != 4)
+ 	return 0;
+ 
+       /* Only allow  r + ...  */
+       if (! BASE_P (reg_rtx))
+ 	return 0;
+ 
+       /* If we got here, all seems ok.
+ 	 (All checks need to be done above).  */
+       return 1;
+     }
+ 
+   /* If we get here, the caller got its initial tests wrong.  */
+   internal_error ("Internal: cris_side_effect_mode_ok with bad operands");
+ }
+ 
+ /* The function reg_overlap_mentioned_p in CVS (still as of 2001-05-16)
+    does not handle the case where the IN operand is strict_low_part; it
+    does handle it for X.  Test-case in Axis-20010516.  This function takes
+    care of that for THIS port.  FIXME: strict_low_part is going away
+    anyway.  */
+ 
+ static int
+ cris_reg_overlap_mentioned_p (x, in)
+      rtx x, in;
+ {
+   /* The function reg_overlap_mentioned now handles when X is
+      strict_low_part, but not when IN is a STRICT_LOW_PART.  */
+   if (GET_CODE (in) == STRICT_LOW_PART)
+     in = XEXP (in, 0);
+ 
+   return reg_overlap_mentioned_p (x, in);
+ }
+ 
+ /* The TARGET_ASM_NAMED_SECTION worker.
+    We just dispatch to the functions for ELF and a.out.  */
+ 
+ void
+ cris_target_asm_named_section (name, flags)
+      const char *name;
+      unsigned int flags;
+ {
+   if (! TARGET_ELF)
+     default_no_named_section (name, flags);
+   else
+     default_elf_asm_named_section (name, flags);
+ }
+ 
+ /* The LEGITIMATE_PIC_OPERAND_P worker.  */
+ 
+ int
+ cris_legitimate_pic_operand (x)
+      rtx x;
+ {
+   /* The PIC representation of a symbol with a GOT entry will be (for
+      example; relocations differ):
+       sym => [rPIC+sym:GOT]
+      and for a GOT-less symbol it will be (for example, relocation differ):
+       sym => rPIC+sym:GOTOFF
+      so only a symbol with a GOT is by itself a valid operand, and it
+      can't be a sum of a symbol and an offset.  */
+   return ! cris_symbol (x) || cris_got_symbol (x);
+ }
+ 
+ /* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+    CONSTANT_P.  */
+ 
+ int
+ cris_symbol (x)
+      rtx x;
+ {
+   switch (GET_CODE (x))
+     {
+     case SYMBOL_REF:
+     case LABEL_REF:
+       return 1;
+ 
+     case UNSPEC:
+       /* A PLT reference.  */
+       ASSERT_PLT_UNSPEC (x);
+       return 1;
+ 
+     case CONST:
+       return cris_symbol (XEXP (x, 0));
+ 
+     case PLUS:
+     case MINUS:
+       return cris_symbol (XEXP (x, 0)) || cris_symbol (XEXP (x, 1));
+ 
+     case CONST_INT:
+     case CONST_DOUBLE:
+     case CONSTANT_P_RTX:
+       return 0;
+ 
+     default:
+       fatal_insn ("Unrecognized supposed constant", x);
+     }
+ 
+   return 1;
+ }
+ 
+ /* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+    CONSTANT_P, and the symbol does not need a GOT entry.  Also set
+    current_function_uses_pic_offset_table if we're generating PIC and ever
+    see something that would need one.  */
+ 
+ int
+ cris_gotless_symbol (x)
+      rtx x;
+ {
+   switch (GET_CODE (x))
+     {
+     case UNSPEC:
+       ASSERT_PLT_UNSPEC (x);
+       return 1;
+ 
+     case SYMBOL_REF:
+       if (flag_pic && cfun != NULL)
+ 	current_function_uses_pic_offset_table = 1;
+       return SYMBOL_REF_FLAG (x);
+ 
+     case LABEL_REF:
+       /* We don't set current_function_uses_pic_offset_table for
+ 	 LABEL_REF:s in here, since they are almost always originating
+ 	 from some branch.  The only time it does not come from a label is
+ 	 when GCC does something like __builtin_setjmp.  Then we get the
+ 	 LABEL_REF from the movsi expander, so we mark it there as a
+ 	 special case.  */
+       return 1;
+ 
+     case CONST:
+       return cris_gotless_symbol (XEXP (x, 0));
+ 
+     case PLUS:
+     case MINUS:
+       {
+ 	int x0 = cris_gotless_symbol (XEXP (x, 0)) != 0;
+ 	int x1 = cris_gotless_symbol (XEXP (x, 1)) != 0;
+ 
+ 	/* One and only one of them must be a local symbol.  Neither must
+ 	   be some other, more general kind of symbol.  */
+ 	return
+ 	  (x0 ^ x1)
+ 	  && ! (x0 == 0 && cris_symbol (XEXP (x, 0)))
+ 	  && ! (x1 == 0 && cris_symbol (XEXP (x, 1)));
+       }
+ 
+     case CONST_INT:
+     case CONST_DOUBLE:
+     case CONSTANT_P_RTX:
+       return 0;
+ 
+     default:
+       fatal_insn ("Unrecognized supposed constant", x);
+     }
+ 
+   return 1;
+ }
+ 
+ /* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+    CONSTANT_P, and the symbol needs a GOT entry.  */
+ 
+ int
+ cris_got_symbol (x)
+      rtx x;
+ {
+   switch (GET_CODE (x))
+     {
+     case UNSPEC:
+       ASSERT_PLT_UNSPEC (x);
+       return 0;
+ 
+     case SYMBOL_REF:
+       if (flag_pic && cfun != NULL)
+ 	current_function_uses_pic_offset_table = 1;
+       return ! SYMBOL_REF_FLAG (x);
+ 
+     case CONST:
+       return cris_got_symbol (XEXP (x, 0));
+ 
+     case LABEL_REF:
+       /* A LABEL_REF is never visible as a symbol outside the local
+          function.  */
+     case PLUS:
+     case MINUS:
+       /* Nope, can't access the GOT for "symbol + offset".  */
+       return 0;
+ 
+     case CONST_INT:
+     case CONST_DOUBLE:
+     case CONSTANT_P_RTX:
+       return 0;
+ 
+     default:
+       fatal_insn ("Unrecognized supposed constant in cris_global_pic_symbol",
+ 		  x);
+     }
+ 
+   return 1;
+ }
+ 
+ /* The OVERRIDE_OPTIONS worker.
+    As is the norm, this also parses -mfoo=bar type parameters.  */
+ 
+ void
+ cris_override_options ()
+ {
+   if (cris_max_stackframe_str)
+     {
+       cris_max_stackframe = atoi (cris_max_stackframe_str);
+ 
+       /* Do some sanity checking.  */
+       if (cris_max_stackframe < 0 || cris_max_stackframe > 0x20000000)
+ 	internal_error ("-max-stackframe=%d is not usable, not between 0 and %d",
+ 			cris_max_stackframe, 0x20000000);
+     }
+ 
+   /* Let "-metrax4" and "-metrax100" change the cpu version.  */
+   if (TARGET_SVINTO && cris_cpu_version < CRIS_CPU_SVINTO)
+     cris_cpu_version = CRIS_CPU_SVINTO;
+   else if (TARGET_ETRAX4_ADD && cris_cpu_version < CRIS_CPU_ETRAX4)
+     cris_cpu_version = CRIS_CPU_ETRAX4;
+ 
+   /* Parse -march=... and its synonym, the deprecated -mcpu=...  */
+   if (cris_cpu_str)
+     {
+       cris_cpu_version
+ 	= (*cris_cpu_str == 'v' ? atoi (cris_cpu_str + 1) : -1);
+ 
+       if (strcmp ("etrax4", cris_cpu_str) == 0)
+ 	cris_cpu_version = 3;
+ 
+       if (strcmp ("svinto", cris_cpu_str) == 0
+ 	  || strcmp ("etrax100", cris_cpu_str) == 0)
+ 	cris_cpu_version = 8;
+ 
+       if (strcmp ("ng", cris_cpu_str) == 0
+ 	  || strcmp ("etrax100lx", cris_cpu_str) == 0)
+ 	cris_cpu_version = 10;
+ 
+       if (cris_cpu_version < 0 || cris_cpu_version > 10)
+ 	error ("Unknown CRIS version specification in -march= or -mcpu= : %s",
+ 	       cris_cpu_str);
+ 
+       /* Set the target flags.  */
+       if (cris_cpu_version >= CRIS_CPU_ETRAX4)
+ 	target_flags |= TARGET_MASK_ETRAX4_ADD;
+ 
+       /* If this is Svinto or higher, align for 32 bit accesses.  */
+       if (cris_cpu_version >= CRIS_CPU_SVINTO)
+ 	target_flags
+ 	  |= (TARGET_MASK_SVINTO | TARGET_MASK_ALIGN_BY_32
+ 	      | TARGET_MASK_STACK_ALIGN | TARGET_MASK_CONST_ALIGN
+ 	      | TARGET_MASK_DATA_ALIGN);
+ 
+       /* Note that we do not add new flags when it can be completely
+ 	 described with a macro that uses -mcpu=X.  So
+ 	 TARGET_HAS_MUL_INSNS is (cris_cpu_version >= CRIS_CPU_NG).  */
+     }
+ 
+   if (cris_tune_str)
+     {
+       int cris_tune
+ 	= (*cris_tune_str == 'v' ? atoi (cris_tune_str + 1) : -1);
+ 
+       if (strcmp ("etrax4", cris_tune_str) == 0)
+ 	cris_tune = 3;
+ 
+       if (strcmp ("svinto", cris_tune_str) == 0
+ 	  || strcmp ("etrax100", cris_tune_str) == 0)
+ 	cris_tune = 8;
+ 
+       if (strcmp ("ng", cris_tune_str) == 0
+ 	  || strcmp ("etrax100lx", cris_tune_str) == 0)
+ 	cris_tune = 10;
+ 
+       if (cris_tune < 0 || cris_tune > 10)
+ 	error ("Unknown CRIS cpu version specification in -mtune= : %s",
+ 	       cris_tune_str);
+ 
+       if (cris_tune >= CRIS_CPU_SVINTO)
+ 	/* We have currently nothing more to tune than alignment for
+ 	   memory accesses.  */
+ 	target_flags
+ 	  |= (TARGET_MASK_STACK_ALIGN | TARGET_MASK_CONST_ALIGN
+ 	      | TARGET_MASK_DATA_ALIGN | TARGET_MASK_ALIGN_BY_32);
+     }
+ 
+   if (flag_pic)
+     {
+       /* Use error rather than warning, so invalid use is easily
+ 	 detectable.  Still change to the values we expect, to avoid
+ 	 further errors.  */
+       if (! TARGET_LINUX)
+ 	{
+ 	  error ("-fPIC not supported in this configuration");
+ 	  flag_pic = 0;
+ 	}
+ 
+       /* Turn off function CSE.  We need to have the addresses reach the
+ 	 call expanders to get PLT-marked, as they could otherwise be
+ 	 compared against zero directly or indirectly.  After visiting the
+ 	 call expanders they will then be cse:ed, as the call expanders
+ 	 force_reg the addresses, effectively forcing flag_no_function_cse
+ 	 to 0.  */
+       flag_no_function_cse = 1;
+     }
+ 
+   if ((write_symbols == DWARF_DEBUG
+        || write_symbols == DWARF2_DEBUG) && ! TARGET_ELF)
+     {
+       warning ("Specified -g option is invalid with -maout and -melinux");
+       write_symbols = DBX_DEBUG;
+     }
+ 
+   /* Set the per-function-data initializer.  */
+   init_machine_status = cris_init_machine_status;
+ }
+ 
+ /* The ASM_OUTPUT_MI_THUNK worker.  */
+ 
+ void
+ cris_asm_output_mi_thunk (stream, thunkdecl, delta, funcdecl)
+      FILE *stream;
+      tree thunkdecl ATTRIBUTE_UNUSED;
+      int delta;
+      tree funcdecl;
+ {
+   if (delta > 0)
+     asm_fprintf (stream, "\tadd%s %d,$%s\n",
+ 		 ADDITIVE_SIZE_MODIFIER (delta), delta,
+ 		 reg_names[CRIS_FIRST_ARG_REG]);
+   else if (delta < 0)
+     asm_fprintf (stream, "\tsub%s %d,$%s\n",
+ 		 ADDITIVE_SIZE_MODIFIER (-delta), -delta,
+ 		 reg_names[CRIS_FIRST_ARG_REG]);
+ 
+   if (flag_pic)
+     {
+       const char *name = XSTR (XEXP (DECL_RTL (funcdecl), 0), 0);
+ 
+       STRIP_NAME_ENCODING (name, name);
+       fprintf (stream, "add.d ");
+       assemble_name (stream, name);
+       fprintf (stream, "%s,$pc\n", CRIS_PLT_PCOFFSET_SUFFIX);
+     }
+   else
+     {
+       fprintf (stream, "jump ");
+       assemble_name (stream, XSTR (XEXP (DECL_RTL (funcdecl), 0), 0));
+       fprintf (stream, "\n");
+     }
+ }
+ 
+ /* The EXPAND_BUILTIN_VA_ARG worker.  This is modified from the
+    "standard" implementation of va_arg: read the value from the current
+    address and increment by the size of one or two registers.  The
+    important difference for CRIS is that if the type is
+    pass-by-reference, then perform an indirection.  */
+ 
+ rtx
+ cris_expand_builtin_va_arg (valist, type)
+      tree valist;
+      tree type;
+ {
+   tree addr_tree, t;
+   rtx addr;
+   enum machine_mode mode = TYPE_MODE (type);
+   int passed_size;
+ 
+   /* Get AP.  */
+   addr_tree = valist;
+ 
+   /* Check if the type is passed by value or by reference.  */
+   if (MUST_PASS_IN_STACK (mode, type)
+       || CRIS_FUNCTION_ARG_SIZE (mode, type) > 8)
+     {
+       tree type_ptr = build_pointer_type (type);
+       addr_tree = build1 (INDIRECT_REF, type_ptr, addr_tree);
+       passed_size = 4;
+     }
+   else
+     passed_size = (CRIS_FUNCTION_ARG_SIZE (mode, type) > 4) ? 8 : 4;
+ 
+   addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
+   addr = copy_to_reg (addr);
+ 
+   /* Compute new value for AP.  */
+   t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+ 	     build (PLUS_EXPR, TREE_TYPE (valist), valist,
+ 		    build_int_2 (passed_size, 0)));
+   TREE_SIDE_EFFECTS (t) = 1;
+   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 
+   return addr;
+ }
+ 
+ /* The INIT_EXPANDERS worker sets the per-function-data initializer and
+    mark functions.  */
+ 
+ void
+ cris_init_expanders ()
+ {
+   /* Nothing here at the moment.  */
+ }
+ 
+ /* Zero initialization is OK for all current fields.  */
+ 
+ static void
+ cris_init_machine_status (p)
+      struct function *p;
+ {
+   p->machine = xcalloc (1, sizeof (struct machine_function));
+ }
+ 
+ /* Split a 2 word move (DI or presumably DF) into component parts.
+    Originally a copy of gen_split_move_double in m32r.c.  */
+ 
+ rtx
+ cris_split_movdx (operands)
+      rtx *operands;
+ {
+   enum machine_mode mode = GET_MODE (operands[0]);
+   rtx dest = operands[0];
+   rtx src  = operands[1];
+   rtx val;
+ 
+   /* We might have (SUBREG (MEM)) here, so just get rid of the
+      subregs to make this code simpler.  It is safe to call
+      alter_subreg any time after reload.  */
+   if (GET_CODE (dest) == SUBREG)
+     dest = alter_subreg (dest);
+   if (GET_CODE (src) == SUBREG)
+     src = alter_subreg (src);
+ 
+   start_sequence ();
+   if (GET_CODE (dest) == REG)
+     {
+       int dregno = REGNO (dest);
+ 
+       /* Reg-to-reg copy.  */
+       if (GET_CODE (src) == REG)
+ 	{
+ 	  int sregno = REGNO (src);
+ 
+ 	  int reverse = (dregno == sregno + 1);
+ 
+ 	  /* We normally copy the low-numbered register first.  However, if
+ 	     the first register operand 0 is the same as the second register of
+ 	     operand 1, we must copy in the opposite order.  */
+ 	  emit_insn (gen_rtx_SET (VOIDmode,
+ 				  operand_subword (dest, reverse, TRUE, mode),
+ 				  operand_subword (src, reverse, TRUE, mode)));
+ 
+ 	  emit_insn (gen_rtx_SET (VOIDmode,
+ 				  operand_subword (dest, !reverse, TRUE, mode),
+ 				  operand_subword (src, !reverse, TRUE, mode)));
+ 	}
+       /* Constant-to-reg copy.  */
+       else if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
+ 	{
+ 	  rtx words[2];
+ 	  split_double (src, &words[0], &words[1]);
+ 	  emit_insn (gen_rtx_SET (VOIDmode,
+ 				  operand_subword (dest, 0, TRUE, mode),
+ 				  words[0]));
+ 
+ 	  emit_insn (gen_rtx_SET (VOIDmode,
+ 				  operand_subword (dest, 1, TRUE, mode),
+ 				  words[1]));
+ 	}
+       /* Mem-to-reg copy.  */
+       else if (GET_CODE (src) == MEM)
+ 	{
+ 	  /* If the high-address word is used in the address, we must load it
+ 	     last.  Otherwise, load it first.  */
+ 	  rtx addr = XEXP (src, 0);
+ 	  int reverse
+ 	    = (refers_to_regno_p (dregno, dregno + 1, addr, NULL) != 0);
+ 
+ 	  /* The original code imples that we can't do
+ 	     move.x [rN+],rM  move.x [rN],rM+1
+ 	     when rN is dead, because of REG_NOTES damage.  That is
+ 	     consistent with what I've seen, so don't try it.
+ 
+              We have two different cases here; if the addr is POST_INC,
+              just pass it through, otherwise add constants.  */
+ 
+           if (GET_CODE (addr) == POST_INC)
+ 	    {
+ 	      emit_insn (gen_rtx_SET (VOIDmode, 
+ 				      operand_subword (dest, 0, TRUE, mode),
+ 				      change_address (src, SImode, addr)));
+ 	      emit_insn (gen_rtx_SET (VOIDmode,
+ 				      operand_subword (dest, 1, TRUE, mode), 
+ 				      change_address (src, SImode, addr)));
+ 	    }
+ 	  else
+ 	    {
+ 	      /* Make sure we don't get any other addresses with
+ 		 embedded postincrements.  They should be stopped in
+ 		 GO_IF_LEGITIMATE_ADDRESS, but we're here for your
+ 		 safety.  */
+ 	      if (side_effects_p (addr))
+ 		fatal_insn ("Unexpected side-effects in address", addr);
+ 
+ 	      emit_insn (gen_rtx_SET
+ 			 (VOIDmode,
+ 			  operand_subword (dest, reverse, TRUE, mode),
+ 			  change_address
+ 			  (src, SImode,
+ 			   plus_constant (addr,
+ 					  reverse * UNITS_PER_WORD))));
+ 	      emit_insn (gen_rtx_SET
+ 			 (VOIDmode,
+ 			  operand_subword (dest, ! reverse, TRUE, mode),
+ 			  change_address
+ 			  (src, SImode,
+ 			   plus_constant (addr,
+ 					  (! reverse) *
+ 					  UNITS_PER_WORD))));
+ 	    }
+ 	}
+       else
+ 	abort ();
+     }
+   /* Reg-to-mem copy or clear mem.  */
+   else if (GET_CODE (dest) == MEM
+ 	   && (GET_CODE (src) == REG
+ 	       || src == const0_rtx
+ 	       || src == CONST0_RTX (DFmode)))
+     {
+       rtx addr = XEXP (dest, 0);
+ 
+       if (GET_CODE (addr) == POST_INC)
+ 	{
+ 	  emit_insn (gen_rtx_SET (VOIDmode,
+ 				  change_address (dest, SImode, addr),
+ 				  operand_subword (src, 0, TRUE, mode)));
+ 	  emit_insn (gen_rtx_SET (VOIDmode,
+ 				  change_address (dest, SImode, addr),
+ 				  operand_subword (src, 1, TRUE, mode)));
+ 	}
+       else
+ 	{
+ 	  /* Make sure we don't get any other addresses with embedded
+ 	     postincrements.  They should be stopped in
+ 	     GO_IF_LEGITIMATE_ADDRESS, but we're here for your safety.  */
+ 	  if (side_effects_p (addr))
+ 	    fatal_insn ("Unexpected side-effects in address", addr);
+ 
+ 	  emit_insn (gen_rtx_SET
+ 		     (VOIDmode,
+ 		      change_address (dest, SImode, addr),
+ 		      operand_subword (src, 0, TRUE, mode)));
+ 
+ 	  emit_insn (gen_rtx_SET
+ 		     (VOIDmode,
+ 		      change_address (dest, SImode,
+ 				      plus_constant (addr,
+ 						     UNITS_PER_WORD)),
+ 		      operand_subword (src, 1, TRUE, mode)));
+ 	}
+     }
+ 
+   else
+     abort ();
+ 
+   val = gen_sequence ();
+   end_sequence ();
+   return val;
+ }
+ 
+ /* This is in essence a copy of output_addr_const altered to output
+    symbolic operands as PIC.
+ 
+    FIXME: Add hooks similar to ASM_OUTPUT_SYMBOL_REF to get this effect in
+    the "real" output_addr_const.  All we need is one for LABEL_REF (and
+    one for CODE_LABEL?).  */
+ 
+ void
+ cris_output_addr_const (file, x)
+      FILE *file;
+      rtx x;
+ {
+   int is_plt = 0;
+ 
+ restart:
+   switch (GET_CODE (x))
+     {
+     case UNSPEC:
+       ASSERT_PLT_UNSPEC (x);
+       x = XVECEXP (x, 0, 0);
+       is_plt = 1;
+ 
+       /* Fall through.  */
+     case SYMBOL_REF:
+       if (flag_pic)
+ 	{
+ 	  const char *origstr = XSTR (x, 0);
+ 	  const char *str;
+ 
+ 	  STRIP_NAME_ENCODING (str, origstr);
+ 
+ 	  if (is_plt)
+ 	    {
+ 	      if (cris_pic_sympart_only)
+ 		{
+ 		  assemble_name (file, str);
+ 		  fprintf (file, ":PLTG");
+ 		}
+ 	      else
+ 		{
+ 		  if (TARGET_AVOID_GOTPLT)
+ 		    /* We shouldn't get here.  */
+ 		    abort ();
+ 
+ 		  fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+ 		  assemble_name (file, XSTR (x, 0));
+ 
+ 		  if (flag_pic == 1)
+ 		    fprintf (file, ":GOTPLT16]");
+ 		  else
+ 		    fprintf (file, ":GOTPLT]");
+ 		}
+ 	    }
+ 	  else if (cris_gotless_symbol (x))
+ 	    {
+ 	      if (! cris_pic_sympart_only)
+ 		fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+ 	      assemble_name (file, str);
+ 	      fprintf (file, ":GOTOFF");
+ 	    }
+ 	  else if (cris_got_symbol (x))
+ 	    {
+ 	      if (cris_pic_sympart_only)
+ 		abort ();
+ 	      fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+ 	      assemble_name (file, XSTR (x, 0));
+ 
+ 	      if (flag_pic == 1)
+ 		fprintf (file, ":GOT16]");
+ 	      else
+ 		fprintf (file, ":GOT]");
+ 	    }
+ 	  else
+ 	    fatal_insn ("Unexpected PIC symbol", x);
+ 
+ 	  /* Sanity check.  */
+ 	  if (! current_function_uses_pic_offset_table)
+ 	    internal_error ("Emitting PIC operand, but PIC register isn't set up");
+ 	}
+       else
+ 	assemble_name (file, XSTR (x, 0));
+       break;
+ 
+     case LABEL_REF:
+       /* If we get one of those here, it should be dressed as PIC.  Branch
+ 	 labels are normally output with the 'l' specifier, which means it
+ 	 will go directly to output_asm_label and not end up here.  */
+       if (GET_CODE (XEXP (x, 0)) != CODE_LABEL
+ 	  && (GET_CODE (XEXP (x, 0)) != NOTE
+ 	      || NOTE_LINE_NUMBER (XEXP (x, 0)) != NOTE_INSN_DELETED_LABEL))
+ 	fatal_insn ("Unexpected address expression", x);
+ 
+       if (flag_pic)
+ 	{
+ 	  if (cris_gotless_symbol (x))
+ 	    {
+ 	      if (! cris_pic_sympart_only)
+ 		fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+ 	      cris_output_addr_const (file, XEXP (x, 0));
+ 
+ 	      fprintf (file, ":GOTOFF");
+ 	    }
+ 	  else
+ 	    /* Labels are never marked as global symbols.  */
+ 	    fatal_insn ("Unexpected PIC symbol", x);
+ 
+ 	  /* Sanity check.  */
+ 	  if (! current_function_uses_pic_offset_table)
+ 	    internal_error ("Emitting PIC operand, but PIC register isn't set up");
+ 	  break;
+ 	}
+ 
+       output_addr_const (file, x);
+       break;
+ 
+     case NOTE:
+       if (NOTE_LINE_NUMBER (x) != NOTE_INSN_DELETED_LABEL)
+ 	fatal_insn ("Unexpected NOTE as addr_const:", x);
+     case CODE_LABEL:
+     case CONST_INT:
+     case CONST_DOUBLE:
+     case ZERO_EXTEND:
+     case SIGN_EXTEND:
+       output_addr_const (file, x);
+       break;
+ 
+     case CONST:
+       /* This used to output parentheses around the expression,
+ 	 but that does not work on the 386 (either ATT or BSD assembler).  */
+       cris_output_addr_const (file, XEXP (x, 0));
+       break;
+ 
+     case PLUS:
+       /* Some assemblers need integer constants to appear last (eg masm).  */
+       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+ 	{
+ 	  cris_output_addr_const (file, XEXP (x, 1));
+ 	  if (INTVAL (XEXP (x, 0)) >= 0)
+ 	    fprintf (file, "+");
+ 	  output_addr_const (file, XEXP (x, 0));
+ 	}
+       else
+ 	{
+ 	  cris_output_addr_const (file, XEXP (x, 0));
+ 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT
+ 	      || INTVAL (XEXP (x, 1)) >= 0)
+ 	    fprintf (file, "+");
+ 	  cris_output_addr_const (file, XEXP (x, 1));
+ 	}
+       break;
+ 
+     case MINUS:
+       /* Avoid outputting things like x-x or x+5-x,
+ 	 since some assemblers can't handle that.  */
+       x = simplify_subtraction (x);
+       if (GET_CODE (x) != MINUS)
+ 	goto restart;
+ 
+       cris_output_addr_const (file, XEXP (x, 0));
+       fprintf (file, "-");
+       if ((GET_CODE (XEXP (x, 1)) == CONST_INT
+ 	   && INTVAL (XEXP (x, 1)) < 0)
+ 	  || GET_CODE (XEXP (x, 1)) != CONST_INT)
+ 	{
+ 	  fprintf (file, "%s", targetm.asm_out.open_paren);
+ 	  cris_output_addr_const (file, XEXP (x, 1));
+ 	  fprintf (file, "%s", targetm.asm_out.close_paren);
+ 	}
+       else
+ 	output_addr_const (file, XEXP (x, 1));
+       break;
+ 
+     default:
+       fatal_insn ("Unexpected address expression", x);
+     }
+ }
+ 
+ /* The ENCODE_SECTION_INFO worker.  Code-in whether we can get away
+    without a GOT entry (needed for externally visible objects but not for
+    functions) into SYMBOL_REF_FLAG and add the PLT suffix for global
+    functions.  */
+ 
+ void
+ cris_encode_section_info (exp)
+      tree exp;
+ {
+   if (flag_pic)
+     {
+       if (DECL_P (exp))
+ 	{
+ 	  if (TREE_CODE (exp) == FUNCTION_DECL
+ 	      && (TREE_PUBLIC (exp) || DECL_WEAK (exp)))
+ 	    SYMBOL_REF_FLAG (XEXP (DECL_RTL (exp), 0)) = 0;
+ 	  else
+ 	    SYMBOL_REF_FLAG (XEXP (DECL_RTL (exp), 0))
+ 	      = ! TREE_PUBLIC (exp) && ! DECL_WEAK (exp);
+ 	}
+       else
+ 	/* Others are local entities.  */
+ 	SYMBOL_REF_FLAG (XEXP (TREE_CST_RTL (exp), 0)) = 1;
+     }
+ }
+ 
+ #if 0
+ /* Various small functions to replace macros.  Only called from a
+    debugger.  They might collide with gcc functions or system functions,
+    so only emit them when '#if 1' above.  */
+ 
+ enum rtx_code Get_code PARAMS ((rtx));
+ 
+ enum rtx_code
+ Get_code (x)
+      rtx x;
+ {
+   return GET_CODE (x);
+ }
+ 
+ const char *Get_mode PARAMS ((rtx));
+ 
+ const char *
+ Get_mode (x)
+      rtx x;
+ {
+   return GET_MODE_NAME (GET_MODE (x));
+ }
+ 
+ rtx Xexp PARAMS ((rtx, int));
+ 
+ rtx
+ Xexp (x, n)
+      rtx x;
+      int n;
+ {
+   return XEXP (x, n);
+ }
+ 
+ rtx Xvecexp PARAMS ((rtx, int, int));
+ 
+ rtx
+ Xvecexp (x, n, m)
+      rtx x;
+      int n;
+ { 
+   return XVECEXP (x, n, m);
+ }
+ 
+ int Get_rtx_len PARAMS ((rtx));
+ 
+ int
+ Get_rtx_len (x)
+      rtx x;
+ {
+   return GET_RTX_LENGTH (GET_CODE (x));
+ }
+ 
+ /* Use upper-case to distinguish from local variables that are sometimes
+    called next_insn and prev_insn.  */
+ 
+ rtx Next_insn PARAMS ((rtx));
+ 
+ rtx
+ Next_insn (insn)
+      rtx insn;
+ {
+   return NEXT_INSN (insn);
+ }
+ 
+ rtx Prev_insn PARAMS ((rtx));
+ 
+ rtx
+ Prev_insn (insn)
+      rtx insn;
+ {
+   return PREV_INSN (insn);
+ }
+ #endif
+ 
+ /*
+  * Local variables:
+  * eval: (c-set-style "gnu")
+  * indent-tabs-mode: t
+  * End:
+  */
diff -cprN nothing/cris.h cris/cris.h
*** nothing/cris.h	Thu Jan  1 01:00:00 1970
--- cris/cris.h	Thu Sep 27 05:27:00 2001
***************
*** 0 ****
--- 1,1937 ----
+ /* Definitions for GCC.  Part of the machine description for CRIS.
+    Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+    Contributed by Axis Communications.  Written by Hans-Peter Nilsson.
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING.  If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+ 
+ /* After the first "Node:" comment comes all preprocessor directives and
+    attached declarations described in the info files, the "Using and
+    Porting GCC" manual (uapgcc), in the same order as found in the "Target
+    macros" section in the gcc-2.9x CVS edition of 2000-03-17.  FIXME: Not
+    really, but needs an update anyway.
+ 
+    There is no generic copy-of-uapgcc comment, you'll have to see uapgcc
+    for that.  If applicable, there is a CRIS-specific comment.  The order
+    of macro definitions follow the order in the manual.  Every section in
+    the manual (node in the info pages) has an introductory `Node:
+    <subchapter>' comment.  If no macros are defined for a section, only
+    the section-comment is present.  */
+ 
+ /* Note that other header files (e.g. config/elfos.h, config/linux.h,
+    config/cris/linux.h and config/cris/aout.h) are responsible for lots of
+    settings not repeated below.  This file contains general CRIS
+    definitions and definitions for the cris-*-elf subtarget.  */
+ 
+ /* Replacement for REG_P since it does not match SUBREGs.  Happens for
+    testcase Axis-20000320 with gcc-2.9x.  */
+ #define REG_S_P(x) \
+  (REG_P (x) || (GET_CODE (x) == SUBREG && REG_P (XEXP (x, 0))))
+ 
+ /* Last register in main register bank r0..r15.  */
+ #define CRIS_LAST_GENERAL_REGISTER 15
+ 
+ /* Descriptions of registers used for arguments.  */
+ #define CRIS_FIRST_ARG_REG 10
+ #define CRIS_MAX_ARGS_IN_REGS 4
+ 
+ /* Other convenience definitions.  */
+ #define CRIS_PC_REGNUM 15
+ #define CRIS_SRP_REGNUM 16
+ 
+ /* Most of the time, we need the index into the register-names array.
+    When passing debug-info, we need the real register number.  */
+ #define CRIS_CANONICAL_SRP_REGNUM (16 + 11)
+ #define CRIS_CANONICAL_MOF_REGNUM (16 + 7)
+ 
+ /* When generating PIC, these suffixes are added to the names of non-local
+    functions when being output.  Contrary to other ports, we have offsets
+    relative to the GOT, not the PC.  We might implement PC-relative PLT
+    semantics later for the general case; they are used in some cases right
+    now, such as MI thunks.  */
+ #define CRIS_GOTPLT_SUFFIX ":GOTPLT"
+ #define CRIS_PLT_GOTOFFSET_SUFFIX ":PLTG"
+ #define CRIS_PLT_PCOFFSET_SUFFIX ":PLT"
+ 
+ #define CRIS_FUNCTION_ARG_SIZE(MODE, TYPE)	\
+   ((MODE) != BLKmode ? GET_MODE_SIZE (MODE)	\
+    : (unsigned) int_size_in_bytes (TYPE))
+ 
+ /* Check for max allowed stackframe. A "const char *" to be parsed.  */
+ extern const char *cris_max_stackframe_str;
+ 
+ /* Which CPU version this is.  A "const char *" to be parsed.  */
+ extern const char *cris_cpu_str;
+ 
+ /* Which CPU version this is.  The parsed and adjusted cris_cpu_str.  */
+ extern int cris_cpu_version;
+ 
+ /* Which CPU version to tune for.  A "const char *" to be parsed.  */
+ extern const char *cris_tune_str;
+ 
+ /* The argument to "-melinux-stacksize=".  We don't parse it currently;
+    it's just passed on to the linker.  We might want to do something
+    here someday.  */
+ extern const char *cris_elinux_stacksize_str;
+ 
+ /* Changing the order used to be necessary to put the fourth __make_dp
+    argument (a DImode parameter) in registers, to fit with the libfunc
+    parameter passing scheme used for intrinsic functions.  FIXME: Check
+    performance and maybe remove definition from TARGET_LIBGCC2_CFLAGS now
+    that it isn't strictly necessary.  We used to do this through
+    TARGET_LIBGCC2_CFLAGS, but that became increasingly difficult as the
+    parenthesis (that needed quoting) travels through several layers of
+    make and shell invocations.  */
+ #ifdef IN_LIBGCC2
+ #define __make_dp(a,b,c,d) __cris_make_dp(d,a,b,c)
+ #endif
+ 
+ 
+ /* Node: Driver */
+ 
+ /* When using make with defaults.mak for Sun this will handily remove
+    any "-target sun*" switches.  */
+ /* We need to override any previous definitions (linux.h) */
+ #undef WORD_SWITCH_TAKES_ARG
+ #define WORD_SWITCH_TAKES_ARG(STR)		\
+  (DEFAULT_WORD_SWITCH_TAKES_ARG (STR)		\
+   || !strcmp (STR, "target"))
+ 
+ /* Also provide canonical vN definitions when user specifies an alias.
+    Note that -melf overrides -maout.  */
+ 
+ /* The `-$' is here mostly due to the integrated preprocessor not
+    handling the builtin expansion of "#define __REGISTER_PREFIX__ $"
+    gracefully.  This is slightly redundant although not incorrect.
+    We're quite alone defining REGISTER_PREFIX as "$" so it's unlikely
+    someone will fight for us.  This year in the mountains.
+    Note that for -melinux and -mlinux, command-line -isystem options are
+    emitted both before and after the synthesized one.  We can't remove all
+    of them: a %{<isystem} will only remove the first one and %{<isystem*}
+    will not do TRT.  Those extra occurences are harmless anyway.  */
+ #define CPP_SPEC \
+  "-$ -D__CRIS_ABI_version=2\
+   %{mtune=*:-D__tune_%* %{mtune=v*:-D__CRIS_arch_tune=%*}}\
+    %{mtune=etrax4:-D__tune_v3 -D__CRIS_arch_tune=3}\
+    %{mtune=etrax100:-D__tune_v8 -D__CRIS_arch_tune=8}\
+    %{mtune=svinto:-D__tune_v8 -D__CRIS_arch_tune=8}\
+    %{mtune=etrax100lx:-D__tune_v10 -D__CRIS_arch_tune=10}\
+    %{mtune=ng:-D__tune_v10 -D__CRIS_arch_tune=10}\
+   %{mcpu=*:-D__arch_%* %{mcpu=v*:-D__CRIS_arch_version=%*}}\
+    %{mcpu=etrax4:-D__arch_v3 -D__CRIS_arch_version=3}\
+    %{mcpu=etrax100:-D__arch_v8 -D__CRIS_arch_version=8}\
+    %{mcpu=svinto:-D__arch_v8 -D__CRIS_arch_version=8}\
+    %{mcpu=etrax100lx:-D__arch_v10 -D__CRIS_arch_version=10}\
+    %{mcpu=ng:-D__arch_v10 -D__CRIS_arch_version=10}\
+   %{march=*:-D__arch_%* %{march=v*:-D__CRIS_arch_version=%*}}\
+    %{march=etrax4:-D__arch_v3 -D__CRIS_arch_version=3}\
+    %{march=etrax100:-D__arch_v8 -D__CRIS_arch_version=8}\
+    %{march=svinto:-D__arch_v8 -D__CRIS_arch_version=8}\
+    %{march=etrax100lx:-D__arch_v10 -D__CRIS_arch_version=10}\
+    %{march=ng:-D__arch_v10 -D__CRIS_arch_version=10}\
+   %{metrax100:-D__arch__v8 -D__CRIS_arch_version=8}\
+   %{metrax4:-D__arch__v3 -D__CRIS_arch_version=3}\
+   %(cpp_subtarget)"
+ 
+ /* For the cris-*-elf subtarget.  */
+ #define CRIS_CPP_SUBTARGET_SPEC \
+  "-D__ELF__\
+   %{mbest-lib-options:\
+    %{!moverride-best-lib-options:\
+     %{!march=*:%{!metrax*:%{!mcpu=*:-D__tune_v10 -D__CRIS_arch_tune=10}}}}}"
+ 
+ /* Remove those Sun-make "target" switches.  */
+ /* Override previous definitions (linux.h).  */
+ #undef CC1_SPEC
+ #define CC1_SPEC \
+  "%{target*:}\
+   %{metrax4:-march=v3}\
+   %{metrax100:-march=v8}\
+   %(cc1_subtarget)"
+ 
+ /* For the cris-*-elf subtarget.  */
+ #define CRIS_CC1_SUBTARGET_SPEC \
+  "-melf\
+   %{mbest-lib-options:\
+    %{!moverride-best-lib-options:\
+     %{!march=*:%{!mcpu=*:-mtune=v10 -D__CRIS_arch_tune=10}}\
+     %{!finhibit-size-directive:\
+       %{!fno-function-sections: -ffunction-sections}\
+       %{!fno-data-sections: -fdata-sections}}}}"
+ 
+ /* This adds to CC1_SPEC.  When bugs are removed from -fvtable-gc
+    (-fforce-addr causes invalid .vtable_entry asm in tinfo.cc and
+    nothing at all works in GCC 3.0-pre), add this line:
+    "%{mbest-lib-options:%{!moverride-best-lib-options:\
+    %{!melinux:%{!maout|melf:%{!fno-vtable-gc:-fvtable-gc}}}}}".  */
+ #define CC1PLUS_SPEC ""
+ 
+ /* Override previous definitions (linux.h).  */
+ #undef ASM_SPEC
+ #define ASM_SPEC \
+  "%{v:-v}\
+   %(asm_subtarget)"
+ 
+ /* For the cris-*-elf subtarget.  */
+ #define CRIS_ASM_SUBTARGET_SPEC "--em=criself"
+ 
+ /* FIXME: We should propagate the -melf option to make the criself
+    "emulation" unless a linker script is provided (-T*), but I don't know
+    how to do that if either of -Ttext, -Tdata or -Tbss is given but no
+    linker script, as is usually the case.  Leave it to the user for the
+    time being.
+ 
+    Note that -melf overrides -maout except that a.out-compiled libraries
+    are linked in (multilibbing).  The somewhat cryptic -rpath-link pair is
+    to avoid *only* picking up the linux multilib subdir from the "-B./"
+    option during build, while still giving it preference.  We'd need some
+    %s-variant that checked for existance of some specific file.  */
+ /* Override previous definitions (svr4.h).  */
+ #undef LINK_SPEC
+ #define LINK_SPEC \
+  "%{v:--verbose}\
+   %(link_subtarget)" 
+ 
+ /* For the cris-*-elf subtarget.  */
+ #define CRIS_LINK_SUBTARGET_SPEC \
+  "-mcriself\
+   %{sim2:%{!T*:-Tdata 0x4000000 -Tbss 0x8000000}}\
+   %{O2|O3: --gc-sections}"
+ 
+ /* Which library to get.  The only difference from the default is to get
+    libsc.a if -sim is given to the driver.  Repeat -lc -lsysX
+    {X=sim,linux}, because libsysX needs (at least) errno from libc, and
+    then we want to resolve new unknowns in libc against libsysX, not
+    libnosys.  */
+ /* Override previous definitions (linux.h).  */
+ #undef LIB_SPEC
+ #define LIB_SPEC \
+  "%{sim*:-lc -lsyssim -lc -lsyssim}\
+   %{!sim*:%{g*:-lg}\
+     %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} -lbsp}\
+   -lnosys"
+ 
+ /* Linker startfile options; crt0 flavors.
+ 
+    At the moment there are no gcrt0.o or mcrt0.o, but keep them here and
+    link them to crt0.o to be prepared.  Use scrt0.c if running the
+    simulator, linear style, or s2crt0.c if fixed style.  */
+ /* We need to remove any previous definition (elfos.h).  */
+ #undef STARTFILE_SPEC
+ #define STARTFILE_SPEC \
+  "%{sim2:s2crt0.o%s}\
+   %{!sim2:%{sim:scrt0.o%s}\
+    %{!sim:%{pg:gcrt0.o%s}\
+     %{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}}\
+   crtbegin.o%s"
+ 
+ #define EXTRA_SPECS				\
+   {"cpp_subtarget", CRIS_CPP_SUBTARGET_SPEC},	\
+   {"cc1_subtarget", CRIS_CC1_SUBTARGET_SPEC},	\
+   {"asm_subtarget", CRIS_ASM_SUBTARGET_SPEC},	\
+   {"link_subtarget", CRIS_LINK_SUBTARGET_SPEC},	\
+   CRIS_SUBTARGET_EXTRA_SPECS
+ 
+ #define CRIS_SUBTARGET_EXTRA_SPECS
+ 
+ 
+ /* Node: Run-time Target */
+ 
+ /* Only keep the non-varying ones here.  */
+ #define CPP_PREDEFINES	"-Dcris -DCRIS -DGNU_CRIS"
+ 
+ /* This needs to be at least 32 bits.  */
+ extern int target_flags;
+ 
+ /* Currently this just affects aligment.  FIXME:  Redundant with
+    TARGET_ALIGN_BY_32, or put machine stuff here?  */
+ #define TARGET_MASK_SVINTO 1
+ #define TARGET_SVINTO (target_flags & TARGET_MASK_SVINTO)
+ 
+ /* If to use condition-codes generated by insns other than the
+    immediately preceding compare/test insn.
+     Used to check for errors in notice_update_cc. */
+ #define TARGET_MASK_CCINIT 2
+ #define TARGET_CCINIT (target_flags & TARGET_MASK_CCINIT)
+ 
+ /* Debug option.  */
+ #define TARGET_MASK_PDEBUG 4
+ #define TARGET_PDEBUG (target_flags & TARGET_MASK_PDEBUG)
+ 
+ /* If to use side-effect patterns.  Used to debug the [rx=ry+i] type
+    patterns.  */
+ #define TARGET_MASK_SIDE_EFFECT_PREFIXES 8
+ #define TARGET_SIDE_EFFECT_PREFIXES \
+  (target_flags & TARGET_MASK_SIDE_EFFECT_PREFIXES)
+ 
+ /* If to expand mul into mstep.  Only used when making libc.a.  */
+ #define TARGET_MASK_EXPAND_MUL 16
+ #define TARGET_EXPAND_MUL (target_flags & TARGET_MASK_EXPAND_MUL)
+ 
+ /* If to *keep* (not force) alignment of stack at 16 bits.  */
+ #define TARGET_MASK_STACK_ALIGN 32
+ #define TARGET_STACK_ALIGN (target_flags & TARGET_MASK_STACK_ALIGN)
+ 
+ /* If to do alignment on individual non-modifiable objects.  */
+ #define TARGET_MASK_CONST_ALIGN 64
+ #define TARGET_CONST_ALIGN (target_flags & TARGET_MASK_CONST_ALIGN)
+ 
+ /* If to do alignment on individual modifiable objects.  */
+ #define TARGET_MASK_DATA_ALIGN 128
+ #define TARGET_DATA_ALIGN (target_flags & TARGET_MASK_DATA_ALIGN)
+ 
+ /* If not to omit funtion prologue and epilogue.  */
+ #define TARGET_MASK_PROLOGUE_EPILOGUE 256
+ #define TARGET_PROLOGUE_EPILOGUE (target_flags & TARGET_MASK_PROLOGUE_EPILOGUE)
+ 
+ /* Instructions additions from Etrax 4 and up.
+    (Just "lz", which we don't really generate from GCC -- yet).  */
+ #define TARGET_MASK_ETRAX4_ADD 512
+ #define TARGET_ETRAX4_ADD (target_flags & TARGET_MASK_ETRAX4_ADD)
+ 
+ /* Say that all alignment specifications say to prefer 32 rather
+    than 16 bits.  */
+ #define TARGET_MASK_ALIGN_BY_32 1024
+ #define TARGET_ALIGN_BY_32 (target_flags & TARGET_MASK_ALIGN_BY_32)
+ 
+ /* This condition is of limited use, as gcc is riddled with #ifdef:s
+    controlling this, rather than if (...):s.  */
+ #define TARGET_MASK_ELF 2048
+ #define TARGET_ELF (target_flags & TARGET_MASK_ELF)
+ 
+ /* Currently just used to error-check other options.  Note that this is
+    *not* set for -melinux.  */
+ #define TARGET_MASK_LINUX 4096
+ #define TARGET_LINUX (target_flags & TARGET_MASK_LINUX)
+ 
+ /* There's a small setup cost with using GOTPLT references, but should
+    in total be a win both in code-size and execution-time.  */
+ #define TARGET_MASK_AVOID_GOTPLT 8192
+ #define TARGET_AVOID_GOTPLT (target_flags & TARGET_MASK_AVOID_GOTPLT)
+ 
+ #define TARGET_SWITCHES							\
+  {									\
+   /* No "no-etrax" as it does not really imply any model.		\
+      On the other hand, "etrax" implies the common (and large)		\
+      subset matching all models.  */					\
+   {"etrax4",				 TARGET_MASK_ETRAX4_ADD,	\
+    N_("Compile for ETRAX 4 (CRIS v3)")},				\
+   {"no-etrax4",				-TARGET_MASK_ETRAX4_ADD, ""},	\
+   {"etrax100",			     (TARGET_MASK_SVINTO		\
+ 				      + TARGET_MASK_ETRAX4_ADD		\
+ 				      + TARGET_MASK_ALIGN_BY_32),	\
+    N_("Compile for ETRAX 100 (CRIS v8)")},				\
+   {"no-etrax100",		    -(TARGET_MASK_SVINTO		\
+ 				      + TARGET_MASK_ETRAX4_ADD), ""},	\
+   {"pdebug",				     TARGET_MASK_PDEBUG,	\
+    N_("Emit verbose debug information in assembly code")},		\
+   {"no-pdebug",				    -TARGET_MASK_PDEBUG, ""},	\
+   {"cc-init",				     TARGET_MASK_CCINIT,	\
+    N_("Do not use condition codes from normal instructions")},		\
+   {"no-cc-init",			    -TARGET_MASK_CCINIT, ""},	\
+   {"side-effects",	       TARGET_MASK_SIDE_EFFECT_PREFIXES, ""},	\
+   {"no-side-effects",	      -TARGET_MASK_SIDE_EFFECT_PREFIXES,	\
+    N_("Do not emit addressing modes with side-effect assignment")},	\
+   {"stack-align",			TARGET_MASK_STACK_ALIGN, ""},	\
+   {"no-stack-align",		       -TARGET_MASK_STACK_ALIGN,	\
+    N_("Do not tune stack alignment")},					\
+   {"data-align",			 TARGET_MASK_DATA_ALIGN, ""},	\
+   {"no-data-align",			-TARGET_MASK_DATA_ALIGN,	\
+    N_("Do not tune writable data alignment")},				\
+   {"const-align",			TARGET_MASK_CONST_ALIGN, ""},	\
+   {"no-const-align",		       -TARGET_MASK_CONST_ALIGN,	\
+    N_("Do not tune code and read-only data alignment")},		\
+   {"32-bit",			    (TARGET_MASK_STACK_ALIGN		\
+ 				     + TARGET_MASK_CONST_ALIGN		\
+ 				     + TARGET_MASK_DATA_ALIGN		\
+ 				     + TARGET_MASK_ALIGN_BY_32), ""},	\
+   {"32bit",			    (TARGET_MASK_STACK_ALIGN		\
+ 				     + TARGET_MASK_CONST_ALIGN		\
+ 				     + TARGET_MASK_DATA_ALIGN		\
+ 				     + TARGET_MASK_ALIGN_BY_32),	\
+    N_("Align code and data to 32 bits")},				\
+   {"16-bit",			     (TARGET_MASK_STACK_ALIGN		\
+ 				      + TARGET_MASK_CONST_ALIGN		\
+ 				      + TARGET_MASK_DATA_ALIGN), ""},	\
+   {"16bit",			     (TARGET_MASK_STACK_ALIGN		\
+ 				      + TARGET_MASK_CONST_ALIGN		\
+ 				      + TARGET_MASK_DATA_ALIGN), ""},	\
+   {"8-bit",			    -(TARGET_MASK_STACK_ALIGN		\
+ 				      + TARGET_MASK_CONST_ALIGN		\
+ 				      + TARGET_MASK_DATA_ALIGN), ""},	\
+   {"8bit",			    -(TARGET_MASK_STACK_ALIGN		\
+ 				      + TARGET_MASK_CONST_ALIGN		\
+ 				      + TARGET_MASK_DATA_ALIGN),	\
+    N_("Don't align items in code or data")},				\
+   {"prologue-epilogue",		  TARGET_MASK_PROLOGUE_EPILOGUE, ""},	\
+   {"no-prologue-epilogue",	 -TARGET_MASK_PROLOGUE_EPILOGUE,	\
+    N_("Do not emit function prologue or epilogue")},			\
+   /* We have to handle this m-option here since we can't wash it off in \
+      both CC1_SPEC and CC1PLUS_SPEC.  */				\
+   {"best-lib-options",					      0,	\
+  N_("Use the most feature-enabling options allowed by other options")},	\
+ 									\
+   /* We must call it "override-" since calling it "no-" will cause	\
+      gcc.c to forget it, if there's a "later" -mbest-lib-options.	\
+      Kludgy, but needed for some multilibbed files.  */			\
+   {"override-best-lib-options",				      0,	\
+    N_("Override -mbest-lib-options")},					\
+   CRIS_SUBTARGET_SWITCHES						\
+   {"",			TARGET_DEFAULT | CRIS_SUBTARGET_DEFAULT, ""}}	\
+ 
+ /* For the cris-*-elf subtarget.  */
+ #define CRIS_SUBTARGET_SWITCHES \
+  {"elf", 0, ""},
+ 
+ /* Default target_flags if no switches specified.  */
+ #ifndef TARGET_DEFAULT
+ # define TARGET_DEFAULT \
+  (TARGET_MASK_SIDE_EFFECT_PREFIXES + TARGET_MASK_STACK_ALIGN \
+   + TARGET_MASK_CONST_ALIGN + TARGET_MASK_DATA_ALIGN \
+   + TARGET_MASK_PROLOGUE_EPILOGUE)
+ #endif
+ 
+ /* For the cris-*-elf subtarget.  */
+ #define CRIS_SUBTARGET_DEFAULT TARGET_MASK_ELF
+ 
+ #define CRIS_CPU_BASE 0
+ #define CRIS_CPU_ETRAX4 3	/* Just lz added.  */
+ #define CRIS_CPU_SVINTO 8	/* Added swap, jsrc & Co., 32-bit accesses.  */
+ #define CRIS_CPU_NG 10		/* Added mul[su].  */
+ 
+ /* Local, providing a default for cris_cpu_version.  */
+ #define CRIS_DEFAULT_CPU_VERSION CRIS_CPU_BASE
+ 
+ #define TARGET_HAS_MUL_INSNS (cris_cpu_version >= CRIS_CPU_NG)
+ 
+ #define TARGET_OPTIONS							\
+  {{"cpu=", &cris_cpu_str, ""},						\
+   {"arch=", &cris_cpu_str,						\
+    N_("Generate code for the specified chip or CPU version")},		\
+   {"tune=", &cris_tune_str,						\
+    N_("Tune alignment for the specified chip or CPU version")},		\
+   {"max-stackframe=", &cris_max_stackframe_str,				\
+    N_("Warn when a stackframe is larger than the specified size")},	\
+   CRIS_SUBTARGET_LONG_OPTIONS						\
+   {"ax-stackframe=", &cris_max_stackframe_str, ""}}
+ 
+ #define CRIS_SUBTARGET_LONG_OPTIONS
+ 
+ /* Print subsidiary information on the compiler version in use.
+    Do not use VD.D syntax (D=digit), since this will cause confusion
+    with the base gcc version among users, when we ask which version of
+    gcc-cris they are using.  Please use some flavor of "R<number>" for
+    the version (no need for major.minor versions, I believe).  */
+ #define TARGET_VERSION \
+  fprintf (stderr, " [Axis CRIS release R36a%s]", CRIS_SUBTARGET_VERSION)
+ 
+ /* For the cris-*-elf subtarget.  */
+ #define CRIS_SUBTARGET_VERSION " - generic ELF"
+ 
+ #define OVERRIDE_OPTIONS cris_override_options ()
+ 
+ /* The following gives optimal code for gcc-2.7.2, but *may* be subject
+    to change.  Omitting flag_force_addr gives .1-.7% faster code for gcc
+    *only*, but 1.3% larger code.  On ipps it gives 5.3-10.6% slower
+    code(!) and 0.3% larger code.  For products, images gets .1-1.8%
+    larger.  Do not set strict aliasing from optimization options.  */
+ #define OPTIMIZATION_OPTIONS(OPTIMIZE, SIZE)	\
+   do						\
+     {						\
+       if ((OPTIMIZE) >= 2 || (SIZE))		\
+ 	{					\
+ 	  flag_force_addr =			\
+ 	    flag_omit_frame_pointer = 1;	\
+ 	}					\
+       flag_strict_aliasing = 0;			\
+     }						\
+   while (0)
+ 
+ 
+ /* Node: Storage Layout */
+ 
+ #define BITS_BIG_ENDIAN 0
+ 
+ #define BYTES_BIG_ENDIAN 0
+ 
+ /* WORDS_BIG_ENDIAN is not defined in the hardware, but for consistency,
+    we use little-endianness, and we may also be able to use
+    post-increment on DImode indirect.  */
+ #define WORDS_BIG_ENDIAN 0
+ 
+ #define BITS_PER_UNIT 8
+ 
+ #define BITS_PER_WORD 32
+ 
+ #define UNITS_PER_WORD 4
+ 
+ #define POINTER_SIZE 32
+ 
+ /* A combination of defining PROMOTE_MODE, PROMOTE_FUNCTION_ARGS,
+    PROMOTE_FOR_CALL_ONLY and *not* defining PROMOTE_PROTOTYPES gives the
+    best code size and speed for gcc, ipps and products in gcc-2.7.2.  */
+ #define CRIS_PROMOTED_MODE(MODE, UNSIGNEDP, TYPE) \
+  (GET_MODE_CLASS (MODE) == MODE_INT && GET_MODE_SIZE (MODE) < 4) \
+   ? SImode : MODE
+ 
+ #define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE)  \
+   (MODE) = CRIS_PROMOTED_MODE (MODE, UNSIGNEDP, TYPE)
+ 
+ #define PROMOTE_FUNCTION_ARGS
+ 
+ /* Defining PROMOTE_FUNCTION_RETURN in gcc-2.7.2 uncovers bug 981110 (even
+    if defining FUNCTION_VALUE with MODE as PROMOTED_MODE ;-)
+ 
+    FIXME: Report this when cris.h is part of GCC, so others can easily
+    see the problem.  Maybe check other systems that define
+    PROMOTE_FUNCTION_RETURN.  */
+ #define PROMOTE_FOR_CALL_ONLY
+ 
+ /* We will be using prototype promotion, so they will be 32 bit.  */
+ #define PARM_BOUNDARY 32
+ 
+ /* Stack boundary is guided by -mstack-align, -mno-stack-align,
+    -malign.
+    Old comment: (2.1: still valid in 2.7.2?)
+     Note that to make this macro affect the alignment of stack
+    locals, a fix was required, and special precautions when handling
+    the stack pointer in various other macros (FUNCTION_PROLOGUE et al)
+    were required.  See file "function.c".  If you would just define
+    this macro, it would only affect the builtin alloca and variable
+    local data (non-ANSI, non-K&R, Gnu C extension).  */
+ #define STACK_BOUNDARY \
+  (TARGET_STACK_ALIGN ? (TARGET_ALIGN_BY_32 ? 32 : 16) : 8)
+ 
+ #define FUNCTION_BOUNDARY 16
+ 
+ /* Do not change BIGGEST_ALIGNMENT (when optimizing), as it will affect
+    strange places, at least in 2.1. */
+ #define BIGGEST_ALIGNMENT 8
+ 
+ /* If -m16bit,	-m16-bit, -malign or -mdata-align,
+    align everything to 16 bit. */
+ #define DATA_ALIGNMENT(TYPE, BASIC_ALIGN)			\
+  (TARGET_DATA_ALIGN						\
+   ? (TARGET_ALIGN_BY_32						\
+      ? (BASIC_ALIGN < 32 ? 32 : BASIC_ALIGN)			\
+      : (BASIC_ALIGN < 16 ? 16 : BASIC_ALIGN)) : BASIC_ALIGN)
+ 
+ /* Note that CONSTANT_ALIGNMENT has the effect of making gcc believe that
+    ALL references to constant stuff (in code segment, like strings) has
+    this alignment.  That is a rather rushed assumption.  Luckily we do not
+    care about the "alignment" operand to builtin memcpy (only place where
+    it counts), so it doesn't affect any bad spots.  */
+ #define CONSTANT_ALIGNMENT(CONSTANT, BASIC_ALIGN)		\
+  (TARGET_CONST_ALIGN						\
+   ? (TARGET_ALIGN_BY_32						\
+      ? (BASIC_ALIGN < 32 ? 32 : BASIC_ALIGN)			\
+      : (BASIC_ALIGN < 16 ? 16 : BASIC_ALIGN)) : BASIC_ALIGN)
+ 
+ /* FIXME: Define LOCAL_ALIGNMENT for word and dword or arrays and
+    structures (if -mstack-align=), and check that it is good.  */
+ 
+ #define EMPTY_FIELD_BOUNDARY 8
+ 
+ #define STRUCTURE_SIZE_BOUNDARY 8
+ 
+ #define STRICT_ALIGNMENT 0
+ 
+ /* Remove any previous definition (elfos.h).
+    ??? If it wasn't for all the other stuff that affects layout of
+    structures and bit-fields, this could presumably cause incompatibility
+    with other GNU/Linux ports (i.e. elfos.h users).  */
+ #undef PCC_BITFIELD_TYPE_MATTERS
+ 
+ /* This is only used for non-scalars.  Strange stuff happens to structs
+    (FIXME: What?) if we use anything larger than largest actually used
+    datum size, so lets make it 32.  The type "long long" will still work
+    as usual.  We can still have DImode insns, but they will only be used
+    for scalar data (i.e. long long).  */
+ #define MAX_FIXED_MODE_SIZE 32
+ 
+ 
+ /* Node: Type Layout */
+ 
+ /* Note that DOUBLE_TYPE_SIZE is not defined anymore, since the default
+    value gives a 64-bit double, which is what we now use.  */
+ 
+ /* For compatibility and historical reasons, a char should be signed.  */
+ #define DEFAULT_SIGNED_CHAR 1
+ 
+ /* No DEFAULT_SHORT_ENUMS, please.  */
+ 
+ /* Note that WCHAR_TYPE_SIZE is used in cexp.y,
+    where TARGET_SHORT is not available.  */
+ #undef WCHAR_TYPE
+ #define WCHAR_TYPE "long int"
+ 
+ #undef WCHAR_TYPE_SIZE
+ #define WCHAR_TYPE_SIZE 32
+ 
+ 
+ /* Node: Register Basics */
+ 
+ /*  We count all 16 non-special registers, SRP and a faked argument
+     pointer register.  */
+ #define FIRST_PSEUDO_REGISTER (16 + 1 + 1)
+ 
+ /* For CRIS, these are r15 (pc) and r14 (sp). Register r8 is used as a
+    frame-pointer, but is not fixed.  SRP is not included in general
+    registers and will not be used automatically.  All other special
+    registers are fixed at the moment.  The faked argument pointer register
+    is fixed too.  */
+ #define FIXED_REGISTERS \
+  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1}
+ 
+ /* Register r9 is used for structure-address, r10-r13 for parameters,
+    r10- for return values.  */
+ #define CALL_USED_REGISTERS \
+  {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1}
+ 
+ #define CONDITIONAL_REGISTER_USAGE cris_conditional_register_usage ()
+ 
+ 
+ /* Node: Allocation Order */
+ 
+ /* We need this on CRIS, because call-used regs should be used first,
+    (so we dont need to push).  Else start using registers from r0 and up.
+     This preference is mainly because if we put call-used-regs from r0
+    and up, then we can't use movem to push the rest, (which have to be
+    saved if we use them, and movem has to start with r0).
+    Change here if you change which registers to use as call registers.
+ 
+    The actual need to explicitly prefer call-used registers improved the
+    situation a lot for 2.1, but might not actually be needed anymore.
+    Still, this order reflects what GCC should find out by itself, so it
+    probably does not hurt.
+ 
+    Order of preference: Call-used-regs first, then r0 and up, last fp &
+    sp & pc as fillers.
+    Call-used regs in opposite order, so they will cause less conflict if
+    a function has few args (<= 3) and it wants a scratch reg.
+     Use struct-return address first, since very few functions use
+    structure return values so it is likely to be available.  */
+ #define REG_ALLOC_ORDER \
+  {9, 13, 12, 11, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15, 16, 17}
+ 
+ 
+ /* Node: Values in Registers */
+ 
+ /* The VOIDmode test is so we can omit mode on anonymous insns.  FIXME:
+    Still needed in 2.9x, at least for Axis-20000319.  */
+ #define HARD_REGNO_NREGS(REGNO, MODE)	\
+  (MODE == VOIDmode \
+   ? 1 : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+ 
+ /* CRIS permits all registers to hold all modes.  */
+ #define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+ 
+ #define MODES_TIEABLE_P(MODE1, MODE2)  1
+ 
+ 
+ /* Node: Leaf Functions */
+ /* (no definitions) */
+ 
+ /* Node: Stack Registers */
+ /* (no definitions) */
+ 
+ 
+ /* Node: Register Classes */
+ 
+ /* CRIS has only one kind of registers, so NO_REGS and ALL_REGS
+    are the only classes.  FIXME: It actually makes sense to have another
+    class for special registers, and yet another class for the
+    multiply-overflow register in v10; then a class for the return
+    register also makes sense.  */
+ enum reg_class {NO_REGS, ALL_REGS, LIM_REG_CLASSES};
+ 
+ #define N_REG_CLASSES (int) LIM_REG_CLASSES
+ 
+ #define REG_CLASS_NAMES {"NO_REGS", "ALL_REGS"}
+ 
+ #define GENERAL_REGS ALL_REGS
+ 
+ /* Count in the faked argument register in GENERAL_REGS.  Keep out SRP.  */
+ #define REG_CLASS_CONTENTS {{0}, {0x2ffff}}
+ 
+ #define REGNO_REG_CLASS(REGNO) GENERAL_REGS
+ 
+ #define BASE_REG_CLASS GENERAL_REGS
+ 
+ #define INDEX_REG_CLASS GENERAL_REGS
+ 
+ /* Get reg_class from a letter such as appears in the machine
+    description.  No letters are used, since 'r' is used for any
+    register.  */
+ #define REG_CLASS_FROM_LETTER(C) NO_REGS
+ 
+ /* Since it uses reg_renumber, it is safe only once reg_renumber
+    has been allocated, which happens in local-alloc.c.  */
+ #define REGNO_OK_FOR_BASE_P(REGNO)					\
+  ((REGNO) <= CRIS_LAST_GENERAL_REGISTER					\
+   || (REGNO) == ARG_POINTER_REGNUM					\
+   || (unsigned) reg_renumber[REGNO] <= CRIS_LAST_GENERAL_REGISTER	\
+   || (unsigned) reg_renumber[REGNO] == ARG_POINTER_REGNUM)
+ 
+ /* See REGNO_OK_FOR_BASE_P.  */
+ #define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO)
+ 
+ /* It seems like gcc (2.7.2 and 2.9x of 2000-03-22) may send "NO_REGS" as
+    the class for a constant (testcase: __Mul in arit.c).  To avoid forcing
+    out a constant into the constant pool, we will trap this case and
+    return something a bit more sane.  FIXME: Check if this is a bug.  */
+ #define PREFERRED_RELOAD_CLASS(X, CLASS) \
+  ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS))
+ 
+ /* For CRIS, this is always the size of MODE in words,
+    since all registers are the same size.  To use omitted modes in
+    patterns with reload constraints, you must say the widest size
+    which is allowed for VOIDmode.
+    FIXME:  Does that still apply for gcc-2.9x?  Keep poisoned until such
+    patterns are added back.  News: 2001-03-16: Happens as early as the
+    underscore-test.  */
+ #define CLASS_MAX_NREGS(CLASS, MODE)					\
+  ((MODE) == VOIDmode							\
+   ? 1 /* + cris_fatal ("CLASS_MAX_NREGS with VOIDmode")	*/		\
+   : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+ 
+ /* We are now out of letters; we could use ten more.  This forces us to
+    use C-code in the 'md' file.  FIXME: Use some EXTRA_CONSTRAINTS.  */
+ #define CONST_OK_FOR_LETTER_P(VALUE, C)			\
+  (							\
+   /* MOVEQ, CMPQ, ANDQ, ORQ.  */			\
+   (C) == 'I' ? (VALUE) >= -32 && (VALUE) <= 31 :	\
+   /* ADDQ, SUBQ.  */					\
+   (C) == 'J' ? (VALUE) >= 0 && (VALUE) <= 63 :		\
+   /* ASRQ, BTSTQ, LSRQ, LSLQ.  */			\
+   (C) == 'K' ? (VALUE) >= 0 && (VALUE) <= 31 :		\
+   /* A 16-bit signed number.  */			\
+   (C) == 'L' ? (VALUE) >= -32768 && (VALUE) <= 32767 :	\
+   /* The constant 0 for CLEAR.  */			\
+   (C) == 'M' ? (VALUE) == 0 :				\
+   /* A negative ADDQ or SUBQ.  */			\
+   (C) == 'N' ? (VALUE) >= -63 && (VALUE) < 0 :		\
+   /* Quickened ints, QI and HI.  */			\
+   (C) == 'O' ? (VALUE) >= 0 && (VALUE) <= 65535		\
+ 		&& ((VALUE) >= (65535-31)		\
+ 		    || ((VALUE) >= (255-31)		\
+ 			&& (VALUE) <= 255 )) :		\
+   /* A 16-bit number signed *or* unsigned.  */		\
+   (C) == 'P' ? (VALUE) >= -32768 && (VALUE) <= 65535 :	\
+   0)
+ 
+ /* It is really simple to make up a 0.0; it is the same as int-0 in
+    IEEE754. */
+ #define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C)			\
+  ((C) == 'G' && ((VALUE) == CONST0_RTX (DFmode)			\
+ 		 || (VALUE) == CONST0_RTX (SFmode)))
+ 
+ /* We need this on cris to distinguish delay-slottable addressing modes.  */
+ #define EXTRA_CONSTRAINT(X, C)			\
+  (						\
+   /* Slottable address mode?  */		\
+   (C) == 'Q' ? EXTRA_CONSTRAINT_Q (X) :		\
+   /* Operand to BDAP or BIAP?  */		\
+   (C) == 'R' ? EXTRA_CONSTRAINT_R (X) :		\
+   /* A local PIC symbol?  */			\
+   (C) == 'S' ? EXTRA_CONSTRAINT_S (X) :		\
+   /* A three-address addressing-mode?  */	\
+   (C) == 'T' ? EXTRA_CONSTRAINT_T (X) :		\
+   /* A global PIC symbol?  */			\
+   (C) == 'U' ? EXTRA_CONSTRAINT_U (X) :		\
+   0)
+ 
+ #define EXTRA_CONSTRAINT_Q(X)				\
+  (							\
+   /* Slottable addressing modes:			\
+      A register?  FIXME: Unnecessary.  */		\
+   (BASE_P (X) && REGNO (X) != CRIS_PC_REGNUM)		\
+   /* Indirect register: [reg]?  */			\
+   || (GET_CODE (X) == MEM && BASE_P (XEXP (X, 0))	\
+       && REGNO (XEXP (X, 0)) != CRIS_PC_REGNUM)		\
+  )
+ 
+ #define EXTRA_CONSTRAINT_R(X)					\
+  (								\
+   /* An operand to BDAP or BIAP:				\
+      A BIAP; r.S? */						\
+   BIAP_INDEX_P (X)						\
+   /* A [reg] or (int) [reg], maybe with post-increment.  */	\
+   || BDAP_INDEX_P (X)						\
+   || CONSTANT_INDEX_P (X)					\
+  )
+ 
+ /* FIXME: Bug below: We can't have XEXP (X, 0)) both be MEM and a
+    CONSTANT_P.  Parens don't match indentation.  */
+ 
+ #define EXTRA_CONSTRAINT_T(X)						\
+  (									\
+   /* Three-address-operands.  All are indirect-memory:  */		\
+   GET_CODE (X) == MEM							\
+   && ((GET_CODE (XEXP (X, 0)) == MEM					\
+   /* Double indirect: [[reg]] or [[reg+]]?  */				\
+   && (BASE_OR_AUTOINCR_P (XEXP (XEXP (X, 0), 0))))			\
+       /* Just an explicite indirect reference: [const]?  */		\
+       || CONSTANT_P (XEXP (X, 0))					\
+       /* Something that is indexed; [...+...]?  */			\
+       || (GET_CODE (XEXP (X, 0)) == PLUS				\
+ 	  /* A BDAP constant: [reg+(8|16|32)bit offset]?  */		\
+ 	  && ((BASE_P (XEXP (XEXP (X, 0), 0))				\
+ 	       && CONSTANT_INDEX_P (XEXP (XEXP (X, 0), 1)))		\
+ 	      /* Swap arguments to the above.  FIXME: gcc-2.9x? */	\
+ 	      || (BASE_P (XEXP (XEXP (X, 0), 1))			\
+ 		  && CONSTANT_INDEX_P (XEXP (XEXP (X, 0), 0)))		\
+ 	      /* A BDAP register: [reg+[reg(+)].S]?  */			\
+ 	      || (BASE_P (XEXP (XEXP (X, 0), 0))			\
+ 		  && BDAP_INDEX_P(XEXP(XEXP(X, 0), 1)))			\
+ 	      /* Same, but with swapped arguments.  */			\
+ 	      || (BASE_P (XEXP (XEXP (X, 0), 1))			\
+ 		  && BDAP_INDEX_P (XEXP (XEXP (X, 0), 0)))		\
+ 	      /* A BIAP: [reg+reg.S].  */				\
+ 	      || (BASE_P (XEXP (XEXP (X, 0), 0))			\
+ 		  && BIAP_INDEX_P (XEXP (XEXP (X, 0), 1)))		\
+ 	      /* Same, but with swapped arguments.  */			\
+ 	      || (BASE_P (XEXP (XEXP (X, 0), 1))			\
+ 		  && BIAP_INDEX_P (XEXP (XEXP (X, 0), 0))))))		\
+  )
+ 
+ #define EXTRA_CONSTRAINT_S(X) \
+  (flag_pic && CONSTANT_P (X) && cris_gotless_symbol (X))
+ 
+ #define EXTRA_CONSTRAINT_U(X) \
+  (flag_pic && CONSTANT_P (X) && cris_got_symbol (X))
+ 
+ 
+ /* Node: Frame Layout */
+ 
+ #define STACK_GROWS_DOWNWARD
+ #define FRAME_GROWS_DOWNWARD
+ 
+ /* It seems to be indicated in the code (at least 2.1) that this is
+    better a constant, and best 0.  */
+ #define STARTING_FRAME_OFFSET 0
+ 
+ #define FIRST_PARM_OFFSET(FNDECL) 0
+ 
+ #define RETURN_ADDR_RTX(COUNT, FRAMEADDR) \
+  cris_return_addr_rtx (COUNT, FRAMEADDR)
+ 
+ #define INCOMING_RETURN_ADDR_RTX gen_rtx (REG, Pmode, CRIS_SRP_REGNUM)
+ 
+ /* FIXME: Any __builtin_eh_return callers must not return anything and
+    there must not be collisions with incoming parameters.  Luckily the
+    number of __builtin_eh_return callers is limited.  For now return
+    parameter registers in reverse order and hope for the best.  */
+ #define EH_RETURN_DATA_REGNO(N) \
+   (((N) >= 0 && (N) < 4) ? (CRIS_FIRST_ARG_REG + 3 - (N)) : INVALID_REGNUM)
+ 
+ /* Store the stack adjustment in the structure-return-address register.  */
+ #define CRIS_STACKADJ_REG STRUCT_VALUE_REGNUM
+ #define EH_RETURN_STACKADJ_RTX gen_rtx_REG (SImode, CRIS_STACKADJ_REG)
+ 
+ #define EH_RETURN_HANDLER_RTX \
+   cris_return_addr_rtx (0, NULL)
+ 
+ #define INIT_EXPANDERS cris_init_expanders ()
+ 
+ /* FIXME: Move this to right node (it's not documented properly yet).  */
+ #define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (CRIS_SRP_REGNUM)
+ 
+ /* FIXME: Move this to right node (it's not documented properly yet).
+    FIXME: Check what alignment we can assume regarding
+    TARGET_STACK_ALIGN and TARGET_ALIGN_BY_32.  */
+ #define DWARF_CIE_DATA_ALIGNMENT -1
+ 
+ /* If we would ever need an exact mapping between canonical register
+    number and dwarf frame register, we would either need to include all
+    registers in the gcc decription (with some marked fixed of course), or
+    an inverse mapping from dwarf register to gcc register.  There is one
+    need in dwarf2out.c:expand_builtin_init_dwarf_reg_sizes.  Right now, I
+    don't see that we need exact correspondence between DWARF *frame*
+    registers and DBX_REGISTER_NUMBER, so map them onto GCC registers.  */
+ #define DWARF_FRAME_REGNUM(REG) (REG)
+ 
+ /* Node: Stack Checking */
+ /* (no definitions) FIXME: Check.  */
+ 
+ /* Node: Frame Registers */
+ 
+ #define STACK_POINTER_REGNUM 14
+ 
+ /* Register used for frame pointer.  This is also the last of the saved
+    registers, when a frame pointer is not used. */
+ #define FRAME_POINTER_REGNUM 8
+ 
+ /* Faked register, is always eliminated.  We need it to eliminate
+    allocating stack slots for the return address and the frame pointer.  */
+ #define ARG_POINTER_REGNUM 17
+ 
+ #define STATIC_CHAIN_REGNUM 7
+ 
+ 
+ /* Node: Elimination */
+ 
+ /* Really only needed if the stack frame has variable length (alloca
+    or variable sized local arguments (GNU C extension).  */
+ #define FRAME_POINTER_REQUIRED 0
+ 
+ #define ELIMINABLE_REGS				\
+  {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},	\
+   {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},	\
+   {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+ 
+ /* We need not worry about when the frame-pointer is required for other
+    reasons.  */
+ #define CAN_ELIMINATE(FROM, TO) 1
+ 
+ #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+  (OFFSET) = cris_initial_elimination_offset (FROM, TO)
+ 
+ 
+ /* Node: Stack Arguments */
+ 
+ /* Since many parameters take up one register each in any case,
+    PROMOTE_PROTOTYPES would seem like a good idea, but measurements
+    indicate that a combination using PROMOTE_MODE is better.  */
+ 
+ #define ACCUMULATE_OUTGOING_ARGS 1
+ 
+ #define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0
+ 
+ 
+ /* Node: Register Arguments */
+ 
+ /* The void_type_node is sent as a "closing" call.  We have to stop it
+    since it's invalid to FUNCTION_ARG_PASS_BY_REFERENCE (or was invalid at
+    some time).  */
+ #define FUNCTION_ARG(CUM, MODE, TYPE, NAMED)			\
+  ((CUM).regs < CRIS_MAX_ARGS_IN_REGS				\
+   && (TYPE) != void_type_node					\
+   && ! FUNCTION_ARG_PASS_BY_REFERENCE (CUM, MODE, TYPE, NAMED)	\
+   ? gen_rtx (REG, MODE, (CRIS_FIRST_ARG_REG) + (CUM).regs)	\
+   : NULL_RTX)
+ 
+ /* The differences between this and the previous, is that this one checks
+    that an argument is named, since incoming stdarg/varargs arguments are
+    pushed onto the stack, and we don't have to check against the "closing"
+    void_type_node TYPE parameter.  */
+ #define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED)			\
+  (((NAMED) && (CUM).regs < CRIS_MAX_ARGS_IN_REGS			\
+    && ! FUNCTION_ARG_PASS_BY_REFERENCE (CUM, MODE, TYPE, NAMED))	\
+   ? gen_rtx (REG, MODE, CRIS_FIRST_ARG_REG + (CUM).regs)		\
+   : NULL_RTX)
+ 
+ #define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED)	\
+  (((CUM).regs == (CRIS_MAX_ARGS_IN_REGS - 1)			\
+    && !MUST_PASS_IN_STACK (MODE, TYPE)				\
+    && CRIS_FUNCTION_ARG_SIZE (MODE, TYPE) > 4			\
+    && CRIS_FUNCTION_ARG_SIZE (MODE, TYPE) <= 8)			\
+   ? 1 : 0)
+ 
+ /* Structs may be passed by value, but they must not be more than 8
+    bytes long.  */
+ #define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED)		\
+  (MUST_PASS_IN_STACK (MODE, TYPE)					\
+   || CRIS_FUNCTION_ARG_SIZE (MODE, TYPE) > 8)				\
+ 
+ /* Contrary to what you'd believe, defining FUNCTION_ARG_CALLEE_COPIES
+    seems like a (small total) loss, at least for gcc-2.7.2 compiling and
+    running gcc-2.1 (small win in size, small loss running -- 100.1%),
+    and similarly for size for products (.1 .. .3% bloat, sometimes win).
+    Due to the empirical likeliness of making slower code, it is not
+    defined.  */
+ 
+ /* This no longer *needs* to be a structure; but keeping it as such should
+    not hurt (and hacking the ABI is simpler).  */
+ #define CUMULATIVE_ARGS struct cum_args
+ struct cum_args {int regs;};
+ 
+ /* The regs member is an integer, the number of arguments got into
+    registers so far, and lib is nonzero if init_cumulative_args was
+    found to generate a call to a library function.  */
+ #define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT)	  \
+  ((CUM).regs = 0)
+ 
+ #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)		\
+  ((CUM).regs							\
+   = (FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED)	\
+      ? (CRIS_MAX_ARGS_IN_REGS) + 1				\
+      : ((CUM).regs						\
+ 	+ (3 + (CRIS_FUNCTION_ARG_SIZE (MODE, TYPE))) / 4)))
+ 
+ #define FUNCTION_ARG_REGNO_P(REGNO)			\
+  ((REGNO) >= CRIS_FIRST_ARG_REG				\
+   && (REGNO) < CRIS_FIRST_ARG_REG + (CRIS_MAX_ARGS_IN_REGS))
+ 
+ 
+ /* Node: Scalar Return */
+ 
+ /* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the
+    time being.  */
+ #define FUNCTION_VALUE(VALTYPE, FUNC)  \
+  gen_rtx (REG, TYPE_MODE (VALTYPE), CRIS_FIRST_ARG_REG)
+ 
+ #define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, CRIS_FIRST_ARG_REG)
+ 
+ #define FUNCTION_VALUE_REGNO_P(N) ((N) == CRIS_FIRST_ARG_REG)
+ 
+ 
+ /* Node: Aggregate Return */
+ 
+ #if 0
+ /* FIXME: Let's try this some time, so we return structures in registers.
+    We would cast the result of int_size_in_bytes to unsigned, so we will
+    get a huge number for "structures" of variable size (-1).  */
+ #define RETURN_IN_MEMORY(TYPE) \
+  ((unsigned) int_size_in_bytes (TYPE) > CRIS_MAX_ARGS_IN_REGS * UNITS_PER_WORD)
+ #endif
+ 
+ #define STRUCT_VALUE_REGNUM ((CRIS_FIRST_ARG_REG) - 1)
+ 
+ 
+ /* Node: Caller Saves */
+ /* (no definitions) */
+ 
+ /* Node: Function entry */
+ 
+ /* See cris.c for TARGET_ASM_FUNCTION_PROLOGUE and
+    TARGET_ASM_FUNCTION_EPILOGUE.  */
+ 
+ /* If the epilogue uses the "ret" insn, we need to fill the
+    delay slot.  */
+ #define DELAY_SLOTS_FOR_EPILOGUE cris_delay_slots_for_epilogue ()
+ 
+ #define ELIGIBLE_FOR_EPILOGUE_DELAY(INSN, N) \
+   cris_eligible_for_epilogue_delay (INSN)
+ 
+ #define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
+  cris_asm_output_mi_thunk(FILE, THUNK_FNDECL, DELTA, FUNCTION)
+ 
+ 
+ /* Node: Profiling */
+ 
+ #define FUNCTION_PROFILER(FILE, LABELNO)  \
+  error ("No FUNCTION_PROFILER for CRIS")
+ 
+ /* No profiling for the time being.  */
+ #define FUNCTION_BLOCK_PROFILER(FILE, LABELNO)	\
+  error ("No FUNCTION_BLOCK_PROFILER for CRIS")
+ 
+ /* No profiling for the time being.  */
+ #define BLOCK_PROFILER(FILE, BLOCKNO)	\
+  error ("No BLOCK_PROFILER for CRIS")
+ 
+ /* FIXME: Some of the undefined macros might be mandatory.  If so, fix
+    documentation.  */
+ 
+ 
+ /* Node: Varargs */
+ 
+ /* We save the register number of the first anonymous argument in
+    first_vararg_reg, and take care of this in the function prologue.
+    This behaviour is used by at least one more port (the ARM?), but
+    may be unsafe when compiling nested functions.  (With varargs? Hairy.)
+    Note that nested-functions is a GNU C extension.
+ 
+    FIXME: We can actually put the size in PRETEND and deduce the number
+    of registers from it in the prologue and epilogue.  */
+ #define SETUP_INCOMING_VARARGS(ARGSSF, MODE, TYPE, PRETEND, SECOND)	\
+   do									\
+     {									\
+       if ((ARGSSF).regs < (CRIS_MAX_ARGS_IN_REGS))			\
+ 	(PRETEND) = ((CRIS_MAX_ARGS_IN_REGS) - (ARGSSF).regs) * 4;	\
+       if (TARGET_PDEBUG)						\
+ 	{								\
+ 	  fprintf (asm_out_file,					\
+ 		   "\n; VA:: %s: %d args before, anon @ #%d, %dtime\n",	\
+ 		   current_function_varargs ? "OLD" : "ANSI",		\
+ 		   (ARGSSF).regs, PRETEND, SECOND);			\
+ 	}								\
+     }									\
+   while (0)
+ 
+ /* FIXME: This and other EXPAND_BUILTIN_VA_... target macros are not
+    documented, although used by several targets.  */
+ #define EXPAND_BUILTIN_VA_ARG(VALIST, TYPE) \
+  cris_expand_builtin_va_arg (VALIST, TYPE)
+ 
+ 
+ /* Node: Trampolines */
+ 
+ /* This looks too complicated, and it is.  I assigned r7 to be the
+    static chain register, but it is call-saved, so we have to save it,
+    and come back to restore it after the call, so we have to save srp...
+    Anyway, trampolines are rare enough that we can cope with this
+    somewhat lack of elegance.
+     (Do not be tempted to "straighten up" whitespace in the asms; the
+    assembler #NO_APP state mandates strict spacing). */
+ #define TRAMPOLINE_TEMPLATE(FILE)		\
+   do						\
+     {						\
+       fprintf (FILE, "\tmove.d $%s,[$pc+20]\n",	\
+ 	       reg_names[STATIC_CHAIN_REGNUM]);	\
+       fprintf (FILE, "\tmove $srp,[$pc+22]\n");	\
+       fprintf (FILE, "\tmove.d 0,$%s\n",	\
+ 	       reg_names[STATIC_CHAIN_REGNUM]);	\
+       fprintf (FILE, "\tjsr 0\n");		\
+       fprintf (FILE, "\tmove.d 0,$%s\n",	\
+ 	       reg_names[STATIC_CHAIN_REGNUM]);	\
+       fprintf (FILE, "\tjump 0\n");		\
+     }						\
+   while (0)
+ 
+ #define TRAMPOLINE_SIZE 32
+ 
+ /* CRIS wants instructions on word-boundary.
+    Note that due to a bug (reported) in 2.7.2 and earlier, this is
+    actually treated as alignment in _bytes_, not _bits_.  (Obviously
+    this is not fatal, only a slight waste of stack space). */
+ #define TRAMPOLINE_ALIGNMENT 16
+ 
+ #define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT)		\
+   do								\
+     {								\
+       emit_move_insn (gen_rtx (MEM, SImode,			\
+ 			       plus_constant (TRAMP, 10)),	\
+ 		      CXT);					\
+       emit_move_insn (gen_rtx (MEM, SImode,			\
+ 			       plus_constant (TRAMP, 16)),	\
+ 		      FNADDR);					\
+     }								\
+   while (0)
+ 
+ /* Note that there is no need to do anything with the cache for sake of
+    a trampoline.  */
+ 
+ 
+ /* Node: Library Calls */
+ 
+ #define MULSI3_LIBCALL "__Mul"
+ #define DIVSI3_LIBCALL "__Div"
+ #define UDIVSI3_LIBCALL "__Udiv"
+ #define MODSI3_LIBCALL "__Mod"
+ #define UMODSI3_LIBCALL "__Umod"
+ 
+ /* If you change this, you have to check whatever libraries and systems
+    that use it.  */
+ #define TARGET_EDOM 33
+ 
+ 
+ /* Node: Addressing Modes */
+ 
+ #define HAVE_POST_INCREMENT 1
+ 
+ #define CONSTANT_ADDRESS_P(X) CONSTANT_P (X)
+ 
+ #define MAX_REGS_PER_ADDRESS 2
+ 
+ /* There are helper macros defined here which are used only in
+    GO_IF_LEGITIMATE_ADDRESS.
+ 
+    Note that you *have to* reject invalid addressing modes for mode
+    MODE, even if it is legal for normal addressing modes.  You cannot
+    rely on the constraints to do this work.  They can only be used to
+    doublecheck your intentions.  One example is that you HAVE TO reject
+    (mem:DI (plus:SI (reg:SI x) (reg:SI y))) because for some reason
+    this cannot be reloaded.  (Which of course you can argue that gcc
+    should have done.)  FIXME:  Strange.  Check.  */
+ 
+ /* No symbol can be used as an index (or more correct, as a base) together
+    with a register with PIC; the PIC register must be there.  */
+ #define CONSTANT_INDEX_P(X) \
+  (CONSTANT_P (X) && !(flag_pic && cris_symbol (X)))
+ 
+ /* True if X is a valid base register.  */
+ #define BASE_P(X) \
+  (REG_P (X) && REG_OK_FOR_BASE_P (X))
+ 
+ /* True if X is a valid base register with or without autoincrement.  */
+ #define BASE_OR_AUTOINCR_P(X) \
+  (BASE_P (X) || (GET_CODE (X) == POST_INC && BASE_P (XEXP (X, 0))))
+ 
+ /* True if X is a valid (register) index for BDAP, i.e. [Rs].S or [Rs+].S.  */
+ #define BDAP_INDEX_P(X)					\
+  ((GET_CODE (X) == MEM && GET_MODE (X) == SImode	\
+    && BASE_OR_AUTOINCR_P (XEXP (X, 0)))			\
+   || (GET_CODE (X) == SIGN_EXTEND			\
+       && GET_CODE (XEXP (X, 0)) == MEM			\
+       && (GET_MODE (XEXP (X, 0)) == HImode		\
+ 	  || GET_MODE (XEXP (X, 0)) == QImode)		\
+       && BASE_OR_AUTOINCR_P (XEXP (XEXP (X, 0), 0))))
+ 
+ /* True if X is a valid (register) index for BIAP, i.e. Rd.m.  */
+ #define BIAP_INDEX_P(X)				\
+  ((BASE_P (X) && REG_OK_FOR_INDEX_P (X))	\
+   || (GET_CODE (X) == MULT			\
+       && BASE_P (XEXP (X, 0))			\
+       && REG_OK_FOR_INDEX_P (XEXP (X, 0))	\
+       && GET_CODE (XEXP (X, 1)) == CONST_INT	\
+       && (INTVAL (XEXP (X, 1)) == 2		\
+ 	  || INTVAL (XEXP (X, 1)) == 4)))
+ 
+ /* True if X is an address that doesn't need a prefix i.e. [Rs] or [Rs+].  */
+ #define SIMPLE_ADDRESS_P(X) \
+  (BASE_P (X)						\
+   || (GET_CODE (X) == POST_INC				\
+       && BASE_P (XEXP (X, 0))))
+ 
+ /* A PIC operand looks like a normal symbol here.  At output we dress it
+    in "[rPIC+symbol:GOT]" (global symbol) or "rPIC+symbol:GOTOFF" (local
+    symbol) so we exclude all addressing modes where we can't replace a
+    plain "symbol" with that.  A global PIC symbol does not fit anywhere
+    here (but is thankfully a general_operand in itself).  A local PIC
+    symbol is valid for the plain "symbol + offset" case.  */
+ #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)			\
+  {								\
+    rtx x1, x2;							\
+    if (SIMPLE_ADDRESS_P (X))					\
+      goto ADDR;							\
+    if (CONSTANT_P (X)						\
+        && (! flag_pic						\
+ 	   || cris_gotless_symbol (X)				\
+ 	   || ! cris_symbol (X)))				\
+      goto ADDR;							\
+    /* Indexed?  */						\
+    if (GET_CODE (X) == PLUS)					\
+      {								\
+        x1 = XEXP (X, 0);					\
+        x2 = XEXP (X, 1);					\
+        /* BDAP o, Rd.  */					\
+        if ((BASE_P (x1) && CONSTANT_INDEX_P (x2))		\
+ 	   || (BASE_P (x2) && CONSTANT_INDEX_P (x1))		\
+ 	    /* BDAP Rs[+], Rd.  */				\
+ 	   || (GET_MODE_SIZE (MODE) <= UNITS_PER_WORD		\
+ 	       && ((BASE_P (x1) && BDAP_INDEX_P (x2))		\
+ 		   || (BASE_P (x2) && BDAP_INDEX_P (x1))	\
+ 		   /* BIAP.m Rs, Rd */				\
+ 		   || (BASE_P (x1) && BIAP_INDEX_P (x2))	\
+ 		   || (BASE_P (x2) && BIAP_INDEX_P (x1)))))	\
+ 	 goto ADDR;						\
+      }								\
+    else if (GET_CODE (X) == MEM)				\
+      {								\
+        /* DIP (Rs).  Reject [[reg+]] and [[reg]] for		\
+ 	  DImode (long long).  */				\
+        if (GET_MODE_SIZE (MODE) <= UNITS_PER_WORD		\
+ 	   && (BASE_P (XEXP (X, 0))				\
+ 	       || BASE_OR_AUTOINCR_P (XEXP (X, 0))))		\
+ 	 goto ADDR;						\
+      }								\
+  }
+ 
+ #ifndef REG_OK_STRICT
+  /* Nonzero if X is a hard reg that can be used as a base reg
+     or if it is a pseudo reg.  */
+ # define REG_OK_FOR_BASE_P(X)			\
+  (REGNO (X) <= CRIS_LAST_GENERAL_REGISTER	\
+   || REGNO (X) == ARG_POINTER_REGNUM		\
+   || REGNO (X) >= FIRST_PSEUDO_REGISTER)
+ #else
+  /* Nonzero if X is a hard reg that can be used as a base reg.  */
+ # define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+ #endif
+ 
+ #ifndef REG_OK_STRICT
+  /* Nonzero if X is a hard reg that can be used as an index
+     or if it is a pseudo reg.  */
+ # define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
+ #else
+  /* Nonzero if X is a hard reg that can be used as an index.  */
+ # define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
+ #endif
+ 
+ /* For now, don't do anything.  GCC does a good job most often.
+ 
+     Maybe we could do something about gcc:s misbehaviour when it
+    recalculates frame offsets for local variables, from fp+offs to
+    sp+offs.  The resulting address expression gets screwed up
+    sometimes, but I'm not sure that it may be fixed here, since it is
+    already split up in several instructions (Is this still true?).
+    FIXME: Check and adjust for gcc-2.9x.  */
+ #define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) {}
+ 
+ /* Functionality import from EGCS.
+    Kludge to solve Axis-990219: Work around imperfection in
+    reload_load_address1:
+     (plus (sign_extend (mem:qi (reg))) (reg))
+    should be reloaded as (plus (reg) (reg)), not
+     (plus (sign_extend (reg)) (reg)).
+    There are no checks that reload_load_address_1 "reloads"
+    addresses correctly, so invalidness is not caught or
+    corrected.
+     When the right thing happens, the "something_reloaded" kludge can
+    be removed.  The right thing does not appear to happen for
+    EGCS CVS as of this date (above).  */
+ 
+ #define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN) \
+   do									\
+     {									\
+       if (GET_CODE (X) == PLUS						\
+ 	  && REG_P (XEXP (X, 1))					\
+ 	  && GET_CODE (XEXP (X, 0)) == SIGN_EXTEND			\
+ 	  && GET_CODE (XEXP (XEXP (X, 0), 0)) == MEM			\
+ 	  && (GET_MODE (XEXP (XEXP (X, 0), 0)) == HImode		\
+ 	      || GET_MODE (XEXP (XEXP (X, 0), 0)) == QImode)		\
+ 	  && (REG_P (XEXP (XEXP (XEXP (X, 0), 0), 0))			\
+ 	      || (GET_CODE (XEXP (XEXP (XEXP (X, 0), 0), 0))		\
+ 		  == POST_INC						\
+ 		  && REG_P (XEXP (XEXP (XEXP (XEXP (X, 0), 0), 0),	\
+ 				  0)))))				\
+ 	{								\
+ 	  int something_reloaded = 0;					\
+ 									\
+ 	  if (REGNO (XEXP (X, 1)) >= FIRST_PSEUDO_REGISTER)		\
+ 	    {								\
+ 	      /* Second reg is pseudo, reload it. */			\
+ 	      push_reload (XEXP (X, 1), NULL_RTX, &XEXP (X, 1), 	\
+ 			   NULL,					\
+ 			   GENERAL_REGS, GET_MODE (X), VOIDmode, 0, 0,	\
+ 			   OPNUM, TYPE);				\
+ 	      something_reloaded = 1;					\
+ 	    }								\
+ 									\
+ 	  if (REG_P (XEXP (XEXP (X, 0), 0))				\
+ 	      && (REGNO (XEXP (XEXP (X, 0), 0))				\
+ 		  >= FIRST_PSEUDO_REGISTER))				\
+ 	    {								\
+ 	      /* First one is a pseudo - reload that. */		\
+ 	      push_reload (XEXP (XEXP (X, 0), 0), NULL_RTX,		\
+ 			   &XEXP (XEXP (X, 0), 0), NULL, 		\
+ 			   GENERAL_REGS,				\
+ 			   GET_MODE (X), VOIDmode, 0, 0, OPNUM, TYPE);	\
+ 	      something_reloaded = 1;					\
+ 	    }								\
+ 									\
+ 	  if (! something_reloaded					\
+ 	      || (GET_CODE (XEXP (XEXP (X, 0), 0)) == POST_INC		\
+ 		  && (REGNO (XEXP (XEXP (XEXP (X, 0), 0), 0))		\
+ 		      >= FIRST_PSEUDO_REGISTER)))			\
+ 	    /* Reload the sign_extend.	Happens if neither reg is a	\
+ 	       pseudo, or the first one was inside post_increment.  */	\
+ 	    push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL,	\
+ 			 GENERAL_REGS, GET_MODE (X), VOIDmode, 0, 0,	\
+ 			 OPNUM, TYPE);					\
+ 	  goto WIN;							\
+ 	}								\
+     }									\
+   while (0)
+ 
+ /* In CRIS, only the postincrement address mode depends thus,
+    since the increment depends on the size of the operand.  */
+ #define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)	\
+   do							\
+     {							\
+       if (GET_CODE (ADDR) == POST_INC)			\
+ 	goto LABEL;					\
+     }							\
+   while (0)
+ 
+ #define LEGITIMATE_CONSTANT_P(X) 1
+ 
+ 
+ /* Node: Condition Code */
+ 
+ #define NOTICE_UPDATE_CC(EXP, INSN) cris_notice_update_cc (EXP, INSN)
+ 
+ /* FIXME: Maybe define CANONICALIZE_COMPARISON later, when playing with
+    optimizations.  It is needed; currently we do this with instruction
+    patterns and NOTICE_UPDATE_CC.  */
+ 
+ 
+ /* Node: Costs */
+ 
+ #define CONST_COSTS(RTX, CODE, OUTER_CODE)				\
+  case CONST_INT:							\
+    if (INTVAL (RTX) == 0)						\
+      return 0;								\
+    if (INTVAL (RTX) < 32 && INTVAL (RTX) >= -32)			\
+      return 1;								\
+    /* Eight or 16 bits are a word and cycle more expensive.  */		\
+    if (INTVAL (RTX) <= 32767 && INTVAL (RTX) >= -32768)			\
+      return 2;								\
+    /* A 32 bit constant (or very seldom, unsigned 16 bits) costs	\
+       another word.  FIXME: This isn't linear to 16 bits.  */		\
+    return 4;								\
+  case LABEL_REF:							\
+    return 6;								\
+  case CONST:								\
+  case SYMBOL_REF:							\
+    /* For PIC, we need a prefix (if it isn't already there),		\
+       and the PIC register.  For a global PIC symbol, we also need a	\
+       read of the GOT.  */						\
+    return								\
+      flag_pic ? (cris_got_symbol (RTX) ? (2 + 4 + 6) : (2 + 6)) : 6;	\
+  case CONST_DOUBLE:							\
+    if (RTX != CONST0_RTX (GET_MODE (RTX) == VOIDmode ? DImode		\
+ 			  : GET_MODE (RTX)))				\
+      return 12;								\
+    /* Make 0.0 cheap, else test-insns will not be used.  */		\
+    return 0;
+ 
+ #define RTX_COSTS(X, CODE, OUTER_CODE)					\
+  case MULT:								\
+    /* Identify values that are no powers of two.  Powers of 2 are	\
+       taken care of already and those values should not be		\
+       changed.  */							\
+    if (GET_CODE (XEXP (X, 1)) != CONST_INT				\
+        || exact_log2 (INTVAL (XEXP (X, 1)) < 0))			\
+      {									\
+ 	/* If we have a multiply insn, then the cost is between		\
+ 	   1 and 2 "fast" instructions.  */				\
+ 	if (TARGET_HAS_MUL_INSNS)					\
+ 	  return COSTS_N_INSNS (1) + COSTS_N_INSNS (1) /2;		\
+ 									\
+ 	/* Estimate as 4 + 4 * #ofbits.  */				\
+ 	return COSTS_N_INSNS (132);					\
+      }									\
+      break;								\
+  case UDIV:								\
+  case MOD:								\
+  case UMOD:								\
+  case DIV:								\
+    if (GET_CODE (XEXP (X, 1)) != CONST_INT				\
+        || exact_log2 (INTVAL (XEXP (X, 1)) < 0))			\
+      /* Estimate this as 4 + 8 * #of bits.  */				\
+      return COSTS_N_INSNS (260);					\
+ 									\
+  case AND:								\
+    if (GET_CODE (XEXP (X, 1)) == CONST_INT				\
+        /* Two constants may actually happen before optimization.  */	\
+        && GET_CODE (XEXP (X, 0)) != CONST_INT				\
+        && !CONST_OK_FOR_LETTER_P (INTVAL (XEXP (X, 1)), 'I'))		\
+      return								\
+        rtx_cost (XEXP (X, 0), OUTER_CODE) + 2				\
+        + 2 * GET_MODE_NUNITS (GET_MODE (XEXP (X, 0)));			\
+ 									\
+  case ZERO_EXTEND: case SIGN_EXTEND:					\
+    /* Same as move. If embedded in other insn, cost is 0.  */		\
+    return rtx_cost (XEXP (X, 0), OUTER_CODE);
+ 
+ #define ADDRESS_COST(X) cris_address_cost (X)
+ 
+ /* FIXME: Need to define REGISTER_MOVE_COST when more register classes are
+    introduced.  */
+ 
+ /* This isn't strictly correct for v0..3 in buswidth-8bit mode, but
+    should suffice.  */
+ #define MEMORY_MOVE_COST(M, CLASS, IN) \
+  (((M) == QImode) ? 4 : ((M) == HImode) ? 4 : 6)
+ 
+ /* Regardless of the presence of delay slots, the default value of 1 for
+    BRANCH_COST is the best in the range (1, 2, 3), tested with gcc-2.7.2
+    with testcases ipps and gcc, giving smallest and fastest code.  */
+ 
+ #define SLOW_BYTE_ACCESS 0
+ 
+ /* This is the threshold *below* which inline move sequences of
+    word-length sizes will be emitted.  The "9" will translate to
+    (9 - 1) * 4 = 32 bytes maximum moved, but using 16 instructions
+    (8 instruction sequences) or less.  */
+ #define MOVE_RATIO 9
+ 
+ 
+ /* Node: Sections */
+ 
+ #define TEXT_SECTION_ASM_OP "\t.text"
+ 
+ #define DATA_SECTION_ASM_OP "\t.data"
+ 
+ #define FORCE_EH_FRAME_INFO_IN_DATA_SECTION (! TARGET_ELF)
+ 
+ /* The jump table is immediately connected to the preceding insn.  */
+ #define JUMP_TABLES_IN_TEXT_SECTION 1
+ 
+ /* We need to code in PIC-specific flags into SYMBOL_REF_FLAG.  */
+ 
+ #define ENCODE_SECTION_INFO(EXP) cris_encode_section_info (EXP)
+ 
+ /* We pull a little trick to register the _fini function with atexit,
+    after (presumably) registering the eh frame info, since we don't handle
+    _fini (a.k.a. ___fini_start) in crt0 or have a crti for "pure" ELF.  */
+ #ifdef CRT_BEGIN
+ #define FORCE_INIT_SECTION_ALIGN		\
+  do						\
+    {						\
+      extern void __fini__start (void);		\
+      atexit (__fini__start);			\
+    }						\
+  while (0)
+ #endif
+ 
+ /* Node: PIC */
+ 
+ #define PIC_OFFSET_TABLE_REGNUM 0
+ 
+ #define LEGITIMATE_PIC_OPERAND_P(X) cris_legitimate_pic_operand (X)
+ 
+ 
+ /* Node: File Framework */
+ 
+ /* NO_APP *only at file start* means faster assembly.
+    It also means comments are not allowed.
+    In some cases comments will be output for debugging purposes.
+    Make sure they are allowed then.  */
+ /* Override previous definitions (elfos.h).  */
+ #undef ASM_FILE_START
+ #define ASM_FILE_START(STREAM)					\
+   do								\
+     {								\
+       if (TARGET_PDEBUG || flag_print_asm_name)			\
+ 	fprintf ((STREAM), "#APP\n");				\
+       else							\
+ 	fprintf ((STREAM), "#NO_APP\n");			\
+       if (TARGET_ELF)						\
+ 	output_file_directive ((STREAM), main_input_filename);	\
+     }								\
+   while (0)
+ 
+ /* Override previous definitions (elfos.h).  */
+ #undef ASM_FILE_END
+ #define ASM_FILE_END(STREAM)
+ 
+ /* We don't want an .ident for gcc.  To avoid that but still support
+    #ident, we override ASM_OUTPUT_IDENT and, since the gcc .ident is its
+    only use besides ASM_OUTPUT_IDENT, undef IDENT_ASM_OP from elfos.h.  */
+ #undef IDENT_ASM_OP
+ #undef ASM_OUTPUT_IDENT
+ #define ASM_OUTPUT_IDENT(FILE, NAME) \
+   fprintf (FILE, "%s\"%s\"\n", "\t.ident\t", NAME);
+ 
+ #define ASM_APP_ON "#APP\n"
+ 
+ #define ASM_APP_OFF "#NO_APP\n"
+ 
+ 
+ /* Node: Data Output */
+ 
+ /* We must use REAL_VALUE_TO_TARGET_SINGLE and
+    REAL_VALUE_TO_TARGET_LONG_DOUBLE.  It seems real.h cannot support when
+    target-double is target-single is 32bit-single.  */
+ #define ASM_OUTPUT_LONG_DOUBLE(FILE, VALUE)		\
+   do							\
+     {							\
+       long l[2];					\
+       REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l);	\
+       fprintf (FILE, "\t.dword 0x%lx\n", l[0]);		\
+       fprintf (FILE, "\t.dword 0x%lx\n", l[1]);		\
+     }							\
+   while (0)
+ 
+ /* FIXME: The manual says "array of long:s", but
+    REAL_VALUE_TO_TARGET_SINGLE actually writes a long.  */
+ #define ASM_OUTPUT_FLOAT(FILE, VALUE)		\
+   do						\
+     {						\
+       long l;					\
+       REAL_VALUE_TO_TARGET_SINGLE (VALUE, l);	\
+       fprintf (FILE, "\t.dword 0x%lx\n", l);	\
+     }						\
+   while (0)
+ 
+ /* This is what is used by gcc for 64-bit floats,
+    not the "long double" one. */
+ #define ASM_OUTPUT_DOUBLE(FILE, VALUE) \
+  ASM_OUTPUT_LONG_DOUBLE (FILE, VALUE)
+ 
+ 
+ /* This is a kludge for a.out+ELF support: For non-ELF prioritized
+    [cd]tors, globalize the function so collect2 can collect it.  This is
+    due to short-sightedness guided by defined (ASM_OUTPUT_SECTION_NAME)
+    && defined (ASM_OUTPUT_CONSTRUCTOR).  */
+ 
+ #define ASM_OUTPUT_INT(FILE, VALUE)		\
+   do						\
+     {						\
+       fprintf (FILE, "\t.dword ");		\
+       output_addr_const (FILE, (VALUE));	\
+       fprintf (FILE, "\n");			\
+     }						\
+   while (0)
+ 
+ #define ASM_OUTPUT_SHORT(FILE, VALUE)		\
+   do						\
+     {						\
+       fprintf (FILE, "\t.word ");		\
+       output_addr_const (FILE, (VALUE));	\
+       fprintf (FILE, "\n");			\
+     }						\
+   while (0)
+ 
+ #define ASM_OUTPUT_CHAR(FILE, VALUE)		\
+   do						\
+     {						\
+       fprintf (FILE, "\t.byte ");		\
+       output_addr_const (FILE, (VALUE));	\
+       fprintf (FILE, "\n");			\
+     }						\
+   while (0)
+ 
+ #define ASM_OUTPUT_BYTE(FILE, VALUE)  \
+  fprintf (FILE, "\t.byte 0x%x\n", (VALUE))
+ 
+ #define IS_ASM_LOGICAL_LINE_SEPARATOR(C) (C) == '@'
+ 
+ /* FIXME: These are undocumented. */
+ /* We need to define these, since the 2byte, 4byte, 8byte op:s are only
+    available in ELF.  These "normal" pseudos do not have any alignment
+    constraints or side-effects.  */
+ #undef UNALIGNED_SHORT_ASM_OP
+ #define UNALIGNED_SHORT_ASM_OP "\t.word\t"
+ 
+ #undef INT_ASM_OP
+ #define INT_ASM_OP "\t.dword\t"
+ 
+ #undef UNALIGNED_INT_ASM_OP
+ #define UNALIGNED_INT_ASM_OP "\t.dword\t"
+ 
+ #undef UNALIGNED_DOUBLE_INT_ASM_OP
+ #define UNALIGNED_DOUBLE_INT_ASM_OP "\t.quad\t"
+ 
+ /* Node: Uninitialized Data */
+ 
+ /* Remember to round off odd values if we want data alignment,
+    since we cannot do that with an .align directive.
+ 
+    Using .comm causes the space not to be reserved in .bss, but by
+    tricks with the symbol type.  Not good if other tools than binutils
+    are used on the object files.  Since ".global ... .lcomm ..." works, we
+    use that.  Use .._ALIGNED_COMMON, since gcc whines when we only have
+    ..._COMMON, and we prefer to whine outselves; BIGGEST_ALIGNMENT is not
+    the one to check.  This done for a.out only.  */
+ /* FIXME: I suspect a bug in gcc with alignment.  Do not warn until
+    investigated; it mucks up the testsuite results.  */
+ #define CRIS_ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN, LOCAL) \
+   do									\
+     {									\
+       int align_ = (ALIGN) / BITS_PER_UNIT;				\
+       if (TARGET_DATA_ALIGN && TARGET_ALIGN_BY_32 && align_ < 4)	\
+ 	align_ = 4;							\
+       else if (TARGET_DATA_ALIGN && align_ < 2)				\
+ 	align_ = 2;							\
+       /* FIXME: Do we need this?  */					\
+       else if (align_ < 1)						\
+ 	align_ = 1;							\
+ 									\
+       if (TARGET_ELF)							\
+ 	{								\
+ 	  if (LOCAL)							\
+ 	    {								\
+ 	      fprintf ((FILE), "%s", LOCAL_ASM_OP);			\
+ 	      assemble_name ((FILE), (NAME));				\
+ 	      fprintf ((FILE), "\n");					\
+ 	    }								\
+ 	  fprintf ((FILE), "%s", COMMON_ASM_OP);			\
+ 	  assemble_name ((FILE), (NAME));				\
+ 	  fprintf ((FILE), ",%u,%u\n", (SIZE), align_);			\
+ 	}								\
+       else								\
+ 	{								\
+ 	  /* We can't tell a one-only or weak COMM from a "global	\
+ 	     COMM" so just make all non-locals weak.  */		\
+ 	  if (! (LOCAL))						\
+ 	    ASM_WEAKEN_LABEL (FILE, NAME);				\
+ 	  fputs ("\t.lcomm ", (FILE));					\
+ 	  assemble_name ((FILE), (NAME));				\
+ 	  fprintf ((FILE), ",%u\n",					\
+ 		   ((SIZE) + (align_ - 1)) & ~(align_ - 1));		\
+ 	}								\
+     }									\
+   while (0)
+ 
+ #define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN) \
+  CRIS_ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN, 0)
+ 
+ #undef ASM_OUTPUT_ALIGNED_DECL_LOCAL
+ #define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \
+  CRIS_ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN, 1)
+ 
+ /* FIXME: define ASM_OUTPUT_SHARED_COMMON and emit an error when it is
+    used with -melinux and a.out.  */
+ 
+ /* Node: Label Output */
+ 
+ #define ASM_OUTPUT_LABEL(FILE, NAME)		\
+   do						\
+     {						\
+       assemble_name (FILE, NAME);		\
+       fputs (":\n", FILE);			\
+     }						\
+   while (0)
+ 
+ #define ASM_GLOBALIZE_LABEL(FILE, NAME)		\
+   do						\
+     {						\
+       fputs ("\t.global ", FILE);		\
+       assemble_name (FILE, NAME);		\
+       fputs ("\n", FILE);			\
+     }						\
+   while (0)
+ 
+ #define SUPPORTS_WEAK 1
+ 
+ /* FIXME: This macro isn't documented, but this would probably be an
+    appropriate location.  It's only used in crtstuff.c, else we'd have to
+    handle (to #undef or ignore it) in a.out.  */
+ #define HAVE_GAS_HIDDEN 1
+ 
+ #undef  ASM_OUTPUT_INTERNAL_LABEL
+ #define ASM_OUTPUT_INTERNAL_LABEL(FILE, PREFIX, NUM)	\
+   do							\
+     {							\
+       asm_fprintf (FILE, "%L%s%d:\n", PREFIX, NUM);	\
+     }							\
+   while (0)
+ 
+ /* Remove any previous definition (elfos.h).  */
+ #undef ASM_GENERATE_INTERNAL_LABEL
+ #define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM)	\
+   sprintf (LABEL, "*%s%s%ld", LOCAL_LABEL_PREFIX, PREFIX, (long) NUM)
+ 
+ #define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO)		\
+   do								\
+     {								\
+       (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10);	\
+       sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO));		\
+     }								\
+   while (0)
+ 
+ 
+ /* Node: Initialization */
+ /* (no definitions) */
+ 
+ /* Node: Macros for Initialization */
+ 
+ /* We don't want to use "strip" for anything linked with "-melinux"
+    "-shlib", seen by the linker as "-Ur -d -Bdynamic" in combination.  */
+ #define SET_STRIPPABLE_EXECUTABLE(DS, ARGC, ARGV)		\
+   do 								\
+     {								\
+       int i;							\
+       int flags = 0;						\
+       for (i = (ARGC) - 1; i > 0; i--)				\
+ 	{							\
+ 	  if (strcmp ((ARGV)[i], "-Ur") == 0)			\
+ 	    flags |= 1;						\
+ 	  else if (strcmp ((ARGV)[i], "-d") == 0)		\
+ 	    flags |= 2;						\
+ 	  else if (strcmp ((ARGV)[i], "-Bdynamic") == 0)	\
+ 	    flags |= 4;						\
+ 								\
+ 	  if (flags == 7)					\
+ 	    break;						\
+ 	}							\
+ 								\
+       (DS) = (flags != 7);					\
+     }								\
+   while (0)
+ 
+ 
+ /* Node: Instruction Output */
+ 
+ #define REGISTER_NAMES					\
+  {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",	\
+   "r9", "r10", "r11", "r12", "r13", "sp", "pc", "srp", "faked_ap"}
+ 
+ #define ADDITIONAL_REGISTER_NAMES \
+  {{"r14", 14}, {"r15", 15}}
+ 
+ #define PRINT_OPERAND(FILE, X, CODE)		\
+  cris_print_operand (FILE, X, CODE)
+ 
+ /* For delay-slot handling.  */
+ #define PRINT_OPERAND_PUNCT_VALID_P(CODE) (CODE == '#')
+ 
+ #define PRINT_OPERAND_ADDRESS(FILE, ADDR)	\
+    cris_print_operand_address (FILE, ADDR)
+ 
+ /* Output an empty line to illustrate the presence of the delay slot.  */
+ #define DBR_OUTPUT_SEQEND(FILE) \
+   fprintf (FILE, "\n")
+ 
+ #define LOCAL_LABEL_PREFIX (TARGET_ELF ? "." : "")
+ 
+ /* cppinit.c initializes a const array from this, so it must be constant,
+    can't have it different based on options.  Luckily, the prefix is
+    always allowed, so let's have it on all GCC-generated code.  Note that
+    we have this verbatim everywhere in the back-end, not using %R or %s or
+    such.  */
+ #define REGISTER_PREFIX "$"
+ 
+ /* Remove any previous definition (elfos.h).  */
+ /* We use -fno-leading-underscore to remove it, when necessary.  */
+ #undef USER_LABEL_PREFIX
+ #define USER_LABEL_PREFIX "_"
+ 
+ #define ASM_OUTPUT_REG_PUSH(FILE, REGNO) \
+   fprintf (FILE, "\tpush $%s\n", reg_names[REGNO])
+ 
+ #define ASM_OUTPUT_REG_POP(FILE, REGNO) \
+   fprintf (FILE, "\tpop $%s\n", reg_names[REGNO])
+ 
+ 
+ /* Node: Dispatch Tables */
+ 
+ #define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL)	\
+   asm_fprintf (FILE, "\t.word %LL%d-%LL%d\n", VALUE, REL)
+ 
+ #define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE)  \
+   asm_fprintf (FILE, "\t.dword %LL%d\n", VALUE)
+ 
+ /* Defined to also emit an .align in elfos.h.  We don't want that.  */
+ #undef ASM_OUTPUT_CASE_LABEL
+ 
+ /* Since the "bound" insn loads the comparison value if the compared<
+    value (register) is out of bounds (0..comparison value-1), we need
+    to output another case to catch it.
+    The way to find it is to look for the label_ref at the else-arm inside
+    the expanded casesi core-insn.
+    FIXME: Check this construct when changing to new version of gcc.  */
+ #define ASM_OUTPUT_CASE_END(STREAM, NUM, TABLE)				\
+   do									\
+     {									\
+       asm_fprintf (STREAM, "\t.word %LL%d-%LL%d%s\n",			\
+ 		   CODE_LABEL_NUMBER					\
+ 		    (XEXP (XEXP (XEXP					\
+ 				  (XVECEXP				\
+ 				    (PATTERN (PREV_INSN (PREV_INSN	\
+ 							  (TABLE))),	\
+ 				     0, 0), 1), 2), 0)),		\
+ 		   NUM,							\
+ 		   (TARGET_PDEBUG ? "; default" : ""));			\
+     }									\
+   while (0)
+ 
+ 
+ /* Node: Exception Region Output */
+ /* (no definitions) */
+ /* FIXME: Fill in with our own optimized layout.  */
+ 
+ /* Node: Alignment Output */
+ 
+ #define ASM_OUTPUT_ALIGN(FILE, LOG)  \
+  fprintf (FILE, "\t.align %d\n", (LOG))
+ 
+ 
+ /* Node: All Debuggers */
+ 
+ #define DBX_REGISTER_NUMBER(REGNO) \
+  ((REGNO) == CRIS_SRP_REGNUM ? CRIS_CANONICAL_SRP_REGNUM : (REGNO))
+ 
+ /* FIXME: Investigate DEBUGGER_AUTO_OFFSET, DEBUGGER_ARG_OFFSET.  */
+ 
+ 
+ /* Node: DBX Options */
+ 
+ /* Is this correct? Check later. */
+ #define DBX_NO_XREFS
+ 
+ #define DBX_CONTIN_LENGTH 0
+ 
+ /* FIXME: Is this needed when we have 0 DBX_CONTIN_LENGTH?  */
+ #define DBX_CONTIN_CHAR '?'
+ 
+ 
+ /* Node: DBX Hooks */
+ /* (no definitions) */
+ 
+ /* Node: File names and DBX */
+ /* (no definitions) */
+ 
+ 
+ /* Node: SDB and DWARF */
+ 
+ #define DWARF_LINE_MIN_INSTR_LENGTH 2
+ 
+ 
+ /* Node: Cross-compilation */
+ #define REAL_ARITHMETIC
+ 
+ 
+ /* Node: Misc */
+ 
+ /* FIXME: Check this one more time.  */
+ #define PREDICATE_CODES					\
+  {"cris_orthogonal_operator",				\
+   {PLUS, MINUS, IOR, AND, UMIN}},			\
+  {"cris_commutative_orth_op",				\
+   {PLUS, IOR, AND, UMIN}},				\
+  {"cris_operand_extend_operator",			\
+   {PLUS, MINUS, UMIN}},					\
+  {"cris_extend_operator",				\
+   {ZERO_EXTEND, SIGN_EXTEND}},				\
+  {"cris_plus_or_bound_operator",			\
+   {PLUS, UMIN}},					\
+  {"cris_bdap_operand",					\
+   {SUBREG, REG, LABEL_REF, SYMBOL_REF, MEM, CONST_INT,	\
+    CONST_DOUBLE, CONST, SIGN_EXTEND}},			\
+  {"cris_bdap_biap_operand",				\
+   {SUBREG, REG, LABEL_REF, SYMBOL_REF, MEM, CONST_INT,	\
+    CONST_DOUBLE, CONST, SIGN_EXTEND, MULT}},		\
+  {"cris_general_operand_or_gotless_symbol",		\
+   {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,		\
+    LABEL_REF, SUBREG, REG, MEM}},			\
+  {"cris_general_operand_or_symbol",			\
+   {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,		\
+    LABEL_REF, SUBREG, REG, MEM}},			\
+  {"cris_general_operand_or_plt_symbol",			\
+   {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,		\
+    LABEL_REF, SUBREG, REG, MEM}},			\
+  {"cris_mem_call_operand",				\
+   {MEM}},
+ 
+ /* A combination of the bound (umin) insn together with a
+    sign-extended add via the table to PC seems optimal.
+    If the table overflows, the assembler will take care of it.
+    Theoretically, in extreme cases (uncertain if they occur), an error
+    will be emitted, so FIXME: Check how large case-tables are emitted,
+    possible add an option to emit SImode case-tables.  */
+ #define CASE_VECTOR_MODE HImode
+ 
+ #define CASE_VECTOR_PC_RELATIVE 1
+ 
+ /* FIXME: Investigate CASE_VECTOR_SHORTEN_MODE to make sure HImode is not
+    used when broken-.word could possibly fail (plus test-case).  */
+ 
+ #define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
+ 
+ #define FIXUNS_TRUNC_LIKE_FIX_TRUNC
+ 
+ #define EASY_DIV_EXPR TRUNC_DIV_EXPR
+ 
+ /* This is the number of bytes that can be moved in one
+    reasonably fast instruction sequence.  For CRIS, this is two
+    instructions: mem => reg, reg => mem.  */
+ #define MOVE_MAX 4
+ 
+ /* Maybe SHIFT_COUNT_TRUNCATED is safe to define?  FIXME: Check later.  */
+ 
+ #define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+ 
+ #define STORE_FLAG_VALUE 1
+ 
+ #define Pmode SImode
+ 
+ #define FUNCTION_MODE QImode
+ 
+ #define NO_IMPLICIT_EXTERN_C
+ 
+ /*
+  * Local variables:
+  * eval: (c-set-style "gnu")
+  * indent-tabs-mode: t
+  * End:
+  */
diff -cprN nothing/cris.md cris/cris.md
*** nothing/cris.md	Thu Jan  1 01:00:00 1970
--- cris/cris.md	Sat Sep 29 16:29:24 2001
***************
*** 0 ****
--- 1,5096 ----
+ ;; GCC machine description for CRIS cpu cores.
+ ;; Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ ;; Contributed by Axis Communications.
+ 
+ ;; This file is part of GCC.
+ ;;
+ ;; GCC is free software; you can redistribute it and/or modify
+ ;; it under the terms of the GNU General Public License as published by
+ ;; the Free Software Foundation; either version 2, or (at your option)
+ ;; any later version.
+ ;;
+ ;; GCC is distributed in the hope that it will be useful,
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ ;; GNU General Public License for more details.
+ ;;
+ ;; You should have received a copy of the GNU General Public License
+ ;; along with GCC; see the file COPYING.  If not, write to
+ ;; the Free Software Foundation, 59 Temple Place - Suite 330,
+ ;; Boston, MA 02111-1307, USA.
+ 
+ ;; The original PO technology requires these to be ordered by speed,
+ ;; so that assigner will pick the fastest.
+ 
+ ;; See files "md.texi" and "rtl.def" for documentation on define_insn,
+ ;; match_*, et. al.
+ ;;
+ ;; The function cris_notice_update_cc in cris.c handles condition code
+ ;; updates for most instructions, helped by the "cc" attribute.
+ 
+ ;; There are several instructions that are orthogonal in size, and seems
+ ;; they could be matched by a single pattern without a specified size
+ ;; for the operand that is orthogonal.  However, this did not work on
+ ;; gcc-2.7.2 (and problably not on gcc-2.8.1), relating to that when a
+ ;; constant is substituted into an operand, the actual mode must be
+ ;; deduced from the pattern.  There is reasonable hope that that has been
+ ;; fixed in egcs post 1.1.1, so FIXME: try again.
+ 
+ ;; You will notice that three-operand alternatives ("=r", "r", "!To")
+ ;; are marked with a "!" constraint modifier to avoid being reloaded
+ ;; into.  This is because gcc would otherwise prefer to use the constant
+ ;; pool and its offsettable address instead of reloading to an
+ ;; ("=r", "0", "i") alternative.  Also, the constant-pool support was not
+ ;; only suboptimal but also buggy in 2.7.2, ??? maybe only in 2.6.3.
+ 
+ ;; All insns that look like (set (...) (plus (...) (reg:SI 8)))
+ ;; get problems when reloading r8 (frame pointer) to r14 + offs (stack
+ ;; pointer).  Thus the instructions that get into trouble have specific
+ ;; checks against matching frame_pointer_rtx.
+ ;; ??? But it should be re-checked for gcc > 2.7.2
+ ;; FIXME: This changed some time ago (from 2000-03-16) for gcc-2.9x.
+ 
+ ;; FIXME: When PIC, all [rX=rY+S] could be enabled to match
+ ;; [rX=gotless_symbol].
+ ;; The movsi for a gotless symbol could be split (post reload).
+ 
+ ;; 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)])
+ 
+ ;; 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.
+ 
+ ;; 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.
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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);")
+ 
+ ;; 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")
+ 
+ ;; 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\";
+ }")
+ 
+ ;; 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]));")
+ 
+ ;; 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]));")
+ 
+ ;; 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]\";
+ }")
+ 
+ ;; 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")])
+ 
+ ;; 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")
+ 
+ ;; 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\";
+ }")
+ 
+ ;; 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")])
+ 
+ (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")])
+ 
+ 
+ ;; 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")])
+ 
+ 
+ ;; 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")])
+ 
+ ;; 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")
+ 
+ ;; [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\";
+ }")
+ 
+ ;; 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")
+ 
+ ;; [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\";
+ }")
+ 
+ ;; 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")])
+ 
+ (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")])
+ 
+ ;; 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")])
+ 
+ (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")])
+ 
+ ;; 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")
+ 
+ 
+ ;; [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\";
+ }")
+ 
+ 
+ ;; 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")
+ 
+ ;; [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\";
+ }")
+ 
+ ;; 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")])
+ 
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ (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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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);")
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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);
+ }")
+ 
+ ;; 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)]))]
+   "")
+ 
+ ;; 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]));")
+ 
+ ;; 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);")
+ 
+ ;; 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\";
+ }")
+ 
+ 
+ ;; 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")])
+ 
+ ;; 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")])
+ 
+ ;; 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\";
+ }")
+ 
+ ;; Local variables:
+ ;; mode:emacs-lisp
+ ;; comment-start: ";; "
+ ;; eval: (set-syntax-table (copy-sequence (syntax-table)))
+ ;; eval: (modify-syntax-entry ?[ "(]")
+ ;; eval: (modify-syntax-entry ?] ")[")
+ ;; eval: (modify-syntax-entry ?{ "(}")
+ ;; eval: (modify-syntax-entry ?} "){")
+ ;; eval: (setq indent-tabs-mode t)
+ ;; End:
diff -cprN nothing/linux.h cris/linux.h
*** nothing/linux.h	Thu Jan  1 01:00:00 1970
--- cris/linux.h	Tue Sep 25 10:45:19 2001
***************
*** 0 ****
--- 1,134 ----
+ /* Definitions for GCC.  Part of the machine description for CRIS.
+    Copyright (C) 2001 Free Software Foundation, Inc.
+    Contributed by Axis Communications.  Written by Hans-Peter Nilsson.
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING.  If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+ 
+ 
+ /* After the first "Node:" comment comes all preprocessor directives and
+    attached declarations described in the info files, the "Using and
+    Porting GCC" manual (uapgcc), in the same order as found in the "Target
+    macros" section in the gcc-2.9x CVS edition of 2000-03-17.  FIXME: Not
+    really, but needs an update anyway.
+ 
+    There is no generic copy-of-uapgcc comment, you'll have to see uapgcc
+    for that.  If applicable, there is a CRIS-specific comment.  The order
+    of macro definitions follow the order in the manual.  Every section in
+    the manual (node in the info pages) has an introductory `Node:
+    <subchapter>' comment.  If no macros are defined for a section, only
+    the section-comment is present.  */
+ 
+ /* This file defines the macros for cris-axis-linux-gnu that are not
+    covered by cris.h, elfos.h and (config/)linux.h.  */
+ 
+ 
+ /* Node: Instruction Output */
+ 
+ #undef USER_LABEL_PREFIX
+ #define USER_LABEL_PREFIX ""
+ 
+ /* Node: Driver */
+ /* These macros are CRIS-specific, but used in target driver macros.  */
+ 
+ #undef CRIS_CPP_SUBTARGET_SPEC
+ #define CRIS_CPP_SUBTARGET_SPEC \
+   "-D__linux__ -D__unix__  -D__ELF__\
+    %{pthread:-D_REENTRANT}\
+    %{fPIC|fpic: -D__PIC__ -D__pic__}\
+    %{!fleading-underscore:-fno-leading-underscore -D__NO_UNDERSCORES__}\
+    %{!march=*:%{!cpu=*:-D__arch_v10 -D__CRIS_arch_version=10}}\
+    %{!ansi:%{!std=*:%{!undef:-Dlinux -Dunix}\
+      -Asystem(unix) -Asystem(posix) -Acpu(cris) -Amachine(cris)}}"
+ 
+ #undef CRIS_CC1_SUBTARGET_SPEC
+ #define CRIS_CC1_SUBTARGET_SPEC \
+  "%{!march=*:%{!cpu=*:-march=v10}}"
+ 
+ #undef CRIS_ASM_SUBTARGET_SPEC
+ #define CRIS_ASM_SUBTARGET_SPEC \
+  "--em=criself\
+   %{!fleading-underscore:--no-underscore}\
+   %{fPIC|fpic: --pic}"
+ 
+ /* Provide a legacy -mlinux option.  */
+ #undef CRIS_SUBTARGET_SWITCHES
+ #define CRIS_SUBTARGET_SWITCHES						\
+  {"linux",				 0, ""},			\
+  {"gotplt",	 -TARGET_MASK_AVOID_GOTPLT, ""},			\
+  {"no-gotplt",	  TARGET_MASK_AVOID_GOTPLT,				\
+   N_("Together with -fpic and -fPIC, do not use GOTPLT references")},
+ 
+ #undef CRIS_SUBTARGET_DEFAULT
+ #define CRIS_SUBTARGET_DEFAULT			\
+   (TARGET_MASK_SVINTO				\
+    + TARGET_MASK_ETRAX4_ADD			\
+    + TARGET_MASK_ALIGN_BY_32			\
+    + TARGET_MASK_ELF				\
+    + TARGET_MASK_LINUX)
+ 
+ #undef CRIS_DEFAULT_CPU_VERSION
+ #define CRIS_DEFAULT_CPU_VERSION CRIS_CPU_NG
+ 
+ #undef CRIS_SUBTARGET_VERSION
+ #define CRIS_SUBTARGET_VERSION " - cris-axis-linux-gnu"
+ 
+ 
+ /* Redefine what was in svr4.h.  Include order madness makes it less
+    useful to include (config/)linux.h after cris.h.  (config/)linux.h
+    includes svr4.h which undef:s lots of supposedly arch-specific macros
+    carefully defined by cris.h.  */
+ #undef LIB_SPEC
+ #define LIB_SPEC "%{!shared:%{!symbolic:-lc}}"
+ 
+ /* We need an -rpath-link to ld.so.1, and presumably to each directory
+    specified with -B.  */
+ #undef CRIS_LINK_SUBTARGET_SPEC
+ #define CRIS_LINK_SUBTARGET_SPEC \
+  "-mcrislinux\
+   -rpath-link include/asm/../..%s\
+   %{shared} %{static}\
+   %{symbolic:-Bdynamic} %{shlib:-Bdynamic} %{static:-Bstatic}\
+   %{!shared:%{!static:%{rdynamic:-export-dynamic}}}\
+   %{O2|O3: --gc-sections}"
+ 
+ #undef STARTFILE_SPEC
+ #define STARTFILE_SPEC \
+  "%{!shared:\
+    %{pg:gcrt1.o%s}\
+    %{!pg:\
+     %{p:gcrt1.o%s}\
+     %{!p:\
+      %{profile:gcrt1.o%s}\
+      %{!profile:crt1.o%s}}}}\
+   crti.o%s\
+   %{!shared:crtbegin.o%s}\
+   %{shared:crtbeginS.o%s}"
+ 
+ 
+ /* Node: Sections */
+ 
+ /* GNU/Linux has crti and crtn and does not need the
+    FORCE_INIT_SECTION_ALIGN trick in cris.h.  */
+ #undef FORCE_INIT_SECTION_ALIGN
+ 
+ /*
+  * Local variables:
+  * eval: (c-set-style "gnu")
+  * indent-tabs-mode: t
+  * End:
+  */
diff -cprN nothing/aout.h cris/aout.h
*** nothing/aout.h	Thu Jan  1 01:00:00 1970
--- cris/aout.h	Sat Sep 29 16:04:21 2001
***************
*** 0 ****
--- 1,422 ----
+ /* Definitions for GCC.  Part of the machine description for CRIS.
+    Copyright (C) 2001 Free Software Foundation, Inc.
+    Contributed by Axis Communications.  Written by Hans-Peter Nilsson.
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING.  If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+ 
+ /* After the first "Node:" comment comes all preprocessor directives and
+    attached declarations described in the info files, the "Using and
+    Porting GCC" manual (uapgcc), in the same order as found in the "Target
+    macros" section in the gcc-2.9x CVS edition of 2000-03-17.  FIXME: Not
+    really, but needs an update anyway.
+ 
+    There is no generic copy-of-uapgcc comment, you'll have to see uapgcc
+    for that.  If applicable, there is a CRIS-specific comment.  The order
+    of macro definitions follow the order in the manual.  Every section in
+    the manual (node in the info pages) has an introductory `Node:
+    <subchapter>' comment.  If no macros are defined for a section, only
+    the section-comment is present.  */
+ 
+ /* This file defines the macros for a.out that are not covered by cris.h.
+    Many macros are copied from elfos.h and should be in some generic
+    config/gas-aout.h.  */
+ 
+ /* Node: Driver */
+ 
+ #undef STARTFILE_SPEC
+ #define STARTFILE_SPEC \
+  "%{melinux:crt0.o%s}\
+   %{!melinux:\
+    %{sim2:s2crt0.o%s}\
+    %{!sim2:\
+     %{sim:scrt0.o%s}\
+     %{!sim:%{pg:gcrt0.o%s}\
+      %{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}}}"
+ 
+ /* Which library to get.  The only difference from the default is to get
+    libsc.a if -sim is given to the driver.  Repeat -lc -lsysX
+    {X=sim,linux}, because libsysX needs (at least) errno from libc, and
+    then we want to resolve new unknowns in libc against libsysX, not
+    libnosys.  Assume everything is in libc for -mlinux.  */
+ #undef LIB_SPEC
+ #define LIB_SPEC \
+  "%{melinux:-lc -lsyslinux -lc -lsyslinux -lic}\
+   %{!melinux:\
+    %{sim*:-lc -lsyssim -lc -lsyssim}\
+    %{!sim*:%{g*:-lg}\
+      %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} -lbsp}\
+    -lnosys}"
+ 
+ #undef CRIS_CPP_SUBTARGET_SPEC
+ #define CRIS_CPP_SUBTARGET_SPEC \
+  "-D__AOUT__\
+   %{melinux:-D__linux__ -D__unix__ -D__elinux__ -D__uclinux__\
+     %{!nostdinc:\
+       %{!mbest-lib-options:%{isystem*}}\
+       -isystem elinux/include%s\
+       %{mbest-lib-options:%{isystem*}}}\
+     %{!ansi:%{!std=*:%{!undef:-Dlinux -Dunix -Delinux -Duclinux}}}}\
+   %{mbest-lib-options:\
+    %{!moverride-best-lib-options:\
+     %{!march=*:%{!metrax*:%{!mcpu=*:-D__tune_v8 -D__CRIS_arch_tune=8}}}}}"
+ 
+ #undef CRIS_CC1_SUBTARGET_SPEC
+ #define CRIS_CC1_SUBTARGET_SPEC \
+  "%{mbest-lib-options:\
+    %{!moverride-best-lib-options:\
+     %{!march=*:%{!mcpu=*:-mtune=v8}}}}"
+ 
+ #undef CRIS_ASM_SUBTARGET_SPEC
+ #define CRIS_ASM_SUBTARGET_SPEC "--em=crisaout"
+ 
+ #undef CRIS_LINK_SUBTARGET_SPEC
+ #define CRIS_LINK_SUBTARGET_SPEC \
+  "-mcrisaout\
+   %{sim2:%{!T*:-Tdata 0x4000000 -Tbss 0x8000000}}\
+   %{melinux:-Ur -d\
+    %{!shlib:%{!symbolic:-Bstatic}}\
+    %{shlib:-Bdynamic}\
+    %{symbolic:-Bdynamic}\
+    %{static:-Bstatic}}\
+   %{melinux-stacksize=*:-defsym __Stacksize=%*}"
+ 
+ #undef CRIS_SUBTARGET_SWITCHES
+ #define CRIS_SUBTARGET_SWITCHES						\
+   {"elinux", (TARGET_MASK_SVINTO					\
+ 	      + TARGET_MASK_STACK_ALIGN					\
+ 	      + TARGET_MASK_CONST_ALIGN					\
+ 	      + TARGET_MASK_DATA_ALIGN					\
+ 	      + TARGET_MASK_ETRAX4_ADD					\
+ 	      + TARGET_MASK_ALIGN_BY_32),				\
+    N_("Compile for the MMU-less Etrax 100-based elinux system")},	\
+   /* Legacy option.  */							\
+   {"aout",   0,	""},
+ 
+ #undef CRIS_SUBTARGET_LONG_OPTIONS
+ #define CRIS_SUBTARGET_LONG_OPTIONS \
+   {"elinux-stacksize=", &cris_elinux_stacksize_str,			\
+    N_("For elinux, request a specified stack-size for this program")},	\
+ 
+ #undef CRIS_SUBTARGET_VERSION
+ #define CRIS_SUBTARGET_VERSION " - a.out"
+ 
+ #undef CRIS_SUBTARGET_DEFAULT
+ #define CRIS_SUBTARGET_DEFAULT 0
+ 
+ /* Node: Storage Layout */
+ 
+ /* We can align to 16 bits (only) with CRIS a.out.  */
+ #define MAX_OFILE_ALIGNMENT 16
+ 
+ 
+ /* Node: Library Calls */
+ 
+ #define TARGET_MEM_FUNCTIONS
+ 
+ 
+ /* Node: Data Output */
+ 
+ #define ESCAPES \
+ "\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+ \0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0\
+ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\
+ \1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+ \1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+ \1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+ \1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1"
+ 
+ /* Some svr4 assemblers have a limit on the number of characters which
+    can appear in the operand of a .string directive.  If your assembler
+    has such a limitation, you should define STRING_LIMIT to reflect that
+    limit.  Note that at least some svr4 assemblers have a limit on the
+    actual number of bytes in the double-quoted string, and that they
+    count each character in an escape sequence as one byte.  Thus, an
+    escape sequence like \377 would count as four bytes.
+ 
+    If your target assembler doesn't support the .string directive, you
+    should define this to zero.  */
+ 
+ #define STRING_LIMIT	((unsigned) 256)
+ 
+ #define STRING_ASM_OP	"\t.string\t"
+ #define ASCII_DATA_ASM_OP	"\t.ascii\t"
+ #define TYPE_ASM_OP	"\t.type\t"
+ #define SIZE_ASM_OP	"\t.size\t"
+ #define TYPE_OPERAND_FMT	"@%s"
+ 
+ /* The routine used to output NUL terminated strings.  We use a special
+    version of this for most svr4 targets because doing so makes the
+    generated assembly code more compact (and thus faster to assemble)
+    as well as more readable, especially for targets like the i386
+    (where the only alternative is to output character sequences as
+    comma separated lists of numbers).  */
+ 
+ #define ASM_OUTPUT_LIMITED_STRING(FILE, STR)		\
+   do							\
+     {							\
+       register const unsigned char *_limited_str =	\
+ 	(const unsigned char *) (STR);			\
+       register unsigned ch;				\
+       							\
+       fprintf ((FILE), "%s\"", STRING_ASM_OP);		\
+       							\
+       for (; (ch = *_limited_str); _limited_str++)	\
+         {						\
+ 	  register int escape;				\
+ 	  						\
+ 	  switch (escape = ESCAPES[ch])			\
+ 	    {						\
+ 	    case 0:					\
+ 	      putc (ch, (FILE));			\
+ 	      break;					\
+ 	    case 1:					\
+ 	      fprintf ((FILE), "\\%03o", ch);		\
+ 	      break;					\
+ 	    default:					\
+ 	      putc ('\\', (FILE));			\
+ 	      putc (escape, (FILE));			\
+ 	      break;					\
+ 	    }						\
+         }						\
+       							\
+       fprintf ((FILE), "\"\n");				\
+     }							\
+   while (0)
+ 
+ /* The routine used to output sequences of byte values.  We use a special
+    version of this for most svr4 targets because doing so makes the
+    generated assembly code more compact (and thus faster to assemble)
+    as well as more readable.  Note that if we find subparts of the
+    character sequence which end with NUL (and which are shorter than
+    STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING.  */
+ 
+ #undef  ASM_OUTPUT_ASCII
+ #define ASM_OUTPUT_ASCII(FILE, STR, LENGTH)				\
+   do									\
+     {									\
+       register const unsigned char *_ascii_bytes =			\
+ 	(const unsigned char *) (STR);					\
+       register const unsigned char *limit = _ascii_bytes + (LENGTH);	\
+       register unsigned bytes_in_chunk = 0;				\
+ 									\
+       for (; _ascii_bytes < limit; _ascii_bytes++)			\
+         {								\
+ 	  register const unsigned char *p;				\
+       									\
+ 	  if (bytes_in_chunk >= 60)					\
+ 	    {								\
+ 	      fprintf ((FILE), "\"\n");					\
+ 	      bytes_in_chunk = 0;					\
+ 	    }								\
+       									\
+ 	  for (p = _ascii_bytes; p < limit && *p != '\0'; p++)		\
+ 	    continue;							\
+       									\
+ 	  if (p < limit && (p - _ascii_bytes) <= (long)STRING_LIMIT)	\
+ 	    {								\
+ 	      if (bytes_in_chunk > 0)					\
+ 		{							\
+ 		  fprintf ((FILE), "\"\n");				\
+ 		  bytes_in_chunk = 0;					\
+ 		}							\
+       									\
+ 	      ASM_OUTPUT_LIMITED_STRING ((FILE), _ascii_bytes);		\
+ 	      _ascii_bytes = p;						\
+ 	    }								\
+ 	  else								\
+ 	    {								\
+ 	      register int escape;					\
+ 	      register unsigned ch;					\
+       									\
+ 	      if (bytes_in_chunk == 0)					\
+ 		fprintf ((FILE), "%s\"", ASCII_DATA_ASM_OP);		\
+       									\
+ 	      switch (escape = ESCAPES[ch = *_ascii_bytes])		\
+ 		{							\
+ 		case 0:							\
+ 		  putc (ch, (FILE));					\
+ 		  bytes_in_chunk++;					\
+ 		  break;						\
+ 		case 1:							\
+ 		  fprintf ((FILE), "\\%03o", ch);			\
+ 		  bytes_in_chunk += 4;					\
+ 		  break;						\
+ 		default:						\
+ 		  putc ('\\', (FILE));					\
+ 		  putc (escape, (FILE));				\
+ 		  bytes_in_chunk += 2;					\
+ 		  break;						\
+ 		}							\
+ 	    }								\
+ 	}								\
+       									\
+       if (bytes_in_chunk > 0)						\
+         fprintf ((FILE), "\"\n");					\
+     }									\
+   while (0)
+ 
+ 
+ /* Node: Label Output */
+ 
+ #define SET_ASM_OP	"\t.set\t"
+ 
+ #define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN)	\
+   ASM_GLOBALIZE_LABEL (FILE, XSTR (FUN, 0))
+ 
+ #define ASM_WEAKEN_LABEL(FILE, NAME) 	\
+   do					\
+     {					\
+       fputs ("\t.weak\t", (FILE));	\
+       assemble_name ((FILE), (NAME)); 	\
+       fputc ('\n', (FILE));		\
+     }					\
+   while (0)
+ 
+ #define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)	\
+   do							\
+     {							\
+       fprintf (FILE, "%s", TYPE_ASM_OP);		\
+       assemble_name (FILE, NAME);			\
+       putc (',', FILE);					\
+       fprintf (FILE, TYPE_OPERAND_FMT, "function");	\
+       putc ('\n', FILE);				\
+       							\
+       ASM_OUTPUT_LABEL(FILE, NAME);			\
+     }							\
+   while (0)
+ 
+ #define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL)		\
+   do								\
+     {								\
+       fprintf (FILE, "%s", TYPE_ASM_OP);			\
+       assemble_name (FILE, NAME);				\
+       putc (',', FILE);						\
+       fprintf (FILE, TYPE_OPERAND_FMT, "object");		\
+       putc ('\n', FILE);					\
+       								\
+       size_directive_output = 0;				\
+       								\
+       if (!flag_inhibit_size_directive				\
+ 	  && (DECL) && DECL_SIZE (DECL))			\
+ 	{							\
+ 	  size_directive_output = 1;				\
+ 	  fprintf (FILE, "%s", SIZE_ASM_OP);			\
+ 	  assemble_name (FILE, NAME);				\
+ 	  putc (',', FILE);					\
+ 	  fprintf (FILE, HOST_WIDE_INT_PRINT_DEC,		\
+ 		   int_size_in_bytes (TREE_TYPE (DECL)));	\
+ 	  fputc ('\n', FILE);					\
+ 	}							\
+       								\
+       ASM_OUTPUT_LABEL (FILE, NAME);				\
+     }								\
+   while (0)
+ 
+ #define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END)\
+   do								\
+     {								\
+       const char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0);	\
+       								\
+       if (!flag_inhibit_size_directive				\
+ 	  && DECL_SIZE (DECL)					\
+ 	  && ! AT_END && TOP_LEVEL				\
+ 	  && DECL_INITIAL (DECL) == error_mark_node		\
+ 	  && !size_directive_output)				\
+ 	{							\
+ 	  size_directive_output = 1;				\
+ 	  fprintf (FILE, "%s", SIZE_ASM_OP);			\
+ 	  assemble_name (FILE, name);				\
+ 	  putc (',', FILE);					\
+ 	  fprintf (FILE, HOST_WIDE_INT_PRINT_DEC,		\
+ 		   int_size_in_bytes (TREE_TYPE (DECL))); 	\
+ 	  fputc ('\n', FILE);					\
+ 	}							\
+     }								\
+   while (0)
+ 
+ #define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL)		\
+   do								\
+     {								\
+       if (!flag_inhibit_size_directive)				\
+ 	{							\
+ 	  char label[256];					\
+ 	  static int labelno;					\
+ 	  							\
+ 	  labelno++;						\
+ 	  							\
+ 	  ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno);	\
+ 	  ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno);	\
+ 	  							\
+ 	  fprintf (FILE, "%s", SIZE_ASM_OP);			\
+ 	  assemble_name (FILE, (FNAME));			\
+ 	  fprintf (FILE, ",");					\
+ 	  assemble_name (FILE, label);				\
+ 	  fprintf (FILE, "-");					\
+ 	  assemble_name (FILE, (FNAME));			\
+ 	  putc ('\n', FILE);					\
+ 	}							\
+     }								\
+   while (0)
+ 
+ 
+ /* Node: Alignment Output */
+ 
+ #define SKIP_ASM_OP	"\t.zero\t"
+ 
+ #undef  ASM_OUTPUT_SKIP
+ #define ASM_OUTPUT_SKIP(FILE, SIZE) \
+   fprintf (FILE, "%s%u\n", SKIP_ASM_OP, (SIZE))
+ 
+ /* Node: All Debuggers */
+ 
+ #define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+ 
+ 
+ /* Node: Misc */
+ 
+ #define HANDLE_SYSV_PRAGMA
+ 
+ /* In theory, this one isn't necessary, but over time, external tools have
+    been primed on names with "." rather than "$".  */
+ #define NO_DOLLAR_IN_LABEL
+ 
+ /* These are undocumented, but to keep a single
+    CRIS_ASM_OUTPUT_ALIGNED_DECL_COMMON, we set this to an asm that will
+    emit an error if ever output.  It will not be emitted for a.out modulo
+    careless hacking.  */
+ #define COMMON_ASM_OP	"\t.err\t"
+ #define LOCAL_ASM_OP	"\t.err\t"
+ 
+ #if defined(__CRIS__) && defined (__AOUT__) && defined (IN_GCC)
+ 
+ #define CRIS_ABI_VERSION_SYMBOL_STRING ".$CRIS_ABI_V2"
+ 
+ /* Make all a.out library functions have undefined references to the
+    .$CRIS_ABI_V2 symbol, so it will be picked up.  Used by GDB.  GDB has
+    a bug with reading a.out symbols; it does not see the GNU weak
+    extensions, so we can't have .$CRIS_ABI_V2 weak.  Weak.  */
+ __asm__ (".set .$abi_referer," CRIS_ABI_VERSION_SYMBOL_STRING);
+ #endif
+ 
+ /*
+  * Local variables:
+  * eval: (c-set-style "gnu")
+  * indent-tabs-mode: t
+  * End:
+  */
diff -cprN nothing/arit.c cris/arit.c
*** nothing/arit.c	Thu Jan  1 01:00:00 1970
--- cris/arit.c	Sat Sep 29 16:24:54 2001
***************
*** 0 ****
--- 1,302 ----
+ /* Signed and unsigned multiplication and division and modulus for CRIS.
+    Contributed by Axis Communications.
+    Written by Hans-Peter Nilsson <hp@axis.se>, c:a 1992.
+ 
+    Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+ 
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file with other programs, and to distribute
+ those programs without any restriction coming from the use of this
+ file.  (The General Public License restrictions do apply in other
+ respects; for example, they cover modification of the file, and
+ distribution when not linked into another program.)
+ 
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.  If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ 
+    As a special exception, if you link this library with files, some of
+    which are compiled with GCC, this library does not by itself cause
+    the resulting object or executable to be covered by the GNU General
+    Public License.
+    This exception does not however invalidate any other reasons why
+    the executable file or object might be covered by the GNU General
+    Public License.  */
+ 
+ 
+ /* Note that we provide prototypes for all "const" functions, to attach
+    the const attribute.  This is necessary in 2.7.2 - adding the
+    attribute to the function *definition* is a syntax error.
+     This did not work with e.g. 2.1; back then, the return type had to
+    be "const".  */
+ 
+ #include "config.h"
+ 
+ #if defined (__CRIS_arch_version) && __CRIS_arch_version >= 3
+ #define LZ(v) __extension__ \
+  ({ int tmp_; __asm__ ("lz %1,%0" : "=r" (tmp_) : "r" (v)); tmp_; })
+ #endif
+ 
+ 
+ #if defined (L_udivsi3) || defined (L_divsi3) || defined (L_umodsi3) \
+     || defined (L_modsi3)
+ /* Result type of divmod worker function.  */
+ struct quot_rem
+  {
+    long quot;
+    long rem;
+  };
+ 
+ /* This is the worker function for div and mod.  It is inlined into the
+    respective library function.  */
+ static __inline__ struct quot_rem
+ do_31div (unsigned long a, unsigned long b) __attribute__ ((__const__));
+ 
+ static __inline__ struct quot_rem
+ do_31div (unsigned long a, unsigned long b)
+ {
+   /* Adjust operands and result if a is 31 bits.  */
+   long extra = 0;
+   int quot_digits = 0;
+ 
+   if (b == 0)
+     {
+       struct quot_rem ret;
+       ret.quot = 0xffffffff;
+       ret.rem = 0xffffffff;
+       return ret;
+     }
+ 
+   if (a < b)
+     return (struct quot_rem) { 0, a };
+ 
+ #ifdef LZ
+   if (b <= a)
+     {
+       quot_digits = LZ (b) - LZ (a);
+       quot_digits += (a >= (b << quot_digits));
+       b <<= quot_digits;
+     }
+ #else
+   while (b <= a)
+     {
+       b <<= 1;
+       quot_digits++;
+     }
+ #endif
+ 
+   /* Is a 31 bits?  Note that bit 31 is handled by the caller.  */
+   if (a & 0x40000000)
+     {
+       /* Then make b:s highest bit max 0x40000000, because it must have
+ 	 been 0x80000000 to be 1 bit higher than a.  */
+       b >>= 1;
+ 
+       /* Adjust a to be maximum 0x3fffffff, i.e. two upper bits zero.  */
+       if (a >= b)
+ 	{
+ 	  a -= b;
+ 	  extra = 1 << (quot_digits - 1);
+ 	}
+       else
+ 	{
+ 	  a -= b >> 1;
+ 
+ 	  /* Remember that we adjusted a by subtracting b * 2 ** Something.  */
+ 	  extra = 1 << quot_digits;
+ 	}
+ 
+       /* The number of quotient digits will be one less, because
+ 	 we just adjusted b.  */
+       quot_digits--;
+     }
+ 
+   /* Now do the division part.  */
+ 
+   /* Subtract b and add ones to the right when a >= b
+      i.e. "a - (b - 1) == (a - b) + 1".  */
+   b--;
+ 
+ #define DS __asm__ ("dstep %2,%0" : "=r" (a) : "0" (a), "r" (b))
+ 
+   switch (quot_digits)
+     {
+     case 32: DS; case 31: DS; case 30: DS; case 29: DS;
+     case 28: DS; case 27: DS; case 26: DS; case 25: DS;
+     case 24: DS; case 23: DS; case 22: DS; case 21: DS;
+     case 20: DS; case 19: DS; case 18: DS; case 17: DS;
+     case 16: DS; case 15: DS; case 14: DS; case 13: DS;
+     case 12: DS; case 11: DS; case 10: DS; case 9: DS;
+     case 8: DS; case 7: DS; case 6: DS; case 5: DS;
+     case 4: DS; case 3: DS; case 2: DS; case 1: DS;
+     case 0:;
+     }
+ 
+   {
+     struct quot_rem ret;
+     ret.quot = (a & ((1 << quot_digits) - 1)) + extra;
+     ret.rem = a >> quot_digits;
+     return ret;
+   }
+ }
+ 
+ /* Note that unsigned and signed division both build when L_divsi3, but
+    the unsigned variant is then inlined, as with do_31div above.  */
+ #if defined (L_udivsi3) || defined (L_divsi3)
+ #ifndef L_udivsi3
+ static __inline__
+ #endif
+ unsigned long
+ __Udiv (unsigned long a, unsigned long b) __attribute__ ((__const__));
+ 
+ #ifndef L_udivsi3
+ static __inline__
+ #endif
+ unsigned long
+ __Udiv (unsigned long a, unsigned long b)
+ {
+   long extra = 0;
+ 
+   /* Adjust operands and result, if a and/or b is 32 bits.  */
+   /* Effectively: b & 0x80000000.  */
+   if ((long) b < 0)
+     return a >= b;
+ 
+   /* Effectively: a & 0x80000000.  */
+   if ((long) a < 0)
+     {
+       int tmp = 0;
+ 
+       if (b == 0)
+ 	return 0xffffffff;
+ #ifdef LZ
+       tmp = LZ (b);
+ #else
+       for (tmp = 31; (((long) b & (1 << tmp)) == 0); tmp--)
+ 	;
+ 
+       tmp = 31 - tmp;
+ #endif
+ 
+       if ((b << tmp) > a)
+ 	{
+ 	  extra = 1 << (tmp-1);
+ 	  a -= b << (tmp - 1);
+ 	}
+       else
+ 	{
+ 	  extra = 1 << tmp;
+ 	  a -= b << tmp;
+ 	}
+     }
+ 
+   return do_31div (a, b).quot+extra;
+ }
+ 
+ 
+ #ifdef L_divsi3
+ long
+ __Div (long a, long b) __attribute__ ((__const__));
+ 
+ long
+ __Div (long a, long b)
+ {
+   long sign;
+   long result;
+ 
+   /* Do *not* call do_31div since abs (-2147483648) == 2147483648
+      <=> abs (-0x80000000) == 0x80000000
+      which is still 32 bits.  */
+ 
+   sign = a ^ b;
+   result = __Udiv (abs (a), abs (b));
+ 
+   return  (sign < 0) ? -result : result;
+ }
+ #endif /* L_divsi3 */
+ #endif /* L_udivsi3 || L_divsi3 */
+ 
+ 
+ /* Note that unsigned and signed modulus both build when L_modsi3, but
+    then the unsigned variant is inlined, as with do_31div above.  */
+ #if defined (L_umodsi3) || defined (L_modsi3)
+ #ifndef L_umodsi3
+ static __inline__
+ #endif
+ unsigned long
+ __Umod (unsigned long a, unsigned long b) __attribute__ ((__const__));
+ 
+ #ifndef L_umodsi3
+ static __inline__
+ #endif
+ unsigned long
+ __Umod (unsigned long a, unsigned long b)
+ {
+   /* Adjust operands and result if a and/or b is 32 bits.  */
+   if ((long) b < 0)
+     return a >= b ? a - b : a;
+ 
+   if ((long) a < 0)
+     {
+       int tmp = 0;
+ 
+       if (b == 0)
+ 	return a;
+ #ifdef LZ
+       tmp = LZ (b);
+ #else
+       for (tmp = 31; (((long) b & (1 << tmp)) == 0); tmp--)
+ 	;
+       tmp = 31 - tmp;
+ #endif
+ 
+       if ((b << tmp) > a)
+ 	{
+ 	  a -= b << (tmp - 1);
+ 	}
+       else
+ 	{
+ 	  a -= b << tmp;
+ 	}
+     }
+ 
+   return do_31div (a, b).rem;
+ }
+ 
+ #ifdef L_modsi3
+ long
+ __Mod (long a, long b) __attribute__ ((__const__));
+ 
+ long
+ __Mod (long a, long b)
+ {
+   long	result;
+ 
+   result = __Umod (abs (a), abs (b));
+ 
+   return (a < 0) ? -result : result;
+ }
+ #endif /* L_modsi3 */
+ #endif /* L_umodsi3 || L_modsi3 */
+ #endif /* L_udivsi3 || L_divsi3 || L_umodsi3 || L_modsi3 */
+ 
+ /*
+  * Local variables:
+  * eval: (c-set-style "gnu")
+  * indent-tabs-mode: t
+  * End:
+  */
diff -cprN nothing/cris_abi_symbol.c cris/cris_abi_symbol.c
*** nothing/cris_abi_symbol.c	Thu Jan  1 01:00:00 1970
--- cris/cris_abi_symbol.c	Sat Sep 29 16:27:43 2001
***************
*** 0 ****
--- 1,56 ----
+ /* Define symbol to recognize CRIS ABI version 2, for a.out use.
+    Contributed by Axis Communications.
+    Written by Hans-Peter Nilsson <hp@axis.se>, c:a 1992.
+ 
+    Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+ 
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file with other programs, and to distribute
+ those programs without any restriction coming from the use of this
+ file.  (The General Public License restrictions do apply in other
+ respects; for example, they cover modification of the file, and
+ distribution when not linked into another program.)
+ 
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.  If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ 
+    As a special exception, if you link this library with files, some of
+    which are compiled with GCC, this library does not by itself cause
+    the resulting object or executable to be covered by the GNU General
+    Public License.
+    This exception does not however invalidate any other reasons why
+    the executable file or object might be covered by the GNU General
+    Public License.  */
+ 
+ #include "config.h"
+ 
+ #ifdef __AOUT__
+ 
+ /* ELF support was not released before the ABI was changed, so we
+    restrict this awkwardness to a.out.  This symbol is for gdb to
+    recognize, so it can debug both old and new programs successfully.  */
+ __asm__ (".global " CRIS_ABI_VERSION_SYMBOL_STRING);
+ __asm__ (".set " CRIS_ABI_VERSION_SYMBOL_STRING ",0");
+ 
+ #else  /* not __AOUT__ */
+ 
+ /* The file must not be empty (declaration/definition-wise) according to
+    ISO, IIRC. */
+ extern int _Dummy;
+ 
+ #endif /* not __AOUT__ */
diff -cprN nothing/mulsi3.asm cris/mulsi3.asm
*** nothing/mulsi3.asm	Thu Jan  1 01:00:00 1970
--- cris/mulsi3.asm	Mon Sep 24 17:24:41 2001
***************
*** 0 ****
--- 1,227 ----
+ ;; This code used to be expanded through interesting expansions in
+ ;; the machine description, compiled from this code:
+ ;;
+ ;; #ifdef L_mulsi3
+ ;; long __Mul (unsigned long a, unsigned long b) __attribute__ ((__const__));
+ ;; 
+ ;; /* This must be compiled with the -mexpand-mul flag, to synthesize the
+ ;;    multiplication from the mstep instructions.  The check for
+ ;;    smaller-size multiplication pays off in the order of .5-10%;
+ ;;    estimated median 1%, depending on application.
+ ;;     FIXME: It can be further optimized if we go to assembler code, as
+ ;;    gcc 2.7.2 adds a few unnecessary instructions and does not put the
+ ;;    basic blocks in optimal order.  */
+ ;; long
+ ;; __Mul (unsigned long a, unsigned long b)
+ ;; {
+ ;; #if defined (__CRIS_arch_version) && __CRIS_arch_version >= 10
+ ;;   /* In case other code is compiled without -march=v10, they will
+ ;; 	contain calls to __Mul, regardless of flags at link-time.  The
+ ;; 	"else"-code below will work, but is unnecessarily slow.  This
+ ;; 	sometimes cuts a few minutes off from simulation time by just
+ ;; 	returning a "mulu.d".  */
+ ;;   return a * b;
+ ;; #else
+ ;;   unsigned long min;
+ ;; 
+ ;;   /* Get minimum via the bound insn.  */
+ ;;   min = a < b ? a : b;
+ ;; 
+ ;;   /* Can we omit computation of the high part?	*/
+ ;;   if (min > 65535)
+ ;;     /* No.  Perform full multiplication.  */
+ ;;     return a * b;
+ ;;   else
+ ;;     {
+ ;; 	 /* Check if both operands are within 16 bits.  */
+ ;; 	 unsigned long max;
+ ;; 
+ ;; 	 /* Get maximum, by knowing the minimum.
+ ;; 	    This will partition a and b into max and min.
+ ;; 	    This is not currently something GCC understands,
+ ;; 	    so do this trick by asm.  */
+ ;; 	 __asm__ ("xor %1,%0\n\txor %2,%0"
+ ;; 		  : "=r" (max)
+ ;; 		  :  "r" (b), "r" (a), "0" (min));
+ ;; 
+ ;;     if (max > 65535)
+ ;; 	 /* Make GCC understand that only the low part of "min" will be
+ ;; 	    used.  */
+ ;; 	 return max * (unsigned short) min;
+ ;;     else
+ ;; 	 /* Only the low parts of both operands are necessary.  */
+ ;; 	 return ((unsigned short) max) * (unsigned short) min;
+ ;;     }
+ ;; #endif /* not __CRIS_arch_version >= 10 */
+ ;; }
+ ;; #endif /* L_mulsi3 */
+ ;;
+ ;; That approach was abandoned since the caveats outweighted the
+ ;; benefits.  The expand-multiplication machinery is also removed, so you
+ ;; can't do this anymore.
+ ;;
+ ;; For doubters of there being any benefits, some where: insensitivity to:
+ ;; - ABI changes (mostly for experimentation)
+ ;; - assembler syntax differences (mostly debug format).
+ ;; - insn scheduling issues.
+ ;; Most ABI experiments will presumably happen with arches with mul insns,
+ ;; so that argument doesn't really hold anymore, and it's unlikely there
+ ;; being new arch variants needing insn scheduling and not having mul
+ ;; insns.
+ 
+ ;; ELF and a.out have different syntax for local labels: the "wrong"
+ ;; one may not be omitted from the object.
+ #undef L
+ #ifdef __AOUT__
+ # define L(x) x
+ #else
+ # define L(x) .x
+ #endif
+ 
+ 	.global ___Mul
+ 	.type	___Mul,@function
+ ___Mul:
+ #if defined (__CRIS_arch_version) && __CRIS_arch_version >= 10
+ 	ret
+ 	mulu.d $r11,$r10
+ #else
+ 	move.d $r10,$r12
+ 	move.d $r11,$r9
+ 	bound.d $r12,$r9
+ 	cmpu.w 65535,$r9
+ 	bls L(L3)
+ 	move.d $r12,$r13
+ 
+ 	movu.w $r11,$r9
+ 	lslq 16,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	mstep $r9,$r13
+ 	clear.w $r10
+ 	test.d $r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	movu.w $r12,$r12
+ 	move.d $r11,$r9
+ 	clear.w $r9
+ 	test.d $r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	mstep $r12,$r9
+ 	add.w $r9,$r10
+ 	lslq 16,$r10
+ 	ret
+ 	add.d $r13,$r10
+ 
+ L(L3):
+ 	move.d $r9,$r10
+ 	xor $r11,$r10
+ 	xor $r12,$r10
+ 	cmpu.w 65535,$r10
+ 	bls L(L5)
+ 	movu.w $r9,$r13
+ 
+ 	movu.w $r13,$r13
+ 	move.d $r10,$r9
+ 	lslq 16,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	mstep $r13,$r9
+ 	clear.w $r10
+ 	test.d $r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	mstep $r13,$r10
+ 	lslq 16,$r10
+ 	ret
+ 	add.d $r9,$r10
+ 
+ L(L5):
+ 	movu.w $r9,$r9
+ 	lslq 16,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	mstep $r9,$r10
+ 	ret
+ 	mstep $r9,$r10
+ #endif
+ L(Lfe1):
+ 	.size	___Mul,L(Lfe1)-___Mul
diff -cprN nothing/t-aout cris/t-aout
*** nothing/t-aout	Thu Jan  1 01:00:00 1970
--- cris/t-aout	Sat Sep 22 12:30:58 2001
***************
*** 0 ****
--- 1,12 ----
+ LIB2FUNCS_STATIC_EXTRA = \
+  tmpabi_symbol.c $(srcdir)/config/cris/mulsi3.asm
+ 
+ MULTILIB_OPTIONS = melinux
+ MULTILIB_DIRNAMES = elinux
+ MULTILIB_EXTRA_OPTS = mbest-lib-options
+ 
+ INSTALL_LIBGCC = install-multilib
+ LIBGCC = stmp-multilib
+ 
+ tmpabi_symbol.c: $(srcdir)/config/cris/cris_abi_symbol.c
+ 	cp $(srcdir)/config/cris/cris_abi_symbol.c $@
diff -cprN nothing/t-cris cris/t-cris
*** nothing/t-cris	Thu Jan  1 01:00:00 1970
--- cris/t-cris	Sat Sep 29 16:26:47 2001
***************
*** 0 ****
--- 1,43 ----
+ #
+ # t-cris
+ #
+ # The Makefile fragment to include when compiling gcc et al for CRIS.
+ #
+ #
+ # The makefile macros etc. are included in the order found in the
+ # section "Target Fragment" in the gcc info-files (or the paper copy) of
+ # "Using and Porting GCC"
+ #
+ # Don't run fixproto
+ STMP_FIXPROTO =
+ 
+ LIB2FUNCS_EXTRA = _udivsi3.c _divsi3.c _umodsi3.c _modsi3.c
+ CRIS_LIB1CSRC = $(srcdir)/config/cris/arit.c
+ 
+ FPBIT = tmplibgcc_fp_bit.c
+ DPBIT = dp-bit.c
+ 
+ dp-bit.c: $(srcdir)/config/fp-bit.c
+ 	echo '#define FLOAT_BIT_ORDER_MISMATCH' > dp-bit.c
+ 	cat $(srcdir)/config/fp-bit.c           >> dp-bit.c
+ 
+ # Use another name to avoid confusing SUN make, if support for
+ # it is reinstated elsewhere.  Prefixed with "tmplibgcc" means
+ # "make clean" will wipe it.  We define a few L_ thingies
+ # because we can't select them individually through FPBIT_FUNCS;
+ # see above.
+ tmplibgcc_fp_bit.c: $(srcdir)/config/fp-bit.c
+ 	echo '#define FLOAT_BIT_ORDER_MISMATCH' >  $@
+ 	echo '#define FLOAT'			>> $@
+ 	cat $(srcdir)/config/fp-bit.c		>> $@
+ 
+ # The fixed-point arithmetic code is in one file, arit.c,
+ # similar to libgcc2.c (or the old libgcc1.c).  We need to
+ # "split it up" with one file per define.
+ $(LIB2FUNCS_EXTRA): $(CRIS_LIB1CSRC)
+ 	name=`echo $@ | sed -e 's,.*/,,' | sed -e 's,.c$$,,'`; \
+ 	echo "#define L$$name" > tmp-$@ \
+ 	&& echo '#include "$<"' >> tmp-$@ \
+ 	&& mv -f tmp-$@ $@
+ 
+ TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc
diff -cprN nothing/t-elfmulti cris/t-elfmulti
*** nothing/t-elfmulti	Thu Jan  1 01:00:00 1970
--- cris/t-elfmulti	Sat Sep 29 02:46:23 2001
***************
*** 0 ****
--- 1,16 ----
+ LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/cris/mulsi3.asm
+ EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o
+ MULTILIB_OPTIONS = march=v10
+ MULTILIB_DIRNAMES = v10
+ MULTILIB_MATCHES = \
+ 		march?v10=mcpu?etrax100lx \
+ 		march?v10=mcpu?ng \
+ 		march?v10=march?etrax100lx \
+ 		march?v10=march?ng \
+ 		march?v10=march?v11 \
+ 		march?v10=mcpu?v11 \
+ 		march?v10=mcpu?v10
+ MULTILIB_EXTRA_OPTS = mbest-lib-options
+ INSTALL_LIBGCC = install-multilib
+ LIBGCC = stmp-multilib
+ CRTSTUFF_T_CFLAGS = $(LIBGCC2_CFLAGS) -moverride-best-lib-options
diff -cprN nothing/t-linux cris/t-linux
*** nothing/t-linux	Thu Jan  1 01:00:00 1970
--- cris/t-linux	Mon Sep 24 06:56:08 2001
***************
*** 0 ****
--- 1,6 ----
+ TARGET_LIBGCC2_CFLAGS += -fPIC
+ CRTSTUFF_T_CFLAGS_S = $(TARGET_LIBGCC2_CFLAGS)
+ 
+ # Override t-slibgcc-elf-ver to export some libgcc symbols with
+ # the symbol versions that glibc used.
+ SHLIB_MAPFILES += $(srcdir)/config/libgcc-glibc.ver

brgds, H-P


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]