Add the FRV port
authorBernd Schmidt <bernds@redhat.com>
Sun, 4 Aug 2002 19:37:03 +0000 (19:37 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Sun, 4 Aug 2002 19:37:03 +0000 (19:37 +0000)
From-SVN: r56029

23 files changed:
gcc/ChangeLog
gcc/config.gcc
gcc/config/frv/cmovd.c [new file with mode: 0644]
gcc/config/frv/cmovh.c [new file with mode: 0644]
gcc/config/frv/cmovw.c [new file with mode: 0644]
gcc/config/frv/frv-abi.h [new file with mode: 0644]
gcc/config/frv/frv-asm.h [new file with mode: 0644]
gcc/config/frv/frv-modes.def [new file with mode: 0644]
gcc/config/frv/frv-protos.h [new file with mode: 0644]
gcc/config/frv/frv.c [new file with mode: 0644]
gcc/config/frv/frv.h [new file with mode: 0644]
gcc/config/frv/frv.md [new file with mode: 0644]
gcc/config/frv/frvbegin.c [new file with mode: 0644]
gcc/config/frv/frvend.c [new file with mode: 0644]
gcc/config/frv/lib1funcs.asm [new file with mode: 0644]
gcc/config/frv/media.h [new file with mode: 0644]
gcc/config/frv/modi.c [new file with mode: 0644]
gcc/config/frv/uitod.c [new file with mode: 0644]
gcc/config/frv/uitof.c [new file with mode: 0644]
gcc/config/frv/ulltod.c [new file with mode: 0644]
gcc/config/frv/ulltof.c [new file with mode: 0644]
gcc/config/frv/umodi.c [new file with mode: 0644]
gcc/config/frv/xm-frv.h [new file with mode: 0644]

index 766d1bc..7680b13 100644 (file)
@@ -1,3 +1,31 @@
+2002-08-04  Bernd Schmidt  <bernds@redhat.com>
+
+       Contribute a port developed primarily by Michael Meissner,
+       Catherine Moore, and Richard Sandiford <rsandifo@redhat.com>.
+       * config.gcc: Add frv-elf target.
+       * config/frv/cmovd.c: New file.
+       * config/frv/cmovh.c: New file.
+       * config/frv/cmovw.c: New file.
+       * config/frv/frv-abi.h: New file.
+       * config/frv/frv-asm.h: New file.
+       * config/frv/frv-modes.def: New file.
+       * config/frv/frv-protos.h: New file.
+       * config/frv/frv.c: New file.
+       * config/frv/frv.h: New file.
+       * config/frv/frv.md: New file.
+       * config/frv/frvbegin.c: New file.
+       * config/frv/frvend.c: New file.
+       * config/frv/lib1funcs.asm: New file.
+       * config/frv/media.h: New file.
+       * config/frv/modi.c: New file.
+       * config/frv/t-frv: New file.
+       * config/frv/uitod.c: New file.
+       * config/frv/uitof.c: New file.
+       * config/frv/ulltod.c: New file.
+       * config/frv/ulltof.c: New file.
+       * config/frv/umodi.c: New file.
+       * config/frv/xm-frv.h: New file.
+               
 2002-08-04  Nathan Sidwell  <nathan@codesourcery.com>
 
        * gcov.c (bb_file_time): New static variable.
index a8fd079..5b8e6ea 100644 (file)
@@ -717,6 +717,10 @@ fr30-*-elf)
        tmake_file=fr30/t-fr30
        extra_parts="crti.o crtn.o crtbegin.o crtend.o"
        ;;
+frv-*-elf)
+       tm_file="dbxelf.h elfos.h svr4.h ${tm_file} frv/frv-abi.h"
+       tmake_file=frv/t-frv
+       ;;
 h8300-*-rtems*)
        xm_defines=POSIX
        tmake_file="h8300/t-h8300 t-rtems"
diff --git a/gcc/config/frv/cmovd.c b/gcc/config/frv/cmovd.c
new file mode 100644 (file)
index 0000000..11b50ba
--- /dev/null
@@ -0,0 +1,47 @@
+/* Move double-word library function.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   Contributed by Red Hat, Inc.
+  
+   This file is part of GNU CC.
+  
+   GNU CC is free software ; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation * either version 2, or (at your option)
+   any later version.
+  
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY ; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+  
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+void
+__cmovd (long long *dest, const long long *src, unsigned len)
+{
+  unsigned i;
+  unsigned num = len >> 3;
+  unsigned xlen = len & ~7;
+  char *dest_byte = (char *)dest;
+  const char *src_byte = (const char *)src;
+
+  if (dest_byte < src_byte || dest_byte > src_byte+len)
+    {
+      for (i = 0; i < num; i++)
+       dest[i] = src[i];
+
+      while (len > xlen)
+       {
+         dest_byte[xlen] = src_byte[xlen];
+         xlen++;
+       }
+    }
+  else
+    {
+      while (len-- > 0)
+       dest_byte[len] = src_byte[len];
+    }
+}
diff --git a/gcc/config/frv/cmovh.c b/gcc/config/frv/cmovh.c
new file mode 100644 (file)
index 0000000..018a0b4
--- /dev/null
@@ -0,0 +1,43 @@
+/* Move half-word library function.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   Contributed by Red Hat, Inc.
+  
+   This file is part of GNU CC.
+  
+   GNU CC is free software ; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation * either version 2, or (at your option)
+   any later version.
+  
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY ; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+  
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+void
+__cmovh (short *dest, const short *src, unsigned len)
+{
+  unsigned i;
+  unsigned num = len >> 1;
+  char *dest_byte = (char *)dest;
+  const char *src_byte = (const char *)src;
+
+  if (dest_byte < src_byte || dest_byte > src_byte+len)
+    {
+      for (i = 0; i < num; i++)
+       dest[i] = src[i];
+
+      if ((len & 1) != 0)
+       dest_byte[len-1] = src_byte[len-1];
+    }
+  else
+    {
+      while (len-- > 0)
+       dest_byte[len] = src_byte[len];
+    }
+}
diff --git a/gcc/config/frv/cmovw.c b/gcc/config/frv/cmovw.c
new file mode 100644 (file)
index 0000000..5509e06
--- /dev/null
@@ -0,0 +1,47 @@
+/* Move word library function.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   Contributed by Red Hat, Inc.
+  
+   This file is part of GNU CC.
+  
+   GNU CC is free software ; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation * either version 2, or (at your option)
+   any later version.
+  
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY ; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+  
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+void
+__cmovw (int *dest, const int *src, unsigned len)
+{
+  unsigned i;
+  unsigned num = len >> 2;
+  unsigned xlen = len & ~3;
+  char *dest_byte = (char *)dest;
+  const char *src_byte = (const char *)src;
+
+  if (dest_byte < src_byte || dest_byte > src_byte+len)
+    {
+      for (i = 0; i < num; i++)
+       dest[i] = src[i];
+
+      while (len > xlen)
+       {
+         dest_byte[xlen] = src_byte[xlen];
+         xlen++;
+       }
+    }
+  else
+    {
+      while (len-- > 0)
+       dest_byte[len] = src_byte[len];
+    }
+}
diff --git a/gcc/config/frv/frv-abi.h b/gcc/config/frv/frv-abi.h
new file mode 100644 (file)
index 0000000..68fd32f
--- /dev/null
@@ -0,0 +1,181 @@
+/* Frv map GCC names to FR-V ABI.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   Contributed by Red Hat, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* For each of the functions in the library that has a corresponding name in
+   the ABI, add an equivalence between the GCC name and the ABI name.  This is
+   in a separate file from frv.h so that fp-bit.c can be made to include it.  */
+
+#ifdef __GNUC__
+#ifdef __FRV_UNDERSCORE__
+#define RENAME_LIBRARY(OLD,NEW)                                                \
+__asm__ (".globl\t_" #NEW "\n"                                         \
+        "_" #NEW "=_" #OLD "\n"                                        \
+        "\t.type\t_" #NEW ",@function\n");
+
+#else
+#define RENAME_LIBRARY(OLD,NEW)                                                \
+__asm__ (".globl\t" #NEW "\n"                                          \
+        #NEW "=" #OLD "\n"                                             \
+        "\t.type\t" #NEW ",@function\n");
+#endif
+
+#define CREATE_DOUBLE_SHIFT(OLD,NEW)                                   \
+__asm__ (".text\n"                                                     \
+        "\t.globl\t" #NEW "\n"                                         \
+        "\t.type\t" #NEW ",@function\n"                                \
+        #NEW ":\n"                                                     \
+        "\tor\tgr11, gr0, gr10\n"                                      \
+        "\tbra\t" #OLD "\n");
+
+#ifdef L_sf_to_df
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__extendsfdf2,__ftod)
+#endif
+
+#ifdef L_sf_to_si
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__fixsfsi,__ftoi)
+#endif
+
+#ifdef L_sf_to_usi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__fixunssfsi,__ftoui)
+#endif
+
+#ifdef L_df_to_si
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__fixdfsi,__dtoi)
+#endif
+
+#ifdef L_fixunssfsi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__fixunssfsi,__ftoui)
+#endif
+
+#ifdef L_fixunsdfsi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__fixunsdfsi,__dtoui)
+#endif
+
+#ifdef L_fixsfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__fixsfdi,__ftoll)
+#endif
+
+#ifdef L_fixdfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__fixdfdi,__dtoll)
+#endif
+
+#ifdef L_fixunssfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__fixunssfdi,__ftoull)
+#endif
+
+#ifdef L_fixunsdfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__fixunsdfdi,__dtoull)
+#endif
+
+#ifdef L_si_to_sf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__floatsisf,__itof)
+#endif
+
+#ifdef L_di_to_sf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__floatdisf,__lltof)
+#endif
+
+#ifdef L_df_to_sf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__truncdfsf2,__dtof)
+#endif
+
+#ifdef L_si_to_df
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__floatsidf,__itod)
+#endif
+
+#ifdef L_floatdisf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__floatdisf,__lltof)
+#endif
+
+#ifdef L_floatdidf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__floatdidf,__lltod)
+#endif
+
+#ifdef L_addsub_df
+#define DECLARE_LIBRARY_RENAMES \
+       RENAME_LIBRARY(__adddf3,__addd)
+       RENAME_LIBRARY(__subdf3,__subd)
+#endif
+
+#ifdef L_mul_df
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__muldf3,__muld)
+#endif
+
+#ifdef L_div_df
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__divdf3,__divd)
+#endif
+
+#ifdef L_addsub_sf
+#define DECLARE_LIBRARY_RENAMES \
+       RENAME_LIBRARY(__addsf3,__addf) \
+       RENAME_LIBRARY(__subsf3,__subf)
+#endif
+
+#ifdef L_mul_sf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__mulsf3,__mulf)
+#endif
+
+#ifdef L_div_sf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__divsf3,__divf)
+#endif
+
+#ifdef L_ashldi3
+#define DECLARE_LIBRARY_RENAMES CREATE_DOUBLE_SHIFT (__ashldi3,__sllll)
+#endif
+
+#ifdef L_lshrdi3
+#define DECLARE_LIBRARY_RENAMES CREATE_DOUBLE_SHIFT (__lshrdi3,__srlll)
+#endif
+
+#ifdef L_ashrdi3
+#define DECLARE_LIBRARY_RENAMES CREATE_DOUBLE_SHIFT (__ashrdi3,__srall)
+#endif
+
+#ifdef L_adddi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__adddi3,__addll)
+#endif
+
+#ifdef L_subdi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__subdi3,__subll)
+#endif
+
+#ifdef L_muldi3
+#define DECLARE_LIBRARY_RENAMES \
+       RENAME_LIBRARY(__muldi3,__mulll)
+       RENAME_LIBRARY(__muldi3,__umulll)
+#endif
+
+#ifdef L_divdi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__divdi3,__divll)
+#endif
+
+#ifdef L_udivdi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__udivdi3,__udivll)
+#endif
+
+#ifdef L_moddi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__moddi3,__modll)
+#endif
+
+#ifdef L_umoddi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__umoddi3,__umodll)
+#endif
+#endif /* __GNUC__ */
diff --git a/gcc/config/frv/frv-asm.h b/gcc/config/frv/frv-asm.h
new file mode 100644 (file)
index 0000000..e8447a6
--- /dev/null
@@ -0,0 +1,49 @@
+/* Assembler Support.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   Contributed by Red Hat, Inc.
+  
+   This file is part of GNU CC.
+  
+   GNU CC is free software ; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation * either version 2, or (at your option)
+   any later version.
+  
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY ; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+  
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* P(INSN): Emit INSN.P for VLIW machines, otherwise emit plain INSN.
+   P2(INSN): Emit INSN.P on the FR500 and above, otherwise emit plain INSN.  */
+#ifdef __FRV_VLIW__
+#ifdef __STDC__
+#define P(A) A##.p
+#else
+#define P(A) A/**/.p
+#endif
+#if __FRV_VLIW__ > 2
+#define P2(A) P(A)
+#else
+#define P2(A) A
+#endif
+#else
+#define P(A) A
+#define P2(A) A
+#endif
+
+/* Add underscore if necessary to external name.  */
+#ifdef __FRV_UNDERSCORE__
+#ifdef __STDC__
+#define EXT(NAME) _##NAME
+#else
+#define EXT(NAME) _/**/NAME
+#endif
+#else
+#define EXT(NAME) NAME
+#endif
diff --git a/gcc/config/frv/frv-modes.def b/gcc/config/frv/frv-modes.def
new file mode 100644 (file)
index 0000000..ca7818c
--- /dev/null
@@ -0,0 +1,30 @@
+/* Definitions of target machine for GNU compiler for FRV.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* On the FRV, the CC modes used are:
+
+   CCmode      set ICC's from comparing signed integers
+   CC_UNSmode  set ICC's from comparing unsigned integers
+   CC_FPmode   set FCC's from comparing floating point
+   CC_CCRmode  set CCR's to do conditional execution */
+
+CC (CC_UNS)
+CC (CC_FP)
+CC (CC_CCR)
diff --git a/gcc/config/frv/frv-protos.h b/gcc/config/frv/frv-protos.h
new file mode 100644 (file)
index 0000000..d00a9b8
--- /dev/null
@@ -0,0 +1,266 @@
+/* Frv prototypes.
+   Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by Red Hat, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Define the information needed to generate branch and scc insns.  This is
+   stored from the compare operation.  Note that we can't use "rtx" here
+   since it hasn't been defined!  */
+
+/* Define global data defined in frv.c */
+extern const char *frv_branch_cost_string;     /* -mbranch-cost option */
+extern int frv_branch_cost_int;                        /* value of -mbranch_cost */
+
+extern const char *frv_cpu_string;             /* -mcpu= option */
+
+extern const char *frv_condexec_insns_str;     /* -mcond-exec-insns= option */
+extern int frv_condexec_insns;                 /* value of -mcond-exec-insns */
+
+extern const char *frv_condexec_temps_str;     /* -mcond-exec-temps= option */
+extern int frv_condexec_temps;                 /* value of -mcond-exec-temps */
+
+extern const char *frv_sched_lookahead_str;    /* -msched-lookahead= option */
+extern int frv_sched_lookahead;                        /* value -msched-lookahead= */
+
+/* CPU type.  This must be identical to the cpu enumeration in frv.md.  */
+typedef enum frv_cpu
+{
+  FRV_CPU_GENERIC,
+  FRV_CPU_FR500,
+  FRV_CPU_FR400,
+  FRV_CPU_FR300,
+  FRV_CPU_SIMPLE,
+  FRV_CPU_TOMCAT
+} frv_cpu_t;
+
+extern frv_cpu_t frv_cpu_type;                 /* value of -mcpu= */
+
+/* Define functions defined in frv.c */
+extern void frv_expand_prologue                        PARAMS ((void));
+extern void frv_expand_epilogue                        PARAMS ((int));
+extern void frv_override_options               PARAMS ((void));
+extern void frv_optimization_options           PARAMS ((int, int));
+extern void frv_conditional_register_usage     PARAMS ((void));
+extern frv_stack_t *frv_stack_info             PARAMS ((void));
+extern void frv_debug_stack                    PARAMS ((frv_stack_t *));
+extern int frv_frame_pointer_required          PARAMS ((void));
+extern int frv_initial_elimination_offset      PARAMS ((int, int));
+
+#ifdef RTX_CODE
+extern int frv_legitimate_address_p            PARAMS ((enum machine_mode, rtx,
+                                                      int, int));
+extern rtx frv_legitimize_address              PARAMS ((rtx, rtx,
+                                                        enum machine_mode));
+
+#ifdef TREE_CODE
+extern void frv_init_builtins PARAMS ((void));
+extern rtx frv_expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int));
+
+extern void frv_init_cumulative_args           PARAMS ((CUMULATIVE_ARGS *, tree,
+                                                      rtx, int, int));
+
+extern int frv_function_arg_boundary           PARAMS ((enum machine_mode, tree));
+extern rtx frv_function_arg                    PARAMS ((CUMULATIVE_ARGS *,
+                                                      enum machine_mode,
+                                                      tree, int, int));
+
+extern void frv_function_arg_advance           PARAMS ((CUMULATIVE_ARGS *,
+                                                      enum machine_mode,
+                                                      tree, int));
+
+extern int frv_function_arg_partial_nregs      PARAMS ((CUMULATIVE_ARGS *,
+                                                      enum machine_mode,
+                                                      tree, int));
+
+extern int frv_function_arg_pass_by_reference  PARAMS ((CUMULATIVE_ARGS *,
+                                                      enum machine_mode,
+                                                      tree, int));
+
+extern int frv_function_arg_callee_copies      PARAMS ((CUMULATIVE_ARGS *,
+                                                      enum machine_mode,
+                                                      tree, int));
+
+extern int frv_function_arg_keep_as_reference  PARAMS ((CUMULATIVE_ARGS *,
+                                                      enum machine_mode,
+                                                      tree, int));
+
+extern rtx frv_expand_builtin_saveregs         PARAMS ((void));
+extern void frv_setup_incoming_varargs         PARAMS ((CUMULATIVE_ARGS *,
+                                                        enum machine_mode,
+                                                        tree, int *, int));
+
+extern void frv_expand_builtin_va_start                PARAMS ((tree, rtx));
+extern rtx frv_expand_builtin_va_arg           PARAMS ((tree, tree));
+#endif /* TREE_CODE */
+
+extern int frv_expand_block_move               PARAMS ((rtx *));
+extern int frv_expand_block_clear              PARAMS ((rtx *));
+extern rtx frv_dynamic_chain_address           PARAMS ((rtx));
+extern rtx frv_return_addr_rtx                 PARAMS ((int, rtx));
+extern rtx frv_index_memory                    PARAMS ((rtx,
+                                                        enum machine_mode,
+                                                        int));
+
+#ifdef TREE_CODE
+extern void frv_asm_output_mi_thunk            PARAMS ((FILE *, tree, long,
+                                                        tree));
+#endif /* TREE_CODE */
+
+extern const char *frv_asm_output_opcode
+                                       PARAMS ((FILE *, const char *));
+extern void frv_final_prescan_insn     PARAMS ((rtx, rtx *, int));
+extern void frv_print_operand          PARAMS ((FILE *, rtx, int));
+extern void frv_print_operand_address  PARAMS ((FILE *, rtx));
+extern int frv_emit_movsi              PARAMS ((rtx, rtx));
+extern const char *output_move_single  PARAMS ((rtx *, rtx));
+extern const char *output_move_double  PARAMS ((rtx *, rtx));
+extern const char *output_condmove_single
+                                       PARAMS ((rtx *, rtx));
+extern int frv_emit_cond_branch                PARAMS ((enum rtx_code, rtx));
+extern int frv_emit_scc                        PARAMS ((enum rtx_code, rtx));
+extern rtx frv_split_scc               PARAMS ((rtx, rtx, rtx, rtx,
+                                                HOST_WIDE_INT));
+extern int frv_emit_cond_move          PARAMS ((rtx, rtx, rtx, rtx));
+extern rtx frv_split_cond_move         PARAMS ((rtx *));
+extern rtx frv_split_minmax            PARAMS ((rtx *));
+extern rtx frv_split_abs               PARAMS ((rtx *));
+extern void frv_split_double_load      PARAMS ((rtx, rtx));
+extern void frv_split_double_store     PARAMS ((rtx, rtx));
+#ifdef BLOCK_HEAD
+extern void frv_ifcvt_init_extra_fields        PARAMS ((ce_if_block_t *));
+extern void frv_ifcvt_modify_tests     PARAMS ((ce_if_block_t *,
+                                                rtx *, rtx *));
+extern void frv_ifcvt_modify_multiple_tests
+                                       PARAMS ((ce_if_block_t *,
+                                                basic_block,
+                                                rtx *, rtx *));
+extern rtx frv_ifcvt_modify_insn       PARAMS ((ce_if_block_t *,
+                                                rtx, rtx));
+extern void frv_ifcvt_modify_final     PARAMS ((ce_if_block_t *));
+extern void frv_ifcvt_modify_cancel    PARAMS ((ce_if_block_t *));
+#endif
+extern int frv_trampoline_size         PARAMS ((void));
+extern void frv_initialize_trampoline  PARAMS ((rtx, rtx, rtx));
+extern enum reg_class frv_secondary_reload_class
+                                       PARAMS ((enum reg_class class,
+                                              enum machine_mode mode,
+                                              rtx x, int));
+extern int frv_class_likely_spilled_p  PARAMS ((enum reg_class class));
+extern int frv_hard_regno_mode_ok      PARAMS ((int, enum machine_mode));
+extern int frv_hard_regno_nregs                PARAMS ((int, enum machine_mode));
+extern int frv_class_max_nregs         PARAMS ((enum reg_class class,
+                                                enum machine_mode mode));
+extern int frv_legitimate_constant_p   PARAMS ((rtx));
+#endif /* RTX_CODE */
+
+extern int direct_return_p             PARAMS ((void));
+extern int frv_register_move_cost      PARAMS ((enum reg_class, enum reg_class));
+
+#ifdef TREE_CODE
+extern int frv_adjust_field_align      PARAMS ((tree, int));
+extern void frv_select_section         PARAMS ((tree, int));
+#endif
+
+#ifdef RTX_CODE
+extern void frv_select_rtx_section     PARAMS ((enum machine_mode, rtx));
+#endif
+
+#ifdef TREE_CODE
+extern void frv_encode_section_info    PARAMS ((tree));
+extern void frv_unique_section         PARAMS ((tree, int));
+#endif
+
+extern void fixup_section              PARAMS ((void));
+extern void sdata_section              PARAMS ((void));
+extern void sbss_section               PARAMS ((void));
+extern void const_section              PARAMS ((void));
+extern void data_section               PARAMS ((void));
+
+#ifdef RTX_CODE
+extern int integer_register_operand    PARAMS ((rtx, enum machine_mode));
+extern int frv_load_operand            PARAMS ((rtx, enum machine_mode));
+extern int gpr_or_fpr_operand          PARAMS ((rtx, enum machine_mode));
+extern int gpr_no_subreg_operand       PARAMS ((rtx, enum machine_mode));
+extern int gpr_or_int6_operand         PARAMS ((rtx, enum machine_mode));
+extern int fpr_or_int6_operand         PARAMS ((rtx, enum machine_mode));
+extern int gpr_or_int_operand          PARAMS ((rtx, enum machine_mode));
+extern int gpr_or_int12_operand                PARAMS ((rtx, enum machine_mode));
+extern int gpr_fpr_or_int12_operand    PARAMS ((rtx, enum machine_mode));
+extern int gpr_or_int10_operand                PARAMS ((rtx, enum machine_mode));
+extern int move_source_operand         PARAMS ((rtx, enum machine_mode));
+extern int move_destination_operand    PARAMS ((rtx, enum machine_mode));
+extern int condexec_source_operand     PARAMS ((rtx, enum machine_mode));
+extern int condexec_dest_operand       PARAMS ((rtx, enum machine_mode));
+extern int lr_operand                  PARAMS ((rtx, enum machine_mode));
+extern int gpr_or_memory_operand       PARAMS ((rtx, enum machine_mode));
+extern int fpr_or_memory_operand       PARAMS ((rtx, enum machine_mode));
+extern int reg_or_0_operand            PARAMS ((rtx, enum machine_mode));
+extern int fcc_operand                 PARAMS ((rtx, enum machine_mode));
+extern int icc_operand                 PARAMS ((rtx, enum machine_mode));
+extern int cc_operand                  PARAMS ((rtx, enum machine_mode));
+extern int fcr_operand                 PARAMS ((rtx, enum machine_mode));
+extern int icr_operand                 PARAMS ((rtx, enum machine_mode));
+extern int cr_operand                  PARAMS ((rtx, enum machine_mode));
+extern int call_operand                        PARAMS ((rtx, enum machine_mode));
+extern int fpr_operand                 PARAMS ((rtx, enum machine_mode));
+extern int even_reg_operand            PARAMS ((rtx, enum machine_mode));
+extern int odd_reg_operand             PARAMS ((rtx, enum machine_mode));
+extern int even_gpr_operand            PARAMS ((rtx, enum machine_mode));
+extern int odd_gpr_operand             PARAMS ((rtx, enum machine_mode));
+extern int quad_fpr_operand            PARAMS ((rtx, enum machine_mode));
+extern int even_fpr_operand            PARAMS ((rtx, enum machine_mode));
+extern int odd_fpr_operand             PARAMS ((rtx, enum machine_mode));
+extern int dbl_memory_one_insn_operand PARAMS ((rtx, enum machine_mode));
+extern int dbl_memory_two_insn_operand PARAMS ((rtx, enum machine_mode));
+extern int int12_operand               PARAMS ((rtx, enum machine_mode));
+extern int int6_operand                        PARAMS ((rtx, enum machine_mode));
+extern int int5_operand                        PARAMS ((rtx, enum machine_mode));
+extern int uint5_operand               PARAMS ((rtx, enum machine_mode));
+extern int uint4_operand               PARAMS ((rtx, enum machine_mode));
+extern int uint1_operand               PARAMS ((rtx, enum machine_mode));
+extern int int_2word_operand           PARAMS ((rtx, enum machine_mode));
+extern int pic_register_operand                PARAMS ((rtx, enum machine_mode));
+extern int pic_symbolic_operand                PARAMS ((rtx, enum machine_mode));
+extern int small_data_register_operand PARAMS ((rtx, enum machine_mode));
+extern int small_data_symbolic_operand PARAMS ((rtx, enum machine_mode));
+extern int upper_int16_operand         PARAMS ((rtx, enum machine_mode));
+extern int uint16_operand              PARAMS ((rtx, enum machine_mode));
+extern int relational_operator         PARAMS ((rtx, enum machine_mode));
+extern int signed_relational_operator  PARAMS ((rtx, enum machine_mode));
+extern int unsigned_relational_operator        PARAMS ((rtx, enum machine_mode));
+extern int float_relational_operator   PARAMS ((rtx, enum machine_mode));
+extern int ccr_eqne_operator           PARAMS ((rtx, enum machine_mode));
+extern int minmax_operator             PARAMS ((rtx, enum machine_mode));
+extern int condexec_si_binary_operator PARAMS ((rtx, enum machine_mode));
+extern int condexec_si_media_operator  PARAMS ((rtx, enum machine_mode));
+extern int condexec_si_divide_operator PARAMS ((rtx, enum machine_mode));
+extern int condexec_si_unary_operator  PARAMS ((rtx, enum machine_mode));
+extern int condexec_sf_conv_operator   PARAMS ((rtx, enum machine_mode));
+extern int condexec_sf_add_operator    PARAMS ((rtx, enum machine_mode));
+extern int condexec_memory_operand     PARAMS ((rtx, enum machine_mode));
+extern int intop_compare_operator      PARAMS ((rtx, enum machine_mode));
+extern int condexec_intop_cmp_operator PARAMS ((rtx, enum machine_mode));
+extern int acc_operand                 PARAMS ((rtx, enum machine_mode));
+extern int even_acc_operand            PARAMS ((rtx, enum machine_mode));
+extern int quad_acc_operand            PARAMS ((rtx, enum machine_mode));
+extern int accg_operand                        PARAMS ((rtx, enum machine_mode));
+extern rtx frv_matching_accg_for_acc   PARAMS ((rtx));
+extern void frv_machine_dependent_reorg        PARAMS ((rtx));
+#endif
+
diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c
new file mode 100644 (file)
index 0000000..b4e3346
--- /dev/null
@@ -0,0 +1,9856 @@
+/* Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by Red Hat, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "tree.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-flags.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "recog.h"
+#include "reload.h"
+#include "expr.h"
+#include "obstack.h"
+#include "except.h"
+#include "function.h"
+#include "optabs.h"
+#include "toplev.h"
+#include "basic-block.h"
+#include "tm_p.h"
+#include "ggc.h"
+#include <ctype.h>
+#include "target.h"
+#include "target-def.h"
+
+#ifndef FRV_INLINE
+#define FRV_INLINE inline
+#endif
+
+/* Temporary register allocation support structure.  */
+typedef struct frv_tmp_reg_struct
+  {
+    HARD_REG_SET regs;         /* possible registers to allocate */
+    int next_reg[N_REG_CLASSES];       /* next register to allocate per class */
+  }
+frv_tmp_reg_t;
+
+/* Register state information for VLIW re-packing phase.  These values must fit
+   within an unsigned char.  */
+#define REGSTATE_DEAD          0x00    /* register is currently dead */
+#define REGSTATE_CC_MASK       0x07    /* Mask to isolate CCn for cond exec */
+#define REGSTATE_LIVE          0x08    /* register is live */
+#define REGSTATE_MODIFIED      0x10    /* reg modified in current VLIW insn */
+#define REGSTATE_IF_TRUE       0x20    /* reg modified in cond exec true */
+#define REGSTATE_IF_FALSE      0x40    /* reg modified in cond exec false */
+#define REGSTATE_UNUSED                0x80    /* bit for hire */
+#define REGSTATE_MASK          0xff    /* mask for the bits to set */
+
+                                       /* conditional expression used */
+#define REGSTATE_IF_EITHER     (REGSTATE_IF_TRUE | REGSTATE_IF_FALSE)
+
+/* the following is not sure in the reg_state bytes, so can have a larger value
+   than 0xff.  */
+#define REGSTATE_CONDJUMP      0x100   /* conditional jump done in VLIW insn */
+
+/* Used in frv_frame_accessor_t to indicate the direction of a register-to-
+   memory move.  */
+enum frv_stack_op
+{
+  FRV_LOAD,
+  FRV_STORE
+};
+
+/* Information required by frv_frame_access.  */
+typedef struct
+{
+  /* This field is FRV_LOAD if registers are to be loaded from the stack and
+     FRV_STORE if they should be stored onto the stack.  FRV_STORE implies
+     the move is being done by the prologue code while FRV_LOAD implies it
+     is being done by the epilogue.  */
+  enum frv_stack_op op;
+
+  /* The base register to use when accessing the stack.  This may be the
+     frame pointer, stack pointer, or a temporary.  The choice of register
+     depends on which part of the frame is being accessed and how big the
+     frame is.  */
+  rtx base;
+
+  /* The offset of BASE from the bottom of the current frame, in bytes.  */
+  int base_offset;
+} frv_frame_accessor_t;
+
+/* Define the information needed to generate branch and scc insns.  This is
+   stored from the compare operation.  */
+rtx frv_compare_op0;
+rtx frv_compare_op1;
+
+/* Conditional execution support gathered together in one structure */
+typedef struct
+  {
+    /* Linked list of insns to add if the conditional execution conversion was
+       successful.  Each link points to an EXPR_LIST which points to the pattern
+       of the insn to add, and the insn to be inserted before.  */
+    rtx added_insns_list;
+
+    /* Identify which registers are safe to allocate for if conversions to
+       conditional execution.  We keep the last allocated register in the
+       register classes between COND_EXEC statements.  This will mean we allocate
+       different registers for each different COND_EXEC group if we can.  This
+       might allow the scheduler to intermix two different COND_EXEC sections.  */
+    frv_tmp_reg_t tmp_reg;
+
+    /* For nested IFs, identify which CC registers are used outside of setting
+       via a compare isnsn, and using via a check insn.  This will allow us to
+       know if we can rewrite the register to use a different register that will
+       be paired with the CR register controlling the nested IF-THEN blocks.  */
+    HARD_REG_SET nested_cc_ok_rewrite;
+
+    /* Temporary registers allocated to hold constants during conditional
+       execution.  */
+    rtx scratch_regs[FIRST_PSEUDO_REGISTER];
+
+    /* Current number of temp registers available.  */
+    int cur_scratch_regs;
+
+    /* Number of nested conditional execution blocks */
+    int num_nested_cond_exec;
+
+    /* Map of insns that set up constants in scratch registers.  */
+    bitmap scratch_insns_bitmap;
+
+    /* Conditional execution test register (CC0..CC7) */
+    rtx cr_reg;
+
+    /* Conditional execution compare register that is paired with cr_reg, so that
+       nested compares can be done.  The csubcc and caddcc instructions don't
+       have enough bits to specify both a CC register to be set and a CR register
+       to do the test on, so the same bit number is used for both.  Needless to
+       say, this is rather inconvient for GCC.  */
+    rtx nested_cc_reg;
+
+    /* Extra CR registers used for &&, ||.  */
+    rtx extra_int_cr;
+    rtx extra_fp_cr;
+
+    /* Previous CR used in nested if, to make sure we are dealing with the same
+       nested if as the previous statement. */
+    rtx last_nested_if_cr;
+  }
+frv_ifcvt_t;
+
+static /* GTY(()) */ frv_ifcvt_t frv_ifcvt;
+
+/* Map register number to smallest register class.  */
+enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
+
+/* Map class letter into register class */
+enum reg_class reg_class_from_letter[256];
+
+/* Cached value of frv_stack_info */
+static frv_stack_t *frv_stack_cache = (frv_stack_t *)0;
+
+/* -mbranch-cost= support */
+const char *frv_branch_cost_string;
+int frv_branch_cost_int = DEFAULT_BRANCH_COST;
+
+/* -mcpu= support */
+const char *frv_cpu_string;            /* -mcpu= option */
+frv_cpu_t frv_cpu_type = CPU_TYPE;     /* value of -mcpu= */
+
+/* -mcond-exec-insns= support */
+const char *frv_condexec_insns_str;             /* -mcond-exec-insns= option */
+int frv_condexec_insns = DEFAULT_CONDEXEC_INSNS; /* value of -mcond-exec-insns*/
+
+/* -mcond-exec-temps= support */
+const char *frv_condexec_temps_str;             /* -mcond-exec-temps= option */
+int frv_condexec_temps = DEFAULT_CONDEXEC_TEMPS; /* value of -mcond-exec-temps*/
+
+/* -msched-lookahead=n */
+const char *frv_sched_lookahead_str;    /* -msched-lookahead=n */
+int frv_sched_lookahead = 4;            /* -msched-lookahead=n */
+
+/* Forward references */
+static int frv_default_flags_for_cpu           PARAMS ((void));
+static int frv_string_begins_with              PARAMS ((tree, const char *));
+static FRV_INLINE int symbol_ref_small_data_p  PARAMS ((rtx));
+static FRV_INLINE int const_small_data_p       PARAMS ((rtx));
+static FRV_INLINE int plus_small_data_p                PARAMS ((rtx, rtx));
+static void frv_print_operand_memory_reference_reg
+                                               PARAMS ((FILE *, rtx));
+static void frv_print_operand_memory_reference PARAMS ((FILE *, rtx, int));
+static int frv_print_operand_jump_hint         PARAMS ((rtx));
+static FRV_INLINE int frv_regno_ok_for_base_p  PARAMS ((int, int));
+static rtx single_set_pattern                  PARAMS ((rtx));
+static int frv_function_contains_far_jump      PARAMS ((void));
+static rtx frv_alloc_temp_reg                  PARAMS ((frv_tmp_reg_t *,
+                                                        enum reg_class,
+                                                        enum machine_mode,
+                                                        int, int));
+static rtx frv_frame_offset_rtx                        PARAMS ((int));
+static rtx frv_frame_mem                       PARAMS ((enum machine_mode,
+                                                        rtx, int));
+static rtx frv_dwarf_store                     PARAMS ((rtx, int));
+static void frv_frame_insn                     PARAMS ((rtx, rtx));
+static void frv_frame_access                   PARAMS ((frv_frame_accessor_t*,
+                                                        rtx, int));
+static void frv_frame_access_multi             PARAMS ((frv_frame_accessor_t*,
+                                                        frv_stack_t *, int));
+static void frv_frame_access_standard_regs     PARAMS ((enum frv_stack_op,
+                                                        frv_stack_t *));
+static struct machine_function *frv_init_machine_status                PARAMS ((void));
+static int frv_legitimate_memory_operand       PARAMS ((rtx,
+                                                        enum machine_mode,
+                                                        int));
+static rtx frv_int_to_acc                      PARAMS ((enum insn_code,
+                                                        int, rtx));
+static enum machine_mode frv_matching_accg_mode        PARAMS ((enum machine_mode));
+static rtx frv_read_argument                   PARAMS ((tree *));
+static int frv_check_constant_argument         PARAMS ((enum insn_code,
+                                                        int, rtx));
+static rtx frv_legitimize_target               PARAMS ((enum insn_code, rtx));
+static rtx frv_legitimize_argument             PARAMS ((enum insn_code,
+                                                        int, rtx));
+static rtx frv_expand_set_builtin              PARAMS ((enum insn_code,
+                                                        tree, rtx));
+static rtx frv_expand_unop_builtin             PARAMS ((enum insn_code,
+                                                        tree, rtx));
+static rtx frv_expand_binop_builtin            PARAMS ((enum insn_code,
+                                                        tree, rtx));
+static rtx frv_expand_cut_builtin              PARAMS ((enum insn_code,
+                                                        tree, rtx));
+static rtx frv_expand_binopimm_builtin         PARAMS ((enum insn_code,
+                                                        tree, rtx));
+static rtx frv_expand_voidbinop_builtin                PARAMS ((enum insn_code,
+                                                        tree));
+static rtx frv_expand_voidtriop_builtin                PARAMS ((enum insn_code,
+                                                        tree));
+static rtx frv_expand_voidaccop_builtin                PARAMS ((enum insn_code,
+                                                        tree));
+static rtx frv_expand_mclracc_builtin          PARAMS ((tree));
+static rtx frv_expand_mrdacc_builtin           PARAMS ((enum insn_code,
+                                                        tree));
+static rtx frv_expand_mwtacc_builtin           PARAMS ((enum insn_code,
+                                                        tree));
+static rtx frv_expand_noargs_builtin           PARAMS ((enum insn_code));
+static rtx frv_emit_comparison                 PARAMS ((enum rtx_code, rtx,
+                                                        rtx));
+static int frv_clear_registers_used            PARAMS ((rtx *, void *));
+static void frv_ifcvt_add_insn                 PARAMS ((rtx, rtx, int));
+static rtx frv_ifcvt_rewrite_mem               PARAMS ((rtx,
+                                                        enum machine_mode,
+                                                        rtx));
+static rtx frv_ifcvt_load_value                        PARAMS ((rtx, rtx));
+static void frv_registers_update               PARAMS  ((rtx, unsigned char [],
+                                                        int [], int *, int));
+static int frv_registers_used_p                        PARAMS ((rtx, unsigned char [],
+                                                        int));
+static int frv_registers_set_p                 PARAMS ((rtx, unsigned char [],
+                                                        int));
+static void frv_pack_insns                     PARAMS ((void));
+static void frv_function_prologue              PARAMS ((FILE *, HOST_WIDE_INT));
+static void frv_function_epilogue              PARAMS ((FILE *, HOST_WIDE_INT));
+static bool frv_assemble_integer               PARAMS ((rtx, unsigned, int));
+\f
+/* Initialize the GCC target structure.  */
+#undef  TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE frv_function_prologue
+#undef  TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE frv_function_epilogue
+#undef  TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER frv_assemble_integer
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
+/* Given a SYMBOL_REF, return true if it points to small data.  */
+
+static FRV_INLINE int
+symbol_ref_small_data_p (x)
+     rtx x;
+{
+  return SDATA_NAME_P (XSTR (x, 0));
+}
+
+/* Given a CONST, return true if the symbol_ref points to small data.  */
+
+static FRV_INLINE int
+const_small_data_p (x)
+     rtx x;
+{
+  rtx x0, x1;
+
+  if (GET_CODE (XEXP (x, 0)) != PLUS)
+    return FALSE;
+
+  x0 = XEXP (XEXP (x, 0), 0);
+  if (GET_CODE (x0) != SYMBOL_REF || !SDATA_NAME_P (XSTR (x0, 0)))
+    return FALSE;
+
+  x1 = XEXP (XEXP (x, 0), 1);
+  if (GET_CODE (x1) != CONST_INT
+      || !IN_RANGE_P (INTVAL (x1), -2048, 2047))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Given a PLUS, return true if this is a small data reference.  */
+
+static FRV_INLINE int
+plus_small_data_p (op0, op1)
+     rtx op0;
+     rtx op1;
+{
+  if (GET_MODE (op0) == SImode
+      && GET_CODE (op0) == REG
+      && REGNO (op0) == SDA_BASE_REG)
+    {
+      if (GET_CODE (op1) == SYMBOL_REF)
+       return symbol_ref_small_data_p (op1);
+
+      if (GET_CODE (op1) == CONST)
+       return const_small_data_p (op1);
+    }
+
+  return FALSE;
+}
+
+\f
+static int
+frv_default_flags_for_cpu ()
+{
+  switch (frv_cpu_type)
+    {
+    case FRV_CPU_GENERIC:
+      return MASK_DEFAULT_FRV;
+
+    case FRV_CPU_FR500:
+    case FRV_CPU_TOMCAT:
+      return MASK_DEFAULT_FR500;
+
+    case FRV_CPU_FR400:
+      return MASK_DEFAULT_FR400;
+
+    case FRV_CPU_FR300:
+    case FRV_CPU_SIMPLE:
+      return MASK_DEFAULT_SIMPLE;
+    }
+  abort ();
+}
+
+/* Sometimes certain combinations of command options do not make
+   sense on a particular target machine.  You can define a macro
+   `OVERRIDE_OPTIONS' to take account of this.  This macro, if
+   defined, is executed once just after all the command options have
+   been parsed.
+
+   Don't use this macro to turn on various extra optimizations for
+   `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */
+
+void
+frv_override_options ()
+{
+  int regno, i;
+
+  /* Set the cpu type */
+  if (frv_cpu_string)
+    {
+      if (strcmp (frv_cpu_string, "simple") == 0)
+       frv_cpu_type = FRV_CPU_SIMPLE;
+
+      else if (strcmp (frv_cpu_string, "tomcat") == 0)
+       frv_cpu_type = FRV_CPU_TOMCAT;
+
+      else if (strncmp (frv_cpu_string, "fr", sizeof ("fr")-1) != 0)
+       error ("Unknown cpu: -mcpu=%s", frv_cpu_string);
+
+      else
+       {
+         const char *p = frv_cpu_string + sizeof ("fr") - 1;
+         if (strcmp (p, "500") == 0)
+           frv_cpu_type = FRV_CPU_FR500;
+
+         else if (strcmp (p, "400") == 0)
+           frv_cpu_type = FRV_CPU_FR400;
+
+         else if (strcmp (p, "300") == 0)
+           frv_cpu_type = FRV_CPU_FR300;
+
+         else if (strcmp (p, "v") == 0)
+           frv_cpu_type = FRV_CPU_GENERIC;
+
+         else
+           error ("Unknown cpu: -mcpu=%s", frv_cpu_string);
+       }
+    }
+
+  target_flags |= (frv_default_flags_for_cpu () & ~target_flags_explicit);
+
+  /* -mlibrary-pic sets -fPIC and -G0 and also suppresses warnings from the
+     linker about linking pic and non-pic code.  */
+  if (TARGET_LIBPIC)
+    {
+      if (!flag_pic)           /* -fPIC */
+       flag_pic = 2;
+
+      if (! g_switch_set)      /* -G0 */
+       {
+         g_switch_set = 1;
+         g_switch_value = 0;
+       }
+    }
+
+  /* Both -fpic and -gdwarf want to use .previous and the assembler only keeps
+     one level.  */
+  if (write_symbols == DWARF_DEBUG && flag_pic)
+    error ("-fpic and -gdwarf are incompatible (-fpic and -g/-gdwarf-2 are fine)");
+
+  /* Change the branch cost value */
+  if (frv_branch_cost_string)
+    frv_branch_cost_int = atoi (frv_branch_cost_string);
+
+  /* Change the # of insns to be converted to conditional execution */
+  if (frv_condexec_insns_str)
+    frv_condexec_insns = atoi (frv_condexec_insns_str);
+
+  /* Change # of temporary registers used to hold integer constants */
+  if (frv_condexec_temps_str)
+    frv_condexec_temps = atoi (frv_condexec_temps_str);
+
+  /* Change scheduling look ahead. */
+  if (frv_sched_lookahead_str)
+    frv_sched_lookahead = atoi (frv_sched_lookahead_str);
+
+  /* A C expression whose value is a register class containing hard
+     register REGNO.  In general there is more than one such class;
+     choose a class which is "minimal", meaning that no smaller class
+     also contains the register. */
+
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    {
+      enum reg_class class;
+
+      if (GPR_P (regno))
+       {
+         int gpr_reg = regno - GPR_FIRST;
+         if ((gpr_reg & 3) == 0)
+           class = QUAD_REGS;
+
+         else if ((gpr_reg & 1) == 0)
+           class = EVEN_REGS;
+
+         else
+           class = GPR_REGS;
+       }
+
+      else if (FPR_P (regno))
+       {
+         int fpr_reg = regno - GPR_FIRST;
+         if ((fpr_reg & 3) == 0)
+           class = QUAD_FPR_REGS;
+
+         else if ((fpr_reg & 1) == 0)
+           class = FEVEN_REGS;
+
+         else
+           class = FPR_REGS;
+       }
+
+      else if (regno == LR_REGNO)
+       class = LR_REG;
+
+      else if (regno == LCR_REGNO)
+       class = LCR_REG;
+
+      else if (ICC_P (regno))
+       class = ICC_REGS;
+
+      else if (FCC_P (regno))
+       class = FCC_REGS;
+
+      else if (ICR_P (regno))
+       class = ICR_REGS;
+
+      else if (FCR_P (regno))
+       class = FCR_REGS;
+
+      else if (ACC_P (regno))
+       {
+         int r = regno - ACC_FIRST;
+         if ((r & 3) == 0)
+           class = QUAD_ACC_REGS;
+         else if ((r & 1) == 0)
+           class = EVEN_ACC_REGS;
+         else
+           class = ACC_REGS;
+       }
+
+      else if (ACCG_P (regno))
+       class = ACCG_REGS;
+
+      else
+       class = NO_REGS;
+
+      regno_reg_class[regno] = class;
+    }
+
+  /* Check for small data option */
+  if (!g_switch_set)
+    g_switch_value = SDATA_DEFAULT_SIZE;
+
+  /* A C expression which defines the machine-dependent operand
+     constraint letters for register classes.  If CHAR is such a
+     letter, the value should be the register class corresponding to
+     it.  Otherwise, the value should be `NO_REGS'.  The register
+     letter `r', corresponding to class `GENERAL_REGS', will not be
+     passed to this macro; you do not need to handle it.
+
+     The following letters are unavailable, due to being used as
+     constraints:
+       '0'..'9'
+       '<', '>'
+       'E', 'F', 'G', 'H'
+       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P'
+       'Q', 'R', 'S', 'T', 'U'
+       'V', 'X'
+       'g', 'i', 'm', 'n', 'o', 'p', 'r', 's' */
+
+  for (i = 0; i < 256; i++)
+    reg_class_from_letter[i] = NO_REGS;
+
+  reg_class_from_letter['a'] = ACC_REGS;
+  reg_class_from_letter['b'] = EVEN_ACC_REGS;
+  reg_class_from_letter['c'] = CC_REGS;
+  reg_class_from_letter['d'] = GPR_REGS;
+  reg_class_from_letter['e'] = EVEN_REGS;
+  reg_class_from_letter['f'] = FPR_REGS;
+  reg_class_from_letter['h'] = FEVEN_REGS;
+  reg_class_from_letter['l'] = LR_REG;
+  reg_class_from_letter['q'] = QUAD_REGS;
+  reg_class_from_letter['t'] = ICC_REGS;
+  reg_class_from_letter['u'] = FCC_REGS;
+  reg_class_from_letter['v'] = ICR_REGS;
+  reg_class_from_letter['w'] = FCR_REGS;
+  reg_class_from_letter['x'] = QUAD_FPR_REGS;
+  reg_class_from_letter['y'] = LCR_REG;
+  reg_class_from_letter['z'] = SPR_REGS;
+  reg_class_from_letter['A'] = QUAD_ACC_REGS;
+  reg_class_from_letter['B'] = ACCG_REGS;
+  reg_class_from_letter['C'] = CR_REGS;
+
+  /* There is no single unaligned SI op for PIC code.  Sometimes we
+     need to use ".4byte" and sometimes we need to use ".picptr".
+     See frv_assemble_integer for details.  */
+  if (flag_pic)
+    targetm.asm_out.unaligned_op.si = 0;
+
+  init_machine_status = frv_init_machine_status;
+}
+
+\f
+/* Some machines may desire to change what optimizations are performed for
+   various optimization levels.  This macro, if defined, is executed once just
+   after the optimization level is determined and before the remainder of the
+   command options have been parsed.  Values set in this macro are used as the
+   default values for the other command line options.
+
+   LEVEL is the optimization level specified; 2 if `-O2' is specified, 1 if
+   `-O' is specified, and 0 if neither is specified.
+
+   SIZE is non-zero if `-Os' is specified, 0 otherwise.
+
+   You should not use this macro to change options that are not
+   machine-specific.  These should uniformly selected by the same optimization
+   level on all supported machines.  Use this macro to enable machbine-specific
+   optimizations.
+
+   *Do not examine `write_symbols' in this macro!* The debugging options are
+   *not supposed to alter the generated code.  */
+
+/* On the FRV, possibly disable VLIW packing which is done by the 2nd
+   scheduling pass at the current time.  */
+void
+frv_optimization_options (level, size)
+     int level;
+     int size ATTRIBUTE_UNUSED;
+{
+  if (level >= 2)
+    {
+#ifdef DISABLE_SCHED2
+      flag_schedule_insns_after_reload = 0;
+#endif
+#ifdef ENABLE_RCSP
+      flag_rcsp = 1;
+#endif
+    }
+}
+
+\f
+/* A C statement or statements to switch to the appropriate section for output
+   of EXP.  You can assume that EXP is either a `VAR_DECL' node or a constant
+   of some sort.  RELOC indicates whether the initial value of EXP requires
+   link-time relocations.  Select the section by calling `text_section' or one
+   of the alternatives for other sections.
+
+   Do not define this macro if you put all read-only variables and constants in
+   the read-only data section (usually the text section).
+
+   Defined in svr4.h.  */
+
+void
+frv_select_section (decl, reloc)
+     tree decl;
+     int reloc;
+{
+  int size = int_size_in_bytes (TREE_TYPE (decl));
+
+  if (TREE_CODE (decl) == STRING_CST)
+    {
+      if (! flag_writable_strings)
+        readonly_data_section ();
+      else
+       data_section ();
+    }
+  else if (TREE_CODE (decl) == VAR_DECL)
+    {
+      if ((flag_pic && reloc)
+          || !TREE_READONLY (decl)
+          || TREE_SIDE_EFFECTS (decl)
+          || !DECL_INITIAL (decl)
+          || (DECL_INITIAL (decl) != error_mark_node
+              && !TREE_CONSTANT (DECL_INITIAL (decl))))
+        {
+          if (SDATA_NAME_P (XSTR (XEXP (DECL_RTL (decl), 0), 0))
+              && size > 0
+              && size <= g_switch_value)
+           sdata_section ();
+          else
+            data_section ();
+        }
+      else
+        {
+          if (SDATA_NAME_P (XSTR (XEXP (DECL_RTL (decl), 0), 0))
+              && size > 0
+              && size <= g_switch_value)
+            sdata_section ();
+          else
+             readonly_data_section ();
+        }
+    }
+  else
+     readonly_data_section ();
+}
+
+\f
+/* A C statement or statements to switch to the appropriate section for output
+   of RTX in mode MODE.  You can assume that OP is some kind of constant in
+   RTL.  The argument MODE is redundant except in the case of a `const_int'
+   rtx.  Select the section by calling `text_section' or one of the
+   alternatives for other sections.
+
+   Do not define this macro if you put all constants in the read-only data
+   section.
+
+   Defined in svr4.h.  */
+
+void
+frv_select_rtx_section (mode, op)
+     enum machine_mode mode;
+     rtx op ATTRIBUTE_UNUSED;
+{
+  int size = (int) GET_MODE_SIZE (mode);
+  if (size > 0 && size <= g_switch_value)
+    sdata_section ();
+  else
+    readonly_data_section ();
+}
+
+\f
+/* Return true if NAME (a STRING_CST node) begins with PREFIX.  */
+
+static int
+frv_string_begins_with (name, prefix)
+     tree name;
+     const char *prefix;
+{
+  int prefix_len = strlen (prefix);
+
+  /* Remember: NAME's length includes the null terminator.  */
+  return (TREE_STRING_LENGTH (name) > prefix_len
+         && strncmp (TREE_STRING_POINTER (name), prefix, prefix_len) == 0);
+}
+
+/* Encode section information of DECL, which is either a VAR_DECL,
+   FUNCTION_DECL, STRING_CST, CONSTRUCTOR, or ???.
+
+   For the FRV we want to record:
+
+   - whether the object lives in .sdata/.sbss.
+     objects living in .sdata/.sbss are prefixed with SDATA_FLAG_CHAR
+
+*/
+
+void
+frv_encode_section_info (decl)
+     tree decl;
+{
+  if (TREE_CODE (decl) == VAR_DECL)
+    {
+      int size = int_size_in_bytes (TREE_TYPE (decl));
+      tree section_name = DECL_SECTION_NAME (decl);
+      int is_small = 0;
+
+      /* Don't apply the -G flag to internal compiler structures.  We
+        should leave such structures in the main data section, partly
+        for efficiency and partly because the size of some of them
+        (such as C++ typeinfos) is not known until later.  */
+      if (!DECL_ARTIFICIAL (decl) && size > 0 && size <= g_switch_value)
+       is_small = 1;
+
+      /* If we already know which section the decl should be in, see if
+        it's a small data section.  */
+      if (section_name)
+       {
+         if (TREE_CODE (section_name) == STRING_CST)
+           {
+             if (frv_string_begins_with (section_name, ".sdata"))
+               is_small = 1;
+             if (frv_string_begins_with (section_name, ".sbss"))
+               is_small = 1;
+           }
+         else
+           abort ();
+       }
+
+      if (is_small)
+       {
+         rtx sym_ref = XEXP (DECL_RTL (decl), 0);
+         char * str = permalloc (2 + strlen (XSTR (sym_ref, 0)));
+
+         str[0] = SDATA_FLAG_CHAR;
+         strcpy (&str[1], XSTR (sym_ref, 0));
+         XSTR (sym_ref, 0) = str;
+       }
+    }
+}
+
+void
+frv_unique_section (decl, reloc)
+     tree decl;
+     int reloc;
+{
+  int len;
+  int sec;
+  const char *name;
+  char *string;
+  const char *prefix;
+  static const char *prefixes[4][2] =
+    {
+      { ".text.", ".gnu.linkonce.t." },
+      { ".rodata.", ".gnu.linkonce.r." },
+      { ".data.", ".gnu.linkonce.d." },
+      { ".sdata.", ".gnu.linkonce.s." }
+    };
+
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    sec = 0;
+  else if (DECL_READONLY_SECTION (decl, reloc))
+    sec = 1;
+  else if (SDATA_NAME_P (XSTR (XEXP (DECL_RTL (decl), 0), 0)))
+    sec = 3;
+  else
+    sec = 2;
+
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  STRIP_NAME_ENCODING (name, name);
+  prefix = prefixes[sec][DECL_ONE_ONLY (decl)];
+  len = strlen (name) + strlen (prefix);
+  string = alloca (len + 1);
+
+  sprintf (string, "%s%s", prefix, name);
+
+  DECL_SECTION_NAME (decl) = build_string (len, string);
+}
+\f
+/* Zero or more C statements that may conditionally modify two variables
+   `fixed_regs' and `call_used_regs' (both of type `char []') after they have
+   been initialized from the two preceding macros.
+
+   This is necessary in case the fixed or call-clobbered registers depend on
+   target flags.
+
+   You need not define this macro if it has no work to do.
+
+   If the usage of an entire class of registers depends on the target flags,
+   you may indicate this to GCC by using this macro to modify `fixed_regs' and
+   `call_used_regs' to 1 for each of the registers in the classes which should
+   not be used by GCC.  Also define the macro `REG_CLASS_FROM_LETTER' to return
+   `NO_REGS' if it is called with a letter for a class that shouldn't be used.
+
+   (However, if this class is not included in `GENERAL_REGS' and all of the
+   insn patterns whose constraints permit this class are controlled by target
+   switches, then GCC will automatically avoid using these registers when the
+   target switches are opposed to them.)  */
+
+void
+frv_conditional_register_usage ()
+{
+  int i;
+
+  for (i = GPR_FIRST + NUM_GPRS; i <= GPR_LAST; i++)
+    fixed_regs[i] = call_used_regs[i] = 1;
+
+  for (i = FPR_FIRST + NUM_FPRS; i <= FPR_LAST; i++)
+    fixed_regs[i] = call_used_regs[i] = 1;
+
+  for (i = ACC_FIRST + NUM_ACCS; i <= ACC_LAST; i++)
+    fixed_regs[i] = call_used_regs[i] = 1;
+
+  for (i = ACCG_FIRST + NUM_ACCS; i <= ACCG_LAST; i++)
+    fixed_regs[i] = call_used_regs[i] = 1;
+
+  /* Reserve the registers used for conditional execution.  At present, we need
+     1 ICC and 1 ICR register.  */
+  fixed_regs[ICC_TEMP] = call_used_regs[ICC_TEMP] = 1;
+  fixed_regs[ICR_TEMP] = call_used_regs[ICR_TEMP] = 1;
+
+  if (TARGET_FIXED_CC)
+    {
+      fixed_regs[ICC_FIRST] = call_used_regs[ICC_FIRST] = 1;
+      fixed_regs[FCC_FIRST] = call_used_regs[FCC_FIRST] = 1;
+      fixed_regs[ICR_FIRST] = call_used_regs[ICR_FIRST] = 1;
+      fixed_regs[FCR_FIRST] = call_used_regs[FCR_FIRST] = 1;
+    }
+
+#if 0
+  /* If -fpic, SDA_BASE_REG is the PIC register.  */
+  if (g_switch_value == 0 && !flag_pic)
+    fixed_regs[SDA_BASE_REG] = call_used_regs[SDA_BASE_REG] = 0;
+
+  if (!flag_pic)
+    fixed_regs[PIC_REGNO] = call_used_regs[PIC_REGNO] = 0;
+#endif
+}
+
+\f
+/*
+ * Compute the stack frame layout
+ *
+ * Register setup:
+ * +---------------+-----------------------+-----------------------+
+ * |Register       |type                   |caller-save/callee-save|
+ * +---------------+-----------------------+-----------------------+
+ * |GR0            |Zero register          |        -              |
+ * |GR1            |Stack pointer(SP)      |        -              |
+ * |GR2            |Frame pointer(FP)      |        -              |
+ * |GR3            |Hidden parameter       |        caller save    |
+ * |GR4-GR7        |        -              |        caller save    |
+ * |GR8-GR13       |Argument register      |        caller save    |
+ * |GR14-GR15      |        -              |        caller save    |
+ * |GR16-GR31      |        -              |        callee save    |
+ * |GR32-GR47      |        -              |        caller save    |
+ * |GR48-GR63      |        -              |        callee save    |
+ * |FR0-FR15       |        -              |        caller save    |
+ * |FR16-FR31      |        -              |        callee save    |
+ * |FR32-FR47      |        -              |        caller save    |
+ * |FR48-FR63      |        -              |        callee save    |
+ * +---------------+-----------------------+-----------------------+
+ *
+ * Stack frame setup:
+ * Low
+ *     SP-> |-----------------------------------|
+ *         |         Argument area             |
+ *         |-----------------------------------|
+ *         |    Register save area             |
+ *         |-----------------------------------|
+ *         |   Local variable save area        |
+ *     FP-> |-----------------------------------|
+ *         |       Old FP                      |
+ *         |-----------------------------------|
+ *         |    Hidden parameter save area     |
+ *         |-----------------------------------|
+ *         | Return address(LR) storage area   |
+ *         |-----------------------------------|
+ *         |     Padding for alignment         |
+ *         |-----------------------------------|
+ *         |     Register argument area        |
+ * OLD SP-> |-----------------------------------|
+ *          |       Parameter area             |
+ *          |-----------------------------------|
+ * High
+ *
+ * Argument area/Parameter area:
+ *
+ * When a function is called, this area is used for argument transfer.  When
+ * the argument is set up by the caller function, this area is referred to as
+ * the argument area.  When the argument is referenced by the callee function,
+ * this area is referred to as the parameter area.  The area is allocated when
+ * all arguments cannot be placed on the argument register at the time of
+ * argument transfer.
+ *
+ * Register save area:
+ *
+ * This is a register save area that must be guaranteed for the caller
+ * function.  This area is not secured when the register save operation is not
+ * needed.
+ *
+ * Local variable save area:
+ *
+ * This is the area for local variables and temporary variables.
+ *
+ * Old FP:
+ *
+ * This area stores the FP value of the caller function.
+ *
+ * Hidden parameter save area:
+ *
+ * This area stores the start address of the return value storage
+ * area for a struct/union return function.
+ * When a struct/union is used as the return value, the caller
+ * function stores the return value storage area start address in
+ * register GR3 and passes it to the caller function.
+ * The callee function interprets the address stored in the GR3
+ * as the return value storage area start address.
+ * When register GR3 needs to be saved into memory, the callee
+ * function saves it in the hidden parameter save area.  This
+ * area is not secured when the save operation is not needed.
+ *
+ * Return address(LR) storage area:
+ *
+ * This area saves the LR.  The LR stores the address of a return to the caller
+ * function for the purpose of function calling.
+ *
+ * Argument register area:
+ *
+ * This area saves the argument register.  This area is not secured when the
+ * save operation is not needed.
+ *
+ * Argument:
+ *
+ * Arguments, the count of which equals the count of argument registers (6
+ * words), are positioned in registers GR8 to GR13 and delivered to the callee
+ * function.  When a struct/union return function is called, the return value
+ * area address is stored in register GR3.  Arguments not placed in the
+ * argument registers will be stored in the stack argument area for transfer
+ * purposes.  When an 8-byte type argument is to be delivered using registers,
+ * it is divided into two and placed in two registers for transfer.  When
+ * argument registers must be saved to memory, the callee function secures an
+ * argument register save area in the stack.  In this case, a continuous
+ * argument register save area must be established in the parameter area.  The
+ * argument register save area must be allocated as needed to cover the size of
+ * the argument register to be saved.  If the function has a variable count of
+ * arguments, it saves all argument registers in the argument register save
+ * area.
+ *
+ * Argument Extension Format:
+ *
+ * When an argument is to be stored in the stack, its type is converted to an
+ * extended type in accordance with the individual argument type.  The argument
+ * is freed by the caller function after the return from the callee function is
+ * made.
+ *
+ * +-----------------------+---------------+------------------------+
+ * |    Argument Type      |Extended Type  |Stack Storage Size(byte)|
+ * +-----------------------+---------------+------------------------+
+ * |char                   |int            |        4              |
+ * |signed char            |int            |        4              |
+ * |unsigned char          |int            |        4              |
+ * |[signed] short int     |int            |        4              |
+ * |unsigned short int     |int            |        4              |
+ * |[signed] int           |No extension   |        4              |
+ * |unsigned int           |No extension   |        4              |
+ * |[signed] long int      |No extension   |        4              |
+ * |unsigned long int      |No extension   |        4              |
+ * |[signed] long long int |No extension   |        8              |
+ * |unsigned long long int |No extension   |        8              |
+ * |float                  |double         |        8              |
+ * |double                 |No extension   |        8              |
+ * |long double            |No extension   |        8              |
+ * |pointer                |No extension   |        4              |
+ * |struct/union           |-              |        4 (*1)         |
+ * +-----------------------+---------------+------------------------+
+ *
+ * When a struct/union is to be delivered as an argument, the caller copies it
+ * to the local variable area and delivers the address of that area.
+ *
+ * Return Value:
+ *
+ * +-------------------------------+----------------------+
+ * |Return Value Type              |Return Value Interface|
+ * +-------------------------------+----------------------+
+ * |void                           |None                  |
+ * |[signed|unsigned] char         |GR8                   |
+ * |[signed|unsigned] short int    |GR8                   |
+ * |[signed|unsigned] int          |GR8                   |
+ * |[signed|unsigned] long int     |GR8                   |
+ * |pointer                        |GR8                   |
+ * |[signed|unsigned] long long int|GR8 & GR9             |
+ * |float                          |GR8                   |
+ * |double                         |GR8 & GR9             |
+ * |long double                    |GR8 & GR9             |
+ * |struct/union                   |(*1)                  |
+ * +-------------------------------+----------------------+
+ *
+ * When a struct/union is used as the return value, the caller function stores
+ * the start address of the return value storage area into GR3 and then passes
+ * it to the callee function.  The callee function interprets GR3 as the start
+ * address of the return value storage area.  When this address needs to be
+ * saved in memory, the callee function secures the hidden parameter save area
+ * and saves the address in that area.
+ */
+
+frv_stack_t *
+frv_stack_info ()
+{
+  static frv_stack_t info, zero_info;
+  frv_stack_t *info_ptr        = &info;
+  tree fndecl          = current_function_decl;
+  int varargs_p                = 0;
+  tree cur_arg;
+  tree next_arg;
+  int range;
+  int alignment;
+  int offset;
+
+  /* If we've already calculated the values and reload is complete, just return now */
+  if (frv_stack_cache)
+    return frv_stack_cache;
+
+  /* Zero all fields */
+  info = zero_info;
+
+  /* Set up the register range information */
+  info_ptr->regs[STACK_REGS_GPR].name         = "gpr";
+  info_ptr->regs[STACK_REGS_GPR].first        = LAST_ARG_REGNUM + 1;
+  info_ptr->regs[STACK_REGS_GPR].last         = GPR_LAST;
+  info_ptr->regs[STACK_REGS_GPR].dword_p      = TRUE;
+
+  info_ptr->regs[STACK_REGS_FPR].name         = "fpr";
+  info_ptr->regs[STACK_REGS_FPR].first        = FPR_FIRST;
+  info_ptr->regs[STACK_REGS_FPR].last         = FPR_LAST;
+  info_ptr->regs[STACK_REGS_FPR].dword_p      = TRUE;
+
+  info_ptr->regs[STACK_REGS_LR].name          = "lr";
+  info_ptr->regs[STACK_REGS_LR].first         = LR_REGNO;
+  info_ptr->regs[STACK_REGS_LR].last          = LR_REGNO;
+  info_ptr->regs[STACK_REGS_LR].special_p     = 1;
+
+  info_ptr->regs[STACK_REGS_CC].name          = "cc";
+  info_ptr->regs[STACK_REGS_CC].first         = CC_FIRST;
+  info_ptr->regs[STACK_REGS_CC].last          = CC_LAST;
+  info_ptr->regs[STACK_REGS_CC].field_p       = TRUE;
+
+  info_ptr->regs[STACK_REGS_LCR].name         = "lcr";
+  info_ptr->regs[STACK_REGS_LCR].first        = LCR_REGNO;
+  info_ptr->regs[STACK_REGS_LCR].last         = LCR_REGNO;
+
+  info_ptr->regs[STACK_REGS_STDARG].name      = "stdarg";
+  info_ptr->regs[STACK_REGS_STDARG].first     = FIRST_ARG_REGNUM;
+  info_ptr->regs[STACK_REGS_STDARG].last      = LAST_ARG_REGNUM;
+  info_ptr->regs[STACK_REGS_STDARG].dword_p   = 1;
+  info_ptr->regs[STACK_REGS_STDARG].special_p = 1;
+
+  info_ptr->regs[STACK_REGS_STRUCT].name      = "struct";
+  info_ptr->regs[STACK_REGS_STRUCT].first     = STRUCT_VALUE_REGNUM;
+  info_ptr->regs[STACK_REGS_STRUCT].last      = STRUCT_VALUE_REGNUM;
+  info_ptr->regs[STACK_REGS_STRUCT].special_p = 1;
+
+  info_ptr->regs[STACK_REGS_FP].name          = "fp";
+  info_ptr->regs[STACK_REGS_FP].first         = FRAME_POINTER_REGNUM;
+  info_ptr->regs[STACK_REGS_FP].last          = FRAME_POINTER_REGNUM;
+  info_ptr->regs[STACK_REGS_FP].special_p     = 1;
+
+  /* Determine if this is a stdarg function.  If so, allocate space to store
+     the 6 arguments.  */
+  if (cfun->stdarg)
+    varargs_p = 1;
+
+  else
+    {
+      /* Find the last argument, and see if it is __builtin_va_alist.  */
+      for (cur_arg = DECL_ARGUMENTS (fndecl); cur_arg != (tree)0; cur_arg = next_arg)
+       {
+         next_arg = TREE_CHAIN (cur_arg);
+         if (next_arg == (tree)0)
+           {
+             if (DECL_NAME (cur_arg)
+                 && !strcmp (IDENTIFIER_POINTER (DECL_NAME (cur_arg)), "__builtin_va_alist"))
+               varargs_p = 1;
+
+             break;
+           }
+       }
+    }
+
+  /* Iterate over all of the register ranges */
+  for (range = 0; range < STACK_REGS_MAX; range++)
+    {
+      frv_stack_regs_t *reg_ptr = &(info_ptr->regs[range]);
+      int first = reg_ptr->first;
+      int last = reg_ptr->last;
+      int size_1word = 0;
+      int size_2words = 0;
+      int regno;
+
+      /* Calculate which registers need to be saved & save area size */
+      switch (range)
+       {
+       default:
+         for (regno = first; regno <= last; regno++)
+           {
+             if ((regs_ever_live[regno] && !call_used_regs[regno])
+                 || (current_function_calls_eh_return
+                     && (regno >= FIRST_EH_REGNUM && regno <= LAST_EH_REGNUM))
+                 || (flag_pic && cfun->uses_pic_offset_table && regno == PIC_REGNO))
+               {
+                 info_ptr->save_p[regno] = REG_SAVE_1WORD;
+                 size_1word += UNITS_PER_WORD;
+               }
+           }
+         break;
+
+         /* Calculate whether we need to create a frame after everything else
+             has been processed.  */
+       case STACK_REGS_FP:
+         break;
+
+       case STACK_REGS_LR:
+         if (regs_ever_live[LR_REGNO]
+              || profile_flag
+              || frame_pointer_needed
+              || (flag_pic && cfun->uses_pic_offset_table))
+           {
+             info_ptr->save_p[LR_REGNO] = REG_SAVE_1WORD;
+             size_1word += UNITS_PER_WORD;
+           }
+         break;
+
+       case STACK_REGS_STDARG:
+         if (varargs_p)
+           {
+             /* If this is a stdarg function with an non varardic argument split
+                between registers and the stack, adjust the saved registers
+                downward */
+             last -= (ADDR_ALIGN (cfun->pretend_args_size, UNITS_PER_WORD)
+                      / UNITS_PER_WORD);
+
+             for (regno = first; regno <= last; regno++)
+               {
+                 info_ptr->save_p[regno] = REG_SAVE_1WORD;
+                 size_1word += UNITS_PER_WORD;
+               }
+
+             info_ptr->stdarg_size = size_1word;
+           }
+         break;
+
+       case STACK_REGS_STRUCT:
+         if (cfun->returns_struct)
+           {
+             info_ptr->save_p[STRUCT_VALUE_REGNUM] = REG_SAVE_1WORD;
+             size_1word += UNITS_PER_WORD;
+           }
+         break;
+       }
+
+
+      if (size_1word)
+       {
+         /* If this is a field, it only takes one word */
+         if (reg_ptr->field_p)
+           size_1word = UNITS_PER_WORD;
+
+         /* Determine which register pairs can be saved together */
+         else if (reg_ptr->dword_p && TARGET_DWORD)
+           {
+             for (regno = first; regno < last; regno += 2)
+               {
+                 if (info_ptr->save_p[regno] && info_ptr->save_p[regno+1])
+                   {
+                     size_2words += 2 * UNITS_PER_WORD;
+                     size_1word -= 2 * UNITS_PER_WORD;
+                     info_ptr->save_p[regno] = REG_SAVE_2WORDS;
+                     info_ptr->save_p[regno+1] = REG_SAVE_NO_SAVE;
+                   }
+               }
+           }
+
+         reg_ptr->size_1word = size_1word;
+         reg_ptr->size_2words = size_2words;
+
+         if (! reg_ptr->special_p)
+           {
+             info_ptr->regs_size_1word += size_1word;
+             info_ptr->regs_size_2words += size_2words;
+           }
+       }
+    }
+
+  /* Set up the sizes of each each field in the frame body, making the sizes
+     of each be divisible by the size of a dword if dword operations might
+     be used, or the size of a word otherwise.  */
+  alignment = (TARGET_DWORD? 2 * UNITS_PER_WORD : UNITS_PER_WORD);
+
+  info_ptr->parameter_size = ADDR_ALIGN (cfun->outgoing_args_size, alignment);
+  info_ptr->regs_size = ADDR_ALIGN (info_ptr->regs_size_2words
+                                   + info_ptr->regs_size_1word,
+                                   alignment);
+  info_ptr->vars_size = ADDR_ALIGN (get_frame_size (), alignment);
+
+  info_ptr->pretend_size = cfun->pretend_args_size;
+
+  /* Work out the size of the frame, excluding the header.  Both the frame
+     body and register parameter area will be dword-aligned.  */
+  info_ptr->total_size
+    = (ADDR_ALIGN (info_ptr->parameter_size
+                  + info_ptr->regs_size
+                  + info_ptr->vars_size,
+                  2 * UNITS_PER_WORD)
+       + ADDR_ALIGN (info_ptr->pretend_size
+                    + info_ptr->stdarg_size,
+                    2 * UNITS_PER_WORD));
+
+  /* See if we need to create a frame at all, if so add header area.  */
+  if (info_ptr->total_size  > 0
+      || info_ptr->regs[STACK_REGS_LR].size_1word > 0
+      || info_ptr->regs[STACK_REGS_STRUCT].size_1word > 0)
+    {
+      offset = info_ptr->parameter_size;
+      info_ptr->header_size = 4 * UNITS_PER_WORD;
+      info_ptr->total_size += 4 * UNITS_PER_WORD;
+
+      /* Calculate the offsets to save normal register pairs */
+      for (range = 0; range < STACK_REGS_MAX; range++)
+       {
+         frv_stack_regs_t *reg_ptr = &(info_ptr->regs[range]);
+         if (! reg_ptr->special_p)
+           {
+             int first = reg_ptr->first;
+             int last = reg_ptr->last;
+             int regno;
+
+             for (regno = first; regno <= last; regno++)
+               if (info_ptr->save_p[regno] == REG_SAVE_2WORDS
+                   && regno != FRAME_POINTER_REGNUM
+                   && (regno < FIRST_ARG_REGNUM
+                       || regno > LAST_ARG_REGNUM))
+                 {
+                   info_ptr->reg_offset[regno] = offset;
+                   offset += 2 * UNITS_PER_WORD;
+                 }
+           }
+       }
+
+      /* Calculate the offsets to save normal single registers */
+      for (range = 0; range < STACK_REGS_MAX; range++)
+       {
+         frv_stack_regs_t *reg_ptr = &(info_ptr->regs[range]);
+         if (! reg_ptr->special_p)
+           {
+             int first = reg_ptr->first;
+             int last = reg_ptr->last;
+             int regno;
+
+             for (regno = first; regno <= last; regno++)
+               if (info_ptr->save_p[regno] == REG_SAVE_1WORD
+                   && regno != FRAME_POINTER_REGNUM
+                   && (regno < FIRST_ARG_REGNUM
+                       || regno > LAST_ARG_REGNUM))
+                 {
+                   info_ptr->reg_offset[regno] = offset;
+                   offset += UNITS_PER_WORD;
+                 }
+           }
+       }
+
+      /* Calculate the offset to save the local variables at.  */
+      offset = ADDR_ALIGN (offset, alignment);
+      if (info_ptr->vars_size)
+       {
+         info_ptr->vars_offset = offset;
+         offset += info_ptr->vars_size;
+       }
+
+      /* Align header to a dword-boundary.  */
+      offset = ADDR_ALIGN (offset, 2 * UNITS_PER_WORD);
+
+      /* Calculate the offsets in the fixed frame.  */
+      info_ptr->save_p[FRAME_POINTER_REGNUM] = REG_SAVE_1WORD;
+      info_ptr->reg_offset[FRAME_POINTER_REGNUM] = offset;
+      info_ptr->regs[STACK_REGS_FP].size_1word = UNITS_PER_WORD;
+
+      info_ptr->save_p[LR_REGNO] = REG_SAVE_1WORD;
+      info_ptr->reg_offset[LR_REGNO] = offset + 2*UNITS_PER_WORD;
+      info_ptr->regs[STACK_REGS_LR].size_1word = UNITS_PER_WORD;
+
+      if (cfun->returns_struct)
+       {
+         info_ptr->save_p[STRUCT_VALUE_REGNUM] = REG_SAVE_1WORD;
+         info_ptr->reg_offset[STRUCT_VALUE_REGNUM] = offset + UNITS_PER_WORD;
+         info_ptr->regs[STACK_REGS_STRUCT].size_1word = UNITS_PER_WORD;
+       }
+
+      /* Calculate the offsets to store the arguments passed in registers
+         for stdarg functions.  The register pairs are first and the single
+         register if any is last.  The register save area starts on a
+         dword-boundary.  */
+      if (info_ptr->stdarg_size)
+       {
+         int first = info_ptr->regs[STACK_REGS_STDARG].first;
+         int last  = info_ptr->regs[STACK_REGS_STDARG].last;
+         int regno;
+
+         /* Skip the header.  */
+         offset += 4 * UNITS_PER_WORD;
+         for (regno = first; regno <= last; regno++)
+           {
+             if (info_ptr->save_p[regno] == REG_SAVE_2WORDS)
+               {
+                 info_ptr->reg_offset[regno] = offset;
+                 offset += 2 * UNITS_PER_WORD;
+               }
+             else if (info_ptr->save_p[regno] == REG_SAVE_1WORD)
+               {
+                 info_ptr->reg_offset[regno] = offset;
+                 offset += UNITS_PER_WORD;
+               }
+           }
+       }
+    }
+
+  if (reload_completed)
+    frv_stack_cache = info_ptr;
+
+  return info_ptr;
+}
+
+\f
+/* Print the information about the frv stack offsets, etc. when debugging. */
+
+void
+frv_debug_stack (info)
+     frv_stack_t *info;
+{
+  int range;
+
+  if (!info)
+    info = frv_stack_info ();
+
+  fprintf (stderr, "\nStack information for function %s:\n",
+          ((current_function_decl && DECL_NAME (current_function_decl))
+           ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
+           : "<unknown>"));
+
+  fprintf (stderr, "\ttotal_size\t= %6d\n", info->total_size);
+  fprintf (stderr, "\tvars_size\t= %6d\n", info->vars_size);
+  fprintf (stderr, "\tparam_size\t= %6d\n", info->parameter_size);
+  fprintf (stderr, "\tregs_size\t= %6d, 1w = %3d, 2w = %3d\n",
+          info->regs_size, info->regs_size_1word, info->regs_size_2words);
+
+  fprintf (stderr, "\theader_size\t= %6d\n", info->header_size);
+  fprintf (stderr, "\tpretend_size\t= %6d\n", info->pretend_size);
+  fprintf (stderr, "\tvars_offset\t= %6d\n", info->vars_offset);
+  fprintf (stderr, "\tregs_offset\t= %6d\n", info->regs_offset);
+
+  for (range = 0; range < STACK_REGS_MAX; range++)
+    {
+      frv_stack_regs_t *regs = &(info->regs[range]);
+      if ((regs->size_1word + regs->size_2words) > 0)
+       {
+         int first = regs->first;
+         int last  = regs->last;
+         int regno;
+
+         fprintf (stderr, "\t%s\tsize\t= %6d, 1w = %3d, 2w = %3d, save =",
+                  regs->name, regs->size_1word + regs->size_2words,
+                  regs->size_1word, regs->size_2words);
+
+         for (regno = first; regno <= last; regno++)
+           {
+             if (info->save_p[regno] == REG_SAVE_1WORD)
+               fprintf (stderr, " %s (%d)", reg_names[regno],
+                        info->reg_offset[regno]);
+
+             else if (info->save_p[regno] == REG_SAVE_2WORDS)
+               fprintf (stderr, " %s-%s (%d)", reg_names[regno],
+                        reg_names[regno+1], info->reg_offset[regno]);
+           }
+
+         fputc ('\n', stderr);
+       }
+    }
+
+  fflush (stderr);
+}
+
+
+\f
+
+/* The following variable value is TRUE if the next output insn should
+   finish cpu cycle.  In order words the insn will have packing bit
+   (which means absence of asm code suffix `.p' on assembler. */
+
+static int frv_insn_packing_flag;
+
+/* True if the current function contains a far jump.  */
+
+static int
+frv_function_contains_far_jump ()
+{
+  rtx insn = get_insns ();
+  while (insn != NULL
+        && !(GET_CODE (insn) == JUMP_INSN
+             /* Ignore tablejump patterns.  */
+             && GET_CODE (PATTERN (insn)) != ADDR_VEC
+             && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
+             && get_attr_far_jump (insn) == FAR_JUMP_YES))
+    insn = NEXT_INSN (insn);
+  return (insn != NULL);
+}
+
+/* For the FRV, this function makes sure that a function with far jumps
+   will return correctly.  It also does the VLIW packing.  */
+
+static void
+frv_function_prologue (file, size)
+     FILE *file;
+     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
+{
+  /* If no frame was created, check whether the function uses a call
+     instruction to implement a far jump.  If so, save the link in gr3 and
+     replace all returns to LR with returns to GR3.  GR3 is used because it
+     is call-clobbered, because is not available to the register allocator,
+     and because all functions that take a hidden argument pointer will have
+     a stack frame.  */
+  if (frv_stack_info ()->total_size == 0 && frv_function_contains_far_jump ())
+    {
+      rtx insn;
+
+      /* Just to check that the above comment is true.  */
+      if (regs_ever_live[GPR_FIRST + 3])
+       abort ();
+
+      /* Generate the instruction that saves the link register.  */
+      fprintf (file, "\tmovsg lr,gr3\n");
+
+      /* Replace the LR with GR3 in *return_internal patterns.  The insn
+        will now return using jmpl @(gr3,0) rather than bralr.  We cannot
+        simply emit a different assembly directive because bralr and jmpl
+        execute in different units.  */
+      for (insn = get_insns(); insn != NULL; insn = NEXT_INSN (insn))
+       if (GET_CODE (insn) == JUMP_INSN)
+         {
+           rtx pattern = PATTERN (insn);
+           if (GET_CODE (pattern) == PARALLEL
+               && XVECLEN (pattern, 0) >= 2
+               && GET_CODE (XVECEXP (pattern, 0, 0)) == RETURN
+               && GET_CODE (XVECEXP (pattern, 0, 1)) == USE)
+             {
+               rtx address = XEXP (XVECEXP (pattern, 0, 1), 0);
+               if (GET_CODE (address) == REG && REGNO (address) == LR_REGNO)
+                 REGNO (address) = GPR_FIRST + 3;
+             }
+         }
+    }
+
+  frv_pack_insns ();
+  frv_insn_packing_flag = TRUE;
+}
+
+\f
+/* Return the next available temporary register in a given class.  */
+
+static rtx
+frv_alloc_temp_reg (info, class, mode, mark_as_used, no_abort)
+     frv_tmp_reg_t *info;      /* which registers are available */
+     enum reg_class class;     /* register class desired */
+     enum machine_mode mode;   /* mode to allocate register with */
+     int mark_as_used;         /* register not available after allocation */
+     int no_abort;             /* return NULL instead of aborting */
+{
+  int regno = info->next_reg[ (int)class ];
+  int orig_regno = regno;
+  HARD_REG_SET *reg_in_class = &reg_class_contents[ (int)class ];
+  int i, nr;
+
+  for (;;)
+    {
+      if (TEST_HARD_REG_BIT (*reg_in_class, regno)
+         && TEST_HARD_REG_BIT (info->regs, regno))
+         break;
+
+      if (++regno >= FIRST_PSEUDO_REGISTER)
+       regno = 0;
+      if (regno == orig_regno)
+       {
+         if (no_abort)
+           return NULL_RTX;
+         else
+           abort ();
+       }
+    }
+
+  nr = HARD_REGNO_NREGS (regno, mode);
+  info->next_reg[ (int)class ] = regno + nr;
+
+  if (mark_as_used)
+    for (i = 0; i < nr; i++)
+      CLEAR_HARD_REG_BIT (info->regs, regno+i);
+
+  return gen_rtx_REG (mode, regno);
+}
+
+\f
+/* Return an rtx with the value OFFSET, which will either be a register or a
+   signed 12-bit integer.  It can be used as the second operand in an "add"
+   instruction, or as the index in a load or store.
+
+   The function returns a constant rtx if OFFSET is small enough, otherwise
+   it loads the constant into register OFFSET_REGNO and returns that.  */
+static rtx
+frv_frame_offset_rtx (offset)
+     int offset;
+{
+  rtx offset_rtx = GEN_INT (offset);
+  if (IN_RANGE_P (offset, -2048, 2047))
+    return offset_rtx;
+  else
+    {
+      rtx reg_rtx = gen_rtx_REG (SImode, OFFSET_REGNO);
+      if (IN_RANGE_P (offset, -32768, 32767))
+       emit_insn (gen_movsi (reg_rtx, offset_rtx));
+      else
+       {
+         emit_insn (gen_movsi_high (reg_rtx, offset_rtx));
+         emit_insn (gen_movsi_lo_sum (reg_rtx, offset_rtx));
+       }
+      return reg_rtx;
+    }
+}
+
+/* Generate (mem:MODE (plus:Pmode BASE (frv_frame_offset OFFSET)))).  The
+   prologue and epilogue uses such expressions to access the stack.  */
+static rtx
+frv_frame_mem (mode, base, offset)
+     enum machine_mode mode;
+     rtx base;
+     int offset;
+{
+  return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode,
+                                         base,
+                                         frv_frame_offset_rtx (offset)));
+}
+
+/* Generate a frame-related expression:
+
+       (set REG (mem (plus (sp) (const_int OFFSET)))).
+
+   Such expressions are used in FRAME_RELATED_EXPR notes for more complex
+   instructions.  Marking the expressions as frame-related is superfluous if
+   the note contains just a single set.  But if the note contains a PARALLEL
+   or SEQUENCE that has several sets, each set must be individually marked
+   as frame-related.  */
+static rtx
+frv_dwarf_store (reg, offset)
+     rtx reg;
+     int offset;
+{
+  rtx set = gen_rtx_SET (VOIDmode,
+                        gen_rtx_MEM (GET_MODE (reg),
+                                     plus_constant (stack_pointer_rtx,
+                                                    offset)),
+                        reg);
+  RTX_FRAME_RELATED_P (set) = 1;
+  return set;
+}
+
+/* Emit a frame-related instruction whose pattern is PATTERN.  The
+   instruction is the last in a sequence that cumulatively performs the
+   operation described by DWARF_PATTERN.  The instruction is marked as
+   frame-related and has a REG_FRAME_RELATED_EXPR note containing
+   DWARF_PATTERN.  */
+static void
+frv_frame_insn (pattern, dwarf_pattern)
+     rtx pattern;
+     rtx dwarf_pattern;
+{
+  rtx insn = emit_insn (pattern);
+  RTX_FRAME_RELATED_P (insn) = 1;
+  REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                                     dwarf_pattern,
+                                     REG_NOTES (insn));
+}
+
+/* Emit instructions that transfer REG to or from the memory location (sp +
+   STACK_OFFSET).  The register is stored in memory if ACCESSOR->OP is
+   FRV_STORE and loaded if it is FRV_LOAD.  Only the prologue uses this
+   function to store registers and only the epilogue uses it to load them.
+
+   The caller sets up ACCESSOR so that BASE is equal to (sp + BASE_OFFSET).
+   The generated instruction will use BASE as its base register.  BASE may
+   simply be the stack pointer, but if several accesses are being made to a
+   region far away from the stack pointer, it may be more efficient to set
+   up a temporary instead.
+   
+   Store instructions will be frame-related and will be annotated with the
+   overall effect of the store.  Load instructions will be followed by a
+   (use) to prevent later optimizations from zapping them.
+
+   The function takes care of the moves to and from SPRs, using TEMP_REGNO
+   as a temporary in such cases.  */
+static void
+frv_frame_access (accessor, reg, stack_offset)
+     frv_frame_accessor_t *accessor;
+     rtx reg;
+     int stack_offset;
+{
+  enum machine_mode mode = GET_MODE (reg);
+  rtx mem = frv_frame_mem (mode,
+                          accessor->base,
+                          stack_offset - accessor->base_offset);
+
+  if (accessor->op == FRV_LOAD)
+    {
+      if (SPR_P (REGNO (reg)))
+       {
+         rtx temp = gen_rtx_REG (mode, TEMP_REGNO);
+         emit_insn (gen_rtx_SET (VOIDmode, temp, mem));
+         emit_insn (gen_rtx_SET (VOIDmode, reg, temp));
+       }
+      else
+       emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
+      emit_insn (gen_rtx_USE (VOIDmode, reg));
+    }
+  else
+    {
+      if (SPR_P (REGNO (reg)))
+       {
+         rtx temp = gen_rtx_REG (mode, TEMP_REGNO);
+         emit_insn (gen_rtx_SET (VOIDmode, temp, reg));
+         frv_frame_insn (gen_rtx_SET (Pmode, mem, temp),
+                         frv_dwarf_store (reg, stack_offset));
+       }
+      else if (GET_MODE (reg) == DImode)
+       {
+         /* For DImode saves, the dwarf2 version needs to be a SEQUENCE
+            with a separate save for each register.  */
+         rtx reg1 = gen_rtx_REG (SImode, REGNO (reg));
+         rtx reg2 = gen_rtx_REG (SImode, REGNO (reg) + 1);
+         rtx set1 = frv_dwarf_store (reg1, stack_offset);
+         rtx set2 = frv_dwarf_store (reg2, stack_offset + 4);
+         frv_frame_insn (gen_rtx_SET (Pmode, mem, reg),
+                         gen_rtx_PARALLEL (VOIDmode,
+                                           gen_rtvec (2, set1, set2)));
+       }
+      else
+       frv_frame_insn (gen_rtx_SET (Pmode, mem, reg),
+                       frv_dwarf_store (reg, stack_offset));
+    }
+}
+
+/* A function that uses frv_frame_access to transfer a group of registers to
+   or from the stack.  ACCESSOR is passed directly to frv_frame_access, INFO
+   is the stack information generated by frv_stack_info, and REG_SET is the
+   number of the register set to transfer.  */
+static void
+frv_frame_access_multi (accessor, info, reg_set)
+     frv_frame_accessor_t *accessor;
+     frv_stack_t *info;
+     int reg_set;
+{
+  frv_stack_regs_t *regs_info;
+  int regno;
+
+  regs_info = &info->regs[reg_set];
+  for (regno = regs_info->first; regno <= regs_info->last; regno++)
+    if (info->save_p[regno])
+      frv_frame_access (accessor,
+                       info->save_p[regno] == REG_SAVE_2WORDS
+                       ? gen_rtx_REG (DImode, regno)
+                       : gen_rtx_REG (SImode, regno),
+                       info->reg_offset[regno]);
+}
+
+/* Save or restore callee-saved registers that are kept outside the frame
+   header.  The function saves the registers if OP is FRV_STORE and restores
+   them if OP is FRV_LOAD.  INFO is the stack information generated by
+   frv_stack_info.  */
+static void
+frv_frame_access_standard_regs (op, info)
+     enum frv_stack_op op;
+     frv_stack_t *info;
+{
+  frv_frame_accessor_t accessor;
+
+  accessor.op = op;
+  accessor.base = stack_pointer_rtx;
+  accessor.base_offset = 0;
+  frv_frame_access_multi (&accessor, info, STACK_REGS_GPR);
+  frv_frame_access_multi (&accessor, info, STACK_REGS_FPR);
+  frv_frame_access_multi (&accessor, info, STACK_REGS_LCR);
+}  
+
+
+/* Called after register allocation to add any instructions needed for the
+   prologue.  Using a prologue insn is favored compared to putting all of the
+   instructions in the FUNCTION_PROLOGUE macro, since it allows the scheduler
+   to intermix instructions with the saves of the caller saved registers.  In
+   some cases, it might be necessary to emit a barrier instruction as the last
+   insn to prevent such scheduling.
+
+   Also any insns generated here should have RTX_FRAME_RELATED_P(insn) = 1
+   so that the debug info generation code can handle them properly.  */
+void
+frv_expand_prologue ()
+{
+  frv_stack_t *info = frv_stack_info ();
+  rtx sp = stack_pointer_rtx;
+  rtx fp = frame_pointer_rtx;
+  frv_frame_accessor_t accessor;
+
+  if (TARGET_DEBUG_STACK)
+    frv_debug_stack (info);
+
+  if (info->total_size == 0)
+    return;
+
+  /* We're interested in three areas of the frame here:
+
+         A: the register save area
+        B: the old FP
+        C: the header after B
+
+     If the frame pointer isn't used, we'll have to set up A, B and C
+     using the stack pointer.  If the frame pointer is used, we'll access
+     them as follows:
+
+         A: set up using sp
+        B: set up using sp or a temporary (see below)
+        C: set up using fp
+
+     We set up B using the stack pointer if the frame is small enough.
+     Otherwise, it's more efficient to copy the old stack pointer into a
+     temporary and use that.
+
+     Note that it's important to make sure the prologue and epilogue use the
+     same registers to access A and C, since doing otherwise will confuse
+     the aliasing code.  */
+
+  /* Set up ACCESSOR for accessing region B above.  If the frame pointer
+     isn't used, the same method will serve for C.  */
+  accessor.op = FRV_STORE;
+  if (frame_pointer_needed && info->total_size > 2048)
+    {
+      rtx insn;
+
+      accessor.base = gen_rtx_REG (Pmode, OLD_SP_REGNO);
+      accessor.base_offset = info->total_size;
+      insn = emit_insn (gen_movsi (accessor.base, sp));
+    }
+  else
+    {
+      accessor.base = stack_pointer_rtx;
+      accessor.base_offset = 0;
+    }
+
+  /* Allocate the stack space.  */
+  {
+    rtx asm_offset = frv_frame_offset_rtx (-info->total_size);
+    rtx dwarf_offset = GEN_INT (-info->total_size);
+
+    frv_frame_insn (gen_stack_adjust (sp, sp, asm_offset),
+                   gen_rtx_SET (Pmode,
+                                sp,
+                                gen_rtx_PLUS (Pmode, sp, dwarf_offset)));
+  }
+
+  /* If the frame pointer is needed, store the old one at (sp + FP_OFFSET)
+     and point the new one to that location.  */
+  if (frame_pointer_needed)
+    {
+      int fp_offset = info->reg_offset[FRAME_POINTER_REGNUM];
+
+      /* ASM_SRC and DWARF_SRC both point to the frame header.  ASM_SRC is
+        based on ACCESSOR.BASE but DWARF_SRC is always based on the stack
+        pointer.  */
+      rtx asm_src = plus_constant (accessor.base,
+                                  fp_offset - accessor.base_offset);
+      rtx dwarf_src = plus_constant (sp, fp_offset);
+
+      /* Store the old frame pointer at (sp + FP_OFFSET).  */
+      frv_frame_access (&accessor, fp, fp_offset);
+
+      /* Set up the new frame pointer.  */
+      frv_frame_insn (gen_rtx_SET (VOIDmode, fp, asm_src),
+                     gen_rtx_SET (VOIDmode, fp, dwarf_src));
+
+      /* Access region C from the frame pointer.  */
+      accessor.base = fp;
+      accessor.base_offset = fp_offset;
+    }
+
+  /* Set up region C.  */
+  frv_frame_access_multi (&accessor, info, STACK_REGS_STRUCT);
+  frv_frame_access_multi (&accessor, info, STACK_REGS_LR);
+  frv_frame_access_multi (&accessor, info, STACK_REGS_STDARG);
+
+  /* Set up region A.  */
+  frv_frame_access_standard_regs (FRV_STORE, info);
+
+  /* If this is a varargs/stdarg function, issue a blockage to prevent the
+     scheduler from moving loads before the stores saving the registers.  */
+  if (info->stdarg_size > 0)
+    emit_insn (gen_blockage ());
+
+  /* Set up pic register/small data register for this function. */
+  if (flag_pic && cfun->uses_pic_offset_table)
+    emit_insn (gen_pic_prologue (gen_rtx_REG (Pmode, PIC_REGNO),
+                                gen_rtx_REG (Pmode, LR_REGNO),
+                                gen_rtx_REG (SImode, OFFSET_REGNO)));
+}
+
+\f
+/* Under frv, all of the work is done via frv_expand_epilogue, but
+   this function provides a convient place to do cleanup.  */
+
+static void
+frv_function_epilogue (file, size)
+     FILE *file ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
+{
+  frv_stack_cache = (frv_stack_t *)0;
+
+  /* zap last used registers for conditional execution.  */
+  memset ((PTR) &frv_ifcvt.tmp_reg, 0, sizeof (frv_ifcvt.tmp_reg));
+
+  /* release the bitmap of created insns.  */
+  BITMAP_XFREE (frv_ifcvt.scratch_insns_bitmap);
+}
+
+\f
+/* Called after register allocation to add any instructions needed for the
+   epilogue.  Using a epilogue insn is favored compared to putting all of the
+   instructions in the FUNCTION_PROLOGUE macro, since it allows the scheduler
+   to intermix instructions with the saves of the caller saved registers.  In
+   some cases, it might be necessary to emit a barrier instruction as the last
+   insn to prevent such scheduling.
+
+   If SIBCALL_P is true, the final branch back to the calling function is
+   omitted, and is used for sibling call (aka tail call) sites.  For sibcalls,
+   we must not clobber any arguments used for parameter passing or any stack
+   slots for arguments passed to the current function.  */
+
+void
+frv_expand_epilogue (sibcall_p)
+     int sibcall_p;
+{
+  frv_stack_t *info = frv_stack_info ();
+  rtx fp = frame_pointer_rtx;
+  rtx sp = stack_pointer_rtx;
+  rtx return_addr;
+  int fp_offset;
+
+  fp_offset = info->reg_offset[FRAME_POINTER_REGNUM];
+
+  /* Restore the stack pointer to its original value if alloca or the like
+     is used.  */
+  if (! current_function_sp_is_unchanging)
+    emit_insn (gen_addsi3 (sp, fp, frv_frame_offset_rtx (-fp_offset)));
+
+  /* Restore the callee-saved registers that were used in this function.  */
+  frv_frame_access_standard_regs (FRV_LOAD, info);
+
+  /* Set RETURN_ADDR to the address we should return to.  Set it to NULL if
+     no return instruction should be emitted.  */
+  if (sibcall_p)
+    return_addr = 0;
+  else if (info->save_p[LR_REGNO])
+    {
+      int lr_offset;
+      rtx mem;
+
+      /* Use the same method to access the link register's slot as we did in
+        the prologue.  In other words, use the frame pointer if available,
+        otherwise use the stack pointer.
+
+        LR_OFFSET is the offset of the link register's slot from the start
+        of the frame and MEM is a memory rtx for it.  */
+      lr_offset = info->reg_offset[LR_REGNO];
+      if (frame_pointer_needed)
+       mem = frv_frame_mem (Pmode, fp, lr_offset - fp_offset);
+      else
+       mem = frv_frame_mem (Pmode, sp, lr_offset);
+
+      /* Load the old link register into a GPR.  */
+      return_addr = gen_rtx_REG (Pmode, TEMP_REGNO);
+      emit_insn (gen_rtx_SET (VOIDmode, return_addr, mem));
+    }
+  else
+    return_addr = gen_rtx_REG (Pmode, LR_REGNO);
+
+  /* Restore the old frame pointer.  Emit a USE afterwards to make sure
+     the load is preserved.  */
+  if (frame_pointer_needed)
+    {
+      emit_insn (gen_rtx_SET (VOIDmode, fp, gen_rtx_MEM (Pmode, fp)));
+      emit_insn (gen_rtx_USE (VOIDmode, fp));
+    }
+
+  /* Deallocate the stack frame.  */
+  if (info->total_size != 0)
+    {
+      rtx offset = frv_frame_offset_rtx (info->total_size);
+      emit_insn (gen_stack_adjust (sp, sp, offset));
+    }
+
+  /* If this function uses eh_return, add the final stack adjustment now.  */
+  if (current_function_calls_eh_return)
+    emit_insn (gen_stack_adjust (sp, sp, EH_RETURN_STACKADJ_RTX));
+
+  if (return_addr)
+    emit_jump_insn (gen_epilogue_return (return_addr));
+}
+
+\f
+/* A C compound statement that outputs the assembler code for a thunk function,
+   used to implement C++ virtual function calls with multiple inheritance.  The
+   thunk acts as a wrapper around a virtual function, adjusting the implicit
+   object parameter before handing control off to the real function.
+
+   First, emit code to add the integer DELTA to the location that contains the
+   incoming first argument.  Assume that this argument contains a pointer, and
+   is the one used to pass the `this' pointer in C++.  This is the incoming
+   argument *before* the function prologue, e.g. `%o0' on a sparc.  The
+   addition must preserve the values of all other incoming arguments.
+
+   After the addition, emit code to jump to FUNCTION, which is a
+   `FUNCTION_DECL'.  This is a direct pure jump, not a call, and does not touch
+   the return address.  Hence returning from FUNCTION will return to whoever
+   called the current `thunk'.
+
+   The effect must be as if FUNCTION had been called directly with the adjusted
+   first argument.  This macro is responsible for emitting all of the code for
+   a thunk function; `FUNCTION_PROLOGUE' and `FUNCTION_EPILOGUE' are not
+   invoked.
+
+   The THUNK_FNDECL is redundant.  (DELTA and FUNCTION have already been
+   extracted from it.)  It might possibly be useful on some targets, but
+   probably not.
+
+   If you do not define this macro, the target-independent code in the C++
+   frontend will generate a less efficient heavyweight thunk that calls
+   FUNCTION instead of jumping to it.  The generic approach does not support
+   varargs.  */
+
+void
+frv_asm_output_mi_thunk (file, thunk_fndecl, delta, function)
+     FILE *file;
+     tree thunk_fndecl ATTRIBUTE_UNUSED;
+     long delta;
+     tree function;
+{
+  const char *name_func = XSTR (XEXP (DECL_RTL (function), 0), 0);
+  const char *name_arg0 = reg_names[FIRST_ARG_REGNUM];
+  const char *name_jmp = reg_names[JUMP_REGNO];
+  const char *parallel = ((PACKING_FLAG_USED_P ()) ? ".p" : "");
+
+  /* Do the add using an addi if possible */
+  if (IN_RANGE_P (delta, -2048, 2047))
+    fprintf (file, "\taddi %s,#%ld,%s\n", name_arg0, delta, name_arg0);
+  else
+    {
+      const char *name_add = reg_names[TEMP_REGNO];
+      fprintf (file, "\tsethi%s #hi(%ld),%s\n", parallel, delta, name_add);
+      fprintf (file, "\tsetlo #lo(%ld),%s\n", delta, name_add);
+      fprintf (file, "\tadd %s,%s,%s\n", name_add, name_arg0, name_arg0);
+    }
+
+  if (!flag_pic)
+    {
+      fprintf (file, "\tsethi%s #hi(", parallel);
+      assemble_name (file, name_func);
+      fprintf (file, "),%s\n", name_jmp);
+
+      fprintf (file, "\tsetlo #lo(");
+      assemble_name (file, name_func);
+      fprintf (file, "),%s\n", name_jmp);
+    }
+  else
+    {
+      /* Use JUMP_REGNO as a temporary PIC register.  */
+      const char *name_lr = reg_names[LR_REGNO];
+      const char *name_gppic = name_jmp;
+      const char *name_tmp = reg_names[TEMP_REGNO];
+
+      fprintf (file, "\tmovsg %s,%s\n", name_lr, name_tmp);
+      fprintf (file, "\tcall 1f\n");
+      fprintf (file, "1:\tmovsg %s,%s\n", name_lr, name_gppic);
+      fprintf (file, "\tmovgs %s,%s\n", name_tmp, name_lr);
+      fprintf (file, "\tsethi%s #gprelhi(1b),%s\n", parallel, name_tmp);
+      fprintf (file, "\tsetlo #gprello(1b),%s\n", name_tmp);
+      fprintf (file, "\tsub %s,%s,%s\n", name_gppic, name_tmp, name_gppic);
+
+      fprintf (file, "\tsethi%s #gprelhi(", parallel);
+      assemble_name (file, name_func);
+      fprintf (file, "),%s\n", name_tmp);
+
+      fprintf (file, "\tsetlo #gprello(");
+      assemble_name (file, name_func);
+      fprintf (file, "),%s\n", name_tmp);
+
+      fprintf (file, "\tadd %s,%s,%s\n", name_gppic, name_tmp, name_jmp);
+    }
+
+  /* Jump to the function address */
+  fprintf (file, "\tjmpl @(%s,%s)\n", name_jmp, reg_names[GPR_FIRST+0]);
+}
+
+\f
+/* A C expression which is nonzero if a function must have and use a frame
+   pointer.  This expression is evaluated in the reload pass.  If its value is
+   nonzero the function will have a frame pointer.
+
+   The expression can in principle examine the current function and decide
+   according to the facts, but on most machines the constant 0 or the constant
+   1 suffices.  Use 0 when the machine allows code to be generated with no
+   frame pointer, and doing so saves some time or space.  Use 1 when there is
+   no possible advantage to avoiding a frame pointer.
+
+   In certain cases, the compiler does not know how to produce valid code
+   without a frame pointer.  The compiler recognizes those cases and
+   automatically gives the function a frame pointer regardless of what
+   `FRAME_POINTER_REQUIRED' says.  You don't need to worry about them.
+
+   In a function that does not require a frame pointer, the frame pointer
+   register can be allocated for ordinary usage, unless you mark it as a fixed
+   register.  See `FIXED_REGISTERS' for more information.  */
+
+/* On frv, create a frame whenever we need to create stack */
+
+int
+frv_frame_pointer_required ()
+{
+  if (! current_function_is_leaf)
+    return TRUE;
+
+  if (get_frame_size () != 0)
+    return TRUE;
+
+  if (cfun->stdarg)
+    return TRUE;
+
+  if (!current_function_sp_is_unchanging)
+    return TRUE;
+
+  if (flag_pic && cfun->uses_pic_offset_table)
+    return TRUE;
+
+  if (profile_flag)
+    return TRUE;
+
+  if (cfun->machine->frame_needed)
+    return TRUE;
+
+  return FALSE;
+}
+
+\f
+/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'.  It specifies the
+   initial difference between the specified pair of registers.  This macro must
+   be defined if `ELIMINABLE_REGS' is defined.  */
+
+/* See frv_stack_info for more details on the frv stack frame.  */
+
+int
+frv_initial_elimination_offset (from, to)
+     int from;
+     int to;
+{
+  frv_stack_t *info = frv_stack_info ();
+  int ret = 0;
+
+  if (to == STACK_POINTER_REGNUM && from == ARG_POINTER_REGNUM)
+    ret = info->total_size - info->pretend_size;
+
+  else if (to == STACK_POINTER_REGNUM && from == FRAME_POINTER_REGNUM)
+    ret = - info->reg_offset[FRAME_POINTER_REGNUM];
+
+  else if (to == FRAME_POINTER_REGNUM && from == ARG_POINTER_REGNUM)
+    ret = (info->total_size
+          - info->reg_offset[FRAME_POINTER_REGNUM]
+          - info->pretend_size);
+
+  else
+    abort ();
+
+  if (TARGET_DEBUG_STACK)
+    fprintf (stderr, "Eliminate %s to %s by adding %d\n",
+            reg_names [from], reg_names[to], ret);
+
+  return ret;
+}
+
+\f
+/* This macro offers an alternative to using `__builtin_saveregs' and defining
+   the macro `EXPAND_BUILTIN_SAVEREGS'.  Use it to store the anonymous register
+   arguments into the stack so that all the arguments appear to have been
+   passed consecutively on the stack.  Once this is done, you can use the
+   standard implementation of varargs that works for machines that pass all
+   their arguments on the stack.
+
+   The argument ARGS_SO_FAR is the `CUMULATIVE_ARGS' data structure, containing
+   the values that obtain after processing of the named arguments.  The
+   arguments MODE and TYPE describe the last named argument--its machine mode
+   and its data type as a tree node.
+
+   The macro implementation should do two things: first, push onto the stack
+   all the argument registers *not* used for the named arguments, and second,
+   store the size of the data thus pushed into the `int'-valued variable whose
+   name is supplied as the argument PRETEND_ARGS_SIZE.  The value that you
+   store here will serve as additional offset for setting up the stack frame.
+
+   Because you must generate code to push the anonymous arguments at compile
+   time without knowing their data types, `SETUP_INCOMING_VARARGS' is only
+   useful on machines that have just a single category of argument register and
+   use it uniformly for all data types.
+
+   If the argument SECOND_TIME is nonzero, it means that the arguments of the
+   function are being analyzed for the second time.  This happens for an inline
+   function, which is not actually compiled until the end of the source file.
+   The macro `SETUP_INCOMING_VARARGS' should not generate any instructions in
+   this case.  */
+
+void
+frv_setup_incoming_varargs (cum, mode, type, pretend_size, second_time)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type ATTRIBUTE_UNUSED;
+     int *pretend_size;
+     int second_time;
+{
+  if (TARGET_DEBUG_ARG)
+    fprintf (stderr,
+            "setup_vararg: words = %2d, mode = %4s, pretend_size = %d, second_time = %d\n",
+            *cum, GET_MODE_NAME (mode), *pretend_size, second_time);
+}
+
+\f
+/* If defined, is a C expression that produces the machine-specific code for a
+   call to `__builtin_saveregs'.  This code will be moved to the very beginning
+   of the function, before any parameter access are made.  The return value of
+   this function should be an RTX that contains the value to use as the return
+   of `__builtin_saveregs'.
+
+   If this macro is not defined, the compiler will output an ordinary call to
+   the library function `__builtin_saveregs'.  */
+
+rtx
+frv_expand_builtin_saveregs ()
+{
+  int offset = UNITS_PER_WORD * FRV_NUM_ARG_REGS;
+
+  if (TARGET_DEBUG_ARG)
+    fprintf (stderr, "expand_builtin_saveregs: offset from ap = %d\n",
+            offset);
+
+  return gen_rtx (PLUS, Pmode, virtual_incoming_args_rtx, GEN_INT (- offset));
+}
+
+\f
+/* Expand __builtin_va_start to do the va_start macro.  */
+
+void
+frv_expand_builtin_va_start (valist, nextarg)
+     tree valist;
+     rtx nextarg;
+{
+  tree t;
+  int num = cfun->args_info - FIRST_ARG_REGNUM - FRV_NUM_ARG_REGS;
+
+  nextarg = gen_rtx_PLUS (Pmode, virtual_incoming_args_rtx,
+                         GEN_INT (UNITS_PER_WORD * num));
+
+  if (TARGET_DEBUG_ARG)
+    {
+      fprintf (stderr, "va_start: args_info = %d, num = %d\n",
+              cfun->args_info, num);
+
+      debug_rtx (nextarg);
+    }
+
+  t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+            make_tree (ptr_type_node, nextarg));
+  TREE_SIDE_EFFECTS (t) = 1;
+
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+}
+
+\f
+/* Expand __builtin_va_arg to do the va_arg macro.  */
+
+rtx
+frv_expand_builtin_va_arg(valist, type)
+     tree valist;
+     tree type;
+{
+  rtx addr;
+  rtx mem;
+  rtx reg;
+
+  if (TARGET_DEBUG_ARG)
+    {
+      fprintf (stderr, "va_arg:\n");
+      debug_tree (type);
+    }
+
+  if (! AGGREGATE_TYPE_P (type))
+    return std_expand_builtin_va_arg (valist, type);
+
+  addr = std_expand_builtin_va_arg (valist, ptr_type_node);
+  mem  = gen_rtx_MEM (Pmode, addr);
+  reg  = gen_reg_rtx (Pmode);
+
+  set_mem_alias_set (mem, get_varargs_alias_set ());
+  emit_move_insn (reg, mem);
+
+  return reg;
+}
+
+\f
+/* Expand a block move operation, and return 1 if successful.  Return 0
+   if we should let the compiler generate normal code.
+
+   operands[0] is the destination
+   operands[1] is the source
+   operands[2] is the length
+   operands[3] is the alignment */
+
+/* Maximum number of loads to do before doing the stores */
+#ifndef MAX_MOVE_REG
+#define MAX_MOVE_REG 4
+#endif
+
+/* Maximum number of total loads to do.  */
+#ifndef TOTAL_MOVE_REG
+#define TOTAL_MOVE_REG 8
+#endif
+
+int
+frv_expand_block_move (operands)
+     rtx operands[];
+{
+  rtx orig_dest = operands[0];
+  rtx orig_src = operands[1];
+  rtx bytes_rtx        = operands[2];
+  rtx align_rtx = operands[3];
+  int constp   = (GET_CODE (bytes_rtx) == CONST_INT);
+  int align;
+  int bytes;
+  int offset;
+  int num_reg;
+  int i;
+  rtx src_reg;
+  rtx dest_reg;
+  rtx src_addr;
+  rtx dest_addr;
+  rtx src_mem;
+  rtx dest_mem;
+  rtx tmp_reg;
+  rtx stores[MAX_MOVE_REG];
+  int move_bytes;
+  enum machine_mode mode;
+
+  /* If this is not a fixed size move, just call memcpy */
+  if (! constp)
+    return FALSE;
+
+  /* If this is not a fixed size alignment, abort */
+  if (GET_CODE (align_rtx) != CONST_INT)
+    abort ();
+
+  align = INTVAL (align_rtx);
+
+  /* Anything to move? */
+  bytes = INTVAL (bytes_rtx);
+  if (bytes <= 0)
+    return TRUE;
+
+  /* Don't support real large moves.  */
+  if (bytes > TOTAL_MOVE_REG*align)
+    return FALSE;
+
+  /* Move the address into scratch registers.  */
+  dest_reg = copy_addr_to_reg (XEXP (orig_dest, 0));
+  src_reg  = copy_addr_to_reg (XEXP (orig_src,  0));
+
+  num_reg = offset = 0;
+  for ( ; bytes > 0; (bytes -= move_bytes), (offset += move_bytes))
+    {
+      /* Calculate the correct offset for src/dest */
+      if (offset == 0)
+       {
+         src_addr  = src_reg;
+         dest_addr = dest_reg;
+       }
+      else
+       {
+         src_addr = plus_constant (src_reg, offset);
+         dest_addr = plus_constant (dest_reg, offset);
+       }
+
+      /* Generate the appropriate load and store, saving the stores
+        for later.  */
+      if (bytes >= 4 && align >= 4)
+       mode = SImode;
+      else if (bytes >= 2 && align >= 2)
+       mode = HImode;
+      else
+       mode = QImode;
+
+      move_bytes = GET_MODE_SIZE (mode);
+      tmp_reg = gen_reg_rtx (mode);
+      src_mem = change_address (orig_src, mode, src_addr);
+      dest_mem = change_address (orig_dest, mode, dest_addr);
+      emit_insn (gen_rtx_SET (VOIDmode, tmp_reg, src_mem));
+      stores[num_reg++] = gen_rtx_SET (VOIDmode, dest_mem, tmp_reg);
+
+      if (num_reg >= MAX_MOVE_REG)
+       {
+         for (i = 0; i < num_reg; i++)
+           emit_insn (stores[i]);
+         num_reg = 0;
+       }
+    }
+
+  for (i = 0; i < num_reg; i++)
+    emit_insn (stores[i]);
+
+  return TRUE;
+}
+
+\f
+/* Expand a block clear operation, and return 1 if successful.  Return 0
+   if we should let the compiler generate normal code.
+
+   operands[0] is the destination
+   operands[1] is the length
+   operands[2] is the alignment */
+
+int
+frv_expand_block_clear (operands)
+     rtx operands[];
+{
+  rtx orig_dest = operands[0];
+  rtx bytes_rtx        = operands[1];
+  rtx align_rtx = operands[2];
+  int constp   = (GET_CODE (bytes_rtx) == CONST_INT);
+  int align;
+  int bytes;
+  int offset;
+  int num_reg;
+  rtx dest_reg;
+  rtx dest_addr;
+  rtx dest_mem;
+  int clear_bytes;
+  enum machine_mode mode;
+
+  /* If this is not a fixed size move, just call memcpy */
+  if (! constp)
+    return FALSE;
+
+  /* If this is not a fixed size alignment, abort */
+  if (GET_CODE (align_rtx) != CONST_INT)
+    abort ();
+
+  align = INTVAL (align_rtx);
+
+  /* Anything to move? */
+  bytes = INTVAL (bytes_rtx);
+  if (bytes <= 0)
+    return TRUE;
+
+  /* Don't support real large clears.  */
+  if (bytes > TOTAL_MOVE_REG*align)
+    return FALSE;
+
+  /* Move the address into a scratch register.  */
+  dest_reg = copy_addr_to_reg (XEXP (orig_dest, 0));
+
+  num_reg = offset = 0;
+  for ( ; bytes > 0; (bytes -= clear_bytes), (offset += clear_bytes))
+    {
+      /* Calculate the correct offset for src/dest */
+      dest_addr = ((offset == 0)
+                  ? dest_reg
+                  : plus_constant (dest_reg, offset));
+
+      /* Generate the appropriate store of gr0 */
+      if (bytes >= 4 && align >= 4)
+       mode = SImode;
+      else if (bytes >= 2 && align >= 2)
+       mode = HImode;
+      else
+       mode = QImode;
+
+      clear_bytes = GET_MODE_SIZE (mode);
+      dest_mem = change_address (orig_dest, mode, dest_addr);
+      emit_insn (gen_rtx_SET (VOIDmode, dest_mem, const0_rtx));
+    }
+
+  return TRUE;
+}
+
+\f
+/* The following variable is used to output modifiers of assembler
+   code of the current output insn.. */
+
+static rtx *frv_insn_operands;
+
+/* The following function is used to add assembler insn code suffix .p
+   if it is necessary. */
+
+const char *
+frv_asm_output_opcode (f, ptr)
+     FILE *f;
+     const char *ptr;
+{
+  int c;
+
+  if (! PACKING_FLAG_USED_P())
+    return ptr;
+
+  for (; *ptr && *ptr != ' ' && *ptr != '\t';)
+    {
+      c = *ptr++;
+      if (c == '%' && ((*ptr >= 'a' && *ptr <= 'z')
+                      || (*ptr >= 'A' && *ptr <= 'Z')))
+       {
+         int letter = *ptr++;
+
+         c = atoi (ptr);
+         frv_print_operand (f, frv_insn_operands [c], letter);
+         while ((c = *ptr) >= '0' && c <= '9')
+           ptr++;
+       }
+      else
+       fputc (c, f);
+    }
+
+  if (!frv_insn_packing_flag)
+    fprintf (f, ".p");
+
+  return ptr;
+}
+
+/* The following function sets up the packing bit for the current
+   output insn.  Remember that the function is not called for asm
+   insns. */
+
+void
+frv_final_prescan_insn (insn, opvec, noperands)
+     rtx insn;
+     rtx *opvec;
+     int noperands ATTRIBUTE_UNUSED;
+{
+  if (! PACKING_FLAG_USED_P())
+    return;
+
+  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+    return;
+
+  frv_insn_operands = opvec;
+
+  /* Look for the next printable instruction.  frv_pack_insns () has set
+     things up so that any printable instruction will have TImode if it
+     starts a new packet and VOIDmode if it should be packed with the
+     previous instruction.
+
+     Printable instructions will be asm_operands or match one of the .md
+     patterns.  Since asm instructions cannot be packed -- and will
+     therefore have TImode -- this loop terminates on any recognisable
+     instruction, and on any unrecognisable instruction with TImode.  */
+  for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
+    {
+      if (NOTE_P (insn))
+       continue;
+      else if (!INSN_P (insn))
+       break;
+      else if (GET_MODE (insn) == TImode || INSN_CODE (insn) != -1)
+       break;
+    }
+
+  /* Set frv_insn_packing_flag to FALSE if the next instruction should
+     be packed with this one.  Set it to TRUE otherwise.  If the next
+     instruction is an asm insntruction, this statement will set the
+     flag to TRUE, and that value will still hold when the asm operands
+     themselves are printed.  */
+  frv_insn_packing_flag = ! (insn && INSN_P (insn)
+                            && GET_MODE (insn) != TImode);
+}
+
+
+\f
+/* A C expression whose value is RTL representing the address in a stack frame
+   where the pointer to the caller's frame is stored.  Assume that FRAMEADDR is
+   an RTL expression for the address of the stack frame itself.
+
+   If you don't define this macro, the default is to return the value of
+   FRAMEADDR--that is, the stack frame address is also the address of the stack
+   word that points to the previous frame.  */
+
+/* The default is correct, but we need to make sure the frame gets created.  */
+rtx
+frv_dynamic_chain_address (frame)
+     rtx frame;
+{
+  cfun->machine->frame_needed = 1;
+  return frame;
+}
+
+
+/* A C expression whose value is RTL representing the value of the return
+   address for the frame COUNT steps up from the current frame, after the
+   prologue.  FRAMEADDR is the frame pointer of the COUNT frame, or the frame
+   pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
+   defined.
+
+   The value of the expression must always be the correct address when COUNT is
+   zero, but may be `NULL_RTX' if there is not way to determine the return
+   address of other frames.  */
+
+rtx
+frv_return_addr_rtx (count, frame)
+     int count ATTRIBUTE_UNUSED;
+     rtx frame;
+{
+  cfun->machine->frame_needed = 1;
+  return gen_rtx_MEM (Pmode, plus_constant (frame, 8));
+}
+
+/* Given a memory reference MEMREF, interpret the referenced memory as
+   an array of MODE values, and return a reference to the element
+   specified by INDEX.  Assume that any pre-modification implicit in
+   MEMREF has already happened.
+
+   MEMREF must be a legitimate operand for modes larger than SImode.
+   GO_IF_LEGITIMATE_ADDRESS forbids register+register addresses, which
+   this function cannot handle.  */
+rtx
+frv_index_memory (memref, mode, index)
+     rtx memref;
+     enum machine_mode mode;
+     int index;
+{
+  rtx base = XEXP (memref, 0);
+  if (GET_CODE (base) == PRE_MODIFY)
+    base = XEXP (base, 0);
+  return change_address (memref, mode,
+                        plus_constant (base, index * GET_MODE_SIZE (mode)));
+}
+
+\f
+/* Print a memory address as an operand to reference that memory location.  */
+void
+frv_print_operand_address (stream, x)
+     FILE * stream;
+     rtx    x;
+{
+  if (GET_CODE (x) == MEM)
+    x = XEXP (x, 0);
+
+  switch (GET_CODE (x))
+    {
+    case REG:
+      fputs (reg_names [ REGNO (x)], stream);
+      return;
+
+    case CONST_INT:
+      fprintf (stream, "%ld", (long) INTVAL (x));
+      return;
+
+    case SYMBOL_REF:
+      assemble_name (stream, XSTR (x, 0));
+      return;
+
+    case LABEL_REF:
+    case CONST:
+      output_addr_const (stream, x);
+      return;
+
+    default:
+      break;
+    }
+
+  fatal_insn ("Bad insn to frv_print_operand_address:", x);
+}
+
+\f
+static void
+frv_print_operand_memory_reference_reg (stream, x)
+     FILE *stream;
+     rtx x;
+{
+  int regno = true_regnum (x);
+  if (GPR_P (regno))
+    fputs (reg_names[regno], stream);
+  else
+    fatal_insn ("Bad register to frv_print_operand_memory_reference_reg:", x);
+}
+
+/* Print a memory reference suitable for the ld/st instructions.  */
+
+static void
+frv_print_operand_memory_reference (stream, x, addr_offset)
+     FILE *stream;
+     rtx x;
+     int addr_offset;
+{
+  rtx x0 = NULL_RTX;
+  rtx x1 = NULL_RTX;
+
+  switch (GET_CODE (x))
+    {
+    case SUBREG:
+    case REG:
+      x0 = x;
+      break;
+
+    case PRE_MODIFY:           /* (pre_modify (reg) (plus (reg) (reg))) */
+      x0 = XEXP (x, 0);
+      x1 = XEXP (XEXP (x, 1), 1);
+      break;
+
+    case CONST_INT:
+      x1 = x;
+      break;
+
+    case PLUS:
+      x0 = XEXP (x, 0);
+      x1 = XEXP (x, 1);
+      if (GET_CODE (x0) == CONST_INT)
+       {
+         x0 = XEXP (x, 1);
+         x1 = XEXP (x, 0);
+       }
+      break;
+
+    default:
+      fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
+      break;
+
+    }
+
+  if (addr_offset)
+    {
+      if (!x1)
+       x1 = const0_rtx;
+      else if (GET_CODE (x1) != CONST_INT)
+       fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
+    }
+
+  fputs ("@(", stream);
+  if (!x0)
+    fputs (reg_names[GPR_R0], stream);
+  else if (GET_CODE (x0) == REG || GET_CODE (x0) == SUBREG)
+    frv_print_operand_memory_reference_reg (stream, x0);
+  else
+    fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
+
+  fputs (",", stream);
+  if (!x1)
+    fputs (reg_names [GPR_R0], stream);
+
+  else
+    {
+      switch (GET_CODE (x1))
+       {
+       case SUBREG:
+       case REG:
+         frv_print_operand_memory_reference_reg (stream, x1);
+         break;
+
+       case CONST_INT:
+         fprintf (stream, "%ld", (long) (INTVAL (x1) + addr_offset));
+         break;
+
+       case SYMBOL_REF:
+         if (x0 && GET_CODE (x0) == REG && REGNO (x0) == SDA_BASE_REG
+             && symbol_ref_small_data_p (x1))
+           {
+             fputs ("#gprel12(", stream);
+             assemble_name (stream, XSTR (x1, 0));
+             fputs (")", stream);
+           }
+         else
+           fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
+         break;
+
+       case CONST:
+         if (x0 && GET_CODE (x0) == REG && REGNO (x0) == SDA_BASE_REG
+             && const_small_data_p (x1))
+           {
+             fputs ("#gprel12(", stream);
+             assemble_name (stream, XSTR (XEXP (XEXP (x1, 0), 0), 0));
+             fprintf (stream, "+%d)", INTVAL (XEXP (XEXP (x1, 0), 1)));
+           }
+         else
+           fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
+         break;
+
+       default:
+         fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
+       }
+    }
+
+  fputs (")", stream);
+}
+
+\f
+/* Return 2 for likely branches and 0 for non-likely branches  */
+
+#define FRV_JUMP_LIKELY 2
+#define FRV_JUMP_NOT_LIKELY 0
+
+static int
+frv_print_operand_jump_hint (insn)
+     rtx insn;
+{
+  rtx note;
+  rtx labelref;
+  int ret;
+  HOST_WIDE_INT prob = -1;
+  enum { UNKNOWN, BACKWARD, FORWARD } jump_type = UNKNOWN;
+
+  if (GET_CODE (insn) != JUMP_INSN)
+    abort ();
+
+  /* Assume any non-conditional jump is likely.  */
+  if (! any_condjump_p (insn))
+    ret = FRV_JUMP_LIKELY;
+
+  else
+    {
+      labelref = condjump_label (insn);
+      if (labelref)
+       {
+         rtx label = XEXP (labelref, 0);
+         jump_type = (insn_current_address > INSN_ADDRESSES (INSN_UID (label))
+                      ? BACKWARD
+                      : FORWARD);
+       }
+
+      note = find_reg_note (insn, REG_BR_PROB, 0);
+      if (!note)
+       ret = ((jump_type == BACKWARD) ? FRV_JUMP_LIKELY : FRV_JUMP_NOT_LIKELY);
+
+      else
+       {
+         prob = INTVAL (XEXP (note, 0));
+         ret = ((prob >= (REG_BR_PROB_BASE / 2))
+                ? FRV_JUMP_LIKELY
+                : FRV_JUMP_NOT_LIKELY);
+       }
+    }
+
+#if 0
+  if (TARGET_DEBUG)
+    {
+      char *direction;
+
+      switch (jump_type)
+       {
+       default:
+       case UNKNOWN:   direction = "unknown jump direction";   break;
+       case BACKWARD:  direction = "jump backward";            break;
+       case FORWARD:   direction = "jump forward";             break;
+       }
+
+      fprintf (stderr,
+              "%s: uid %ld, %s, probability = %ld, max prob. = %ld, hint = %d\n",
+              IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
+              (long)INSN_UID (insn), direction, (long)prob,
+              (long)REG_BR_PROB_BASE, ret);
+    }
+#endif
+
+  return ret;
+}
+
+\f
+/* Print an operand to a assembler instruction.
+
+   `%' followed by a letter and a digit says to output an operand in an
+   alternate fashion.  Four letters have standard, built-in meanings described
+   below.  The machine description macro `PRINT_OPERAND' can define additional
+   letters with nonstandard meanings.
+
+   `%cDIGIT' can be used to substitute an operand that is a constant value
+   without the syntax that normally indicates an immediate operand.
+
+   `%nDIGIT' is like `%cDIGIT' except that the value of the constant is negated
+   before printing.
+
+   `%aDIGIT' can be used to substitute an operand as if it were a memory
+   reference, with the actual operand treated as the address.  This may be
+   useful when outputting a "load address" instruction, because often the
+   assembler syntax for such an instruction requires you to write the operand
+   as if it were a memory reference.
+
+   `%lDIGIT' is used to substitute a `label_ref' into a jump instruction.
+
+   `%=' outputs a number which is unique to each instruction in the entire
+   compilation.  This is useful for making local labels to be referred to more
+   than once in a single template that generates multiple assembler
+   instructions.
+
+   `%' followed by a punctuation character specifies a substitution that does
+   not use an operand.  Only one case is standard: `%%' outputs a `%' into the
+   assembler code.  Other nonstandard cases can be defined in the
+   `PRINT_OPERAND' macro.  You must also define which punctuation characters
+   are valid with the `PRINT_OPERAND_PUNCT_VALID_P' macro.  */
+
+void
+frv_print_operand (file, x, code)
+     FILE * file;
+     rtx    x;
+     int    code;
+{
+  HOST_WIDE_INT value;
+  int offset;
+
+  if (code != 0 && !isalpha (code))
+    value = 0;
+
+  else if (GET_CODE (x) == CONST_INT)
+    value = INTVAL (x);
+
+  else if (GET_CODE (x) == CONST_DOUBLE)
+    {
+      if (GET_MODE (x) == SFmode)
+       {
+         REAL_VALUE_TYPE rv;
+         long l;
+
+         REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+         REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+         value = l;
+       }
+
+      else if (GET_MODE (x) == VOIDmode)
+       value = CONST_DOUBLE_LOW (x);
+
+      else
+        fatal_insn ("Bad insn in frv_print_operand, bad const_double", x);
+    }
+
+  else
+    value = 0;
+
+  switch (code)
+    {
+
+    case '.':
+      /* Output r0 */
+      fputs (reg_names[GPR_R0], file);
+      break;
+
+    case '#':
+      fprintf (file, "%d", frv_print_operand_jump_hint (current_output_insn));
+      break;
+
+    case SDATA_FLAG_CHAR:
+      /* Output small data area base register (gr16). */
+      fputs (reg_names[SDA_BASE_REG], file);
+      break;
+
+    case '~':
+      /* Output pic register (gr17). */
+      fputs (reg_names[PIC_REGNO], file);
+      break;
+
+    case '*':
+      /* Output the temporary integer CCR register */
+      fputs (reg_names[ICR_TEMP], file);
+      break;
+
+    case '&':
+      /* Output the temporary integer CC register */
+      fputs (reg_names[ICC_TEMP], file);
+      break;
+
+    /* case 'a': print an address */
+
+    case 'C':
+      /* Print appropriate test for integer branch false operation */
+      switch (GET_CODE (x))
+       {
+       default:
+         fatal_insn ("Bad insn to frv_print_operand, 'C' modifier:", x);
+
+       case EQ:  fputs ("ne", file); break;
+       case NE:  fputs ("eq", file); break;
+       case LT:  fputs ("ge", file); break;
+       case LE:  fputs ("gt", file); break;
+       case GT:  fputs ("le", file); break;
+       case GE:  fputs ("lt", file); break;
+       case LTU: fputs ("nc", file); break;
+       case LEU: fputs ("hi", file); break;
+       case GTU: fputs ("ls", file); break;
+       case GEU: fputs ("c",  file); break;
+       }
+      break;
+
+    /* case 'c': print a constant without the constant prefix.  If
+       CONSTANT_ADDRESS_P(x) is not true, PRINT_OPERAND is called.  */
+
+    case 'c':
+      /* Print appropriate test for integer branch true operation */
+      switch (GET_CODE (x))
+       {
+       default:
+         fatal_insn ("Bad insn to frv_print_operand, 'c' modifier:", x);
+
+       case EQ:  fputs ("eq", file); break;
+       case NE:  fputs ("ne", file); break;
+       case LT:  fputs ("lt", file); break;
+       case LE:  fputs ("le", file); break;
+       case GT:  fputs ("gt", file); break;
+       case GE:  fputs ("ge", file); break;
+       case LTU: fputs ("c",  file); break;
+       case LEU: fputs ("ls", file); break;
+       case GTU: fputs ("hi", file); break;
+       case GEU: fputs ("nc", file); break;
+       }
+      break;
+
+    case 'e':
+      /* Print 1 for a NE and 0 for an EQ to give the final argument
+        for a conditional instruction.  */
+      if (GET_CODE (x) == NE)
+       fputs ("1", file);
+
+      else if (GET_CODE (x) == EQ)
+       fputs ("0", file);
+
+      else
+       fatal_insn ("Bad insn to frv_print_operand, 'e' modifier:", x);
+      break;
+
+    case 'F':
+      /* Print appropriate test for floating point branch false operation */
+      switch (GET_CODE (x))
+       {
+       default:
+         fatal_insn ("Bad insn to frv_print_operand, 'F' modifier:", x);
+
+       case EQ:  fputs ("ne",  file); break;
+       case NE:  fputs ("eq",  file); break;
+       case LT:  fputs ("uge", file); break;
+       case LE:  fputs ("ug",  file); break;
+       case GT:  fputs ("ule", file); break;
+       case GE:  fputs ("ul",  file); break;
+       }
+      break;
+
+    case 'f':
+      /* Print appropriate test for floating point branch true operation */
+      switch (GET_CODE (x))
+       {
+       default:
+         fatal_insn ("Bad insn to frv_print_operand, 'f' modifier:", x);
+
+       case EQ:  fputs ("eq",  file); break;
+       case NE:  fputs ("ne",  file); break;
+       case LT:  fputs ("lt",  file); break;
+       case LE:  fputs ("le",  file); break;
+       case GT:  fputs ("gt",  file); break;
+       case GE:  fputs ("ge",  file); break;
+       }
+      break;
+
+    case 'I':
+      /* Print 'i' if the operand is a constant, or is a memory reference that
+         adds a constant */
+      if (GET_CODE (x) == MEM)
+       x = ((GET_CODE (XEXP (x, 0)) == PLUS)
+            ? XEXP (XEXP (x, 0), 1)
+            : XEXP (x, 0));
+
+      switch (GET_CODE (x))
+       {
+       default:
+         break;
+
+       case CONST_INT:
+       case SYMBOL_REF:
+       case CONST:
+         fputs ("i", file);
+         break;
+       }
+      break;
+
+    case 'i':
+      /* For jump instructions, print 'i' if the operand is a constant or
+         is an expression that adds a constant */
+      if (GET_CODE (x) == CONST_INT)
+        fputs ("i", file);
+
+      else
+        {
+          if (GET_CODE (x) == CONST_INT
+              || (GET_CODE (x) == PLUS
+                  && (GET_CODE (XEXP (x, 1)) == CONST_INT
+                      || GET_CODE (XEXP (x, 0)) == CONST_INT)))
+            fputs ("i", file);
+        }
+      break;
+
+    case 'L':
+      /* Print the lower register of a double word register pair */
+      if (GET_CODE (x) == REG)
+       fputs (reg_names[ REGNO (x)+1 ], file);
+      else
+       fatal_insn ("Bad insn to frv_print_operand, 'L' modifier:", x);
+      break;
+
+    /* case 'l': print a LABEL_REF */
+
+    case 'M':
+    case 'N':
+      /* Print a memory reference for ld/st/jmp, %N prints a memory reference
+         for the second word of double memory operations.  */
+      offset = (code == 'M') ? 0 : UNITS_PER_WORD;
+      switch (GET_CODE (x))
+       {
+       default:
+         fatal_insn ("Bad insn to frv_print_operand, 'M/N' modifier:", x);
+
+       case MEM:
+         frv_print_operand_memory_reference (file, XEXP (x, 0), offset);
+         break;
+
+       case REG:
+       case SUBREG:
+       case CONST_INT:
+       case PLUS:
+        case SYMBOL_REF:
+         frv_print_operand_memory_reference (file, x, offset);
+         break;
+       }
+      break;
+
+    case 'O':
+      /* Print the opcode of a command.  */
+      switch (GET_CODE (x))
+       {
+       default:
+         fatal_insn ("Bad insn to frv_print_operand, 'O' modifier:", x);
+
+       case PLUS:     fputs ("add", file); break;
+       case MINUS:    fputs ("sub", file); break;
+       case AND:      fputs ("and", file); break;
+       case IOR:      fputs ("or",  file); break;
+       case XOR:      fputs ("xor", file); break;
+       case ASHIFT:   fputs ("sll", file); break;
+       case ASHIFTRT: fputs ("sra", file); break;
+       case LSHIFTRT: fputs ("srl", file); break;
+       }
+      break;
+
+    /* case 'n': negate and print a constant int */
+
+    case 'P':
+      /* Print PIC label using operand as the number.  */
+      if (GET_CODE (x) != CONST_INT)
+       fatal_insn ("Bad insn to frv_print_operand, P modifier:", x);
+
+      fprintf (file, ".LCF%ld", (long)INTVAL (x));
+      break;
+
+    case 'U':
+      /* Print 'u' if the operand is a update load/store */
+      if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
+       fputs ("u", file);
+      break;
+
+    case 'z':
+      /* If value is 0, print gr0, otherwise it must be a register  */
+      if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0)
+       fputs (reg_names[GPR_R0], file);
+
+      else if (GET_CODE (x) == REG)
+        fputs (reg_names [REGNO (x)], file);
+
+      else
+        fatal_insn ("Bad insn in frv_print_operand, z case", x);
+      break;
+
+    case 'x':
+      /* Print constant in hex */
+      if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
+        {
+         fprintf (file, "%s0x%.4lx", IMMEDIATE_PREFIX, (long) value);
+         break;
+       }
+
+      /* fall through */
+
+    case '\0':
+      if (GET_CODE (x) == REG)
+        fputs (reg_names [REGNO (x)], file);
+
+      else if (GET_CODE (x) == CONST_INT
+              || GET_CODE (x) == CONST_DOUBLE)
+        fprintf (file, "%s%ld", IMMEDIATE_PREFIX, (long) value);
+
+      else if (GET_CODE (x) == MEM)
+        frv_print_operand_address (file, XEXP (x, 0));
+
+      else if (CONSTANT_ADDRESS_P (x))
+        frv_print_operand_address (file, x);
+
+      else
+        fatal_insn ("Bad insn in frv_print_operand, 0 case", x);
+
+      break;
+
+    default:
+      fatal_insn ("frv_print_operand: unknown code", x);
+      break;
+    }
+
+  return;
+}
+
+\f
+/* A C statement (sans semicolon) for initializing the variable CUM for the
+   state at the beginning of the argument list.  The variable has type
+   `CUMULATIVE_ARGS'.  The value of FNTYPE is the tree node for the data type
+   of the function which will receive the args, or 0 if the args are to a
+   compiler support library function.  The value of INDIRECT is nonzero when
+   processing an indirect call, for example a call through a function pointer.
+   The value of INDIRECT is zero for a call to an explicitly named function, a
+   library function call, or when `INIT_CUMULATIVE_ARGS' is used to find
+   arguments for the function being compiled.
+
+   When processing a call to a compiler support library function, LIBNAME
+   identifies which one.  It is a `symbol_ref' rtx which contains the name of
+   the function, as a string.  LIBNAME is 0 when an ordinary C function call is
+   being processed.  Thus, each time this macro is called, either LIBNAME or
+   FNTYPE is nonzero, but never both of them at once.  */
+
+void
+frv_init_cumulative_args (cum, fntype, libname, indirect, incoming)
+     CUMULATIVE_ARGS *cum;
+     tree fntype;
+     rtx libname;
+     int indirect;
+     int incoming;
+{
+  *cum = FIRST_ARG_REGNUM;
+
+  if (TARGET_DEBUG_ARG)
+    {
+      fprintf (stderr, "\ninit_cumulative_args:");
+      if (indirect)
+       fputs (" indirect", stderr);
+
+      if (incoming)
+       fputs (" incoming", stderr);
+
+      if (fntype)
+       {
+         tree ret_type = TREE_TYPE (fntype);
+         fprintf (stderr, " return=%s,",
+                  tree_code_name[ (int)TREE_CODE (ret_type) ]);
+       }
+
+      if (libname && GET_CODE (libname) == SYMBOL_REF)
+       fprintf (stderr, " libname=%s", XSTR (libname, 0));
+
+      if (cfun->returns_struct)
+       fprintf (stderr, " return-struct");
+
+      putc ('\n', stderr);
+    }
+}
+
+\f
+/* If defined, a C expression that gives the alignment boundary, in bits, of an
+   argument with the specified mode and type.  If it is not defined,
+   `PARM_BOUNDARY' is used for all arguments.  */
+
+int
+frv_function_arg_boundary (mode, type)
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     tree type ATTRIBUTE_UNUSED;
+{
+  return BITS_PER_WORD;
+}
+
+\f
+/* A C expression that controls whether a function argument is passed in a
+   register, and which register.
+
+   The arguments are CUM, of type CUMULATIVE_ARGS, which summarizes (in a way
+   defined by INIT_CUMULATIVE_ARGS and FUNCTION_ARG_ADVANCE) all of the previous
+   arguments so far passed in registers; MODE, the machine mode of the argument;
+   TYPE, the data type of the argument as a tree node or 0 if that is not known
+   (which happens for C support library functions); and NAMED, which is 1 for an
+   ordinary argument and 0 for nameless arguments that correspond to `...' in the
+   called function's prototype.
+
+   The value of the expression should either be a `reg' RTX for the hard
+   register in which to pass the argument, or zero to pass the argument on the
+   stack.
+
+   For machines like the Vax and 68000, where normally all arguments are
+   pushed, zero suffices as a definition.
+
+   The usual way to make the ANSI library `stdarg.h' work on a machine where
+   some arguments are usually passed in registers, is to cause nameless
+   arguments to be passed on the stack instead.  This is done by making
+   `FUNCTION_ARG' return 0 whenever NAMED is 0.
+
+   You may use the macro `MUST_PASS_IN_STACK (MODE, TYPE)' in the definition of
+   this macro to determine if this argument is of a type that must be passed in
+   the stack.  If `REG_PARM_STACK_SPACE' is not defined and `FUNCTION_ARG'
+   returns non-zero for such an argument, the compiler will abort.  If
+   `REG_PARM_STACK_SPACE' is defined, the argument will be computed in the
+   stack and then loaded into a register.  */
+
+rtx
+frv_function_arg (cum, mode, type, named, incoming)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type ATTRIBUTE_UNUSED;
+     int named;
+     int incoming ATTRIBUTE_UNUSED;
+{
+  enum machine_mode xmode = (mode == BLKmode) ? SImode : mode;
+  int arg_num = *cum;
+  rtx ret;
+  const char *debstr;
+
+  /* Return a marker for use in the call instruction.  */
+  if (xmode == VOIDmode)
+    {
+      ret = const0_rtx;
+      debstr = "<0>";
+    }
+
+  else if (arg_num <= LAST_ARG_REGNUM)
+    {
+      ret = gen_rtx (REG, xmode, arg_num);
+      debstr = reg_names[arg_num];
+    }
+
+  else
+    {
+      ret = NULL_RTX;
+      debstr = "memory";
+    }
+
+  if (TARGET_DEBUG_ARG)
+    fprintf (stderr,
+            "function_arg: words = %2d, mode = %4s, named = %d, size = %3d, arg = %s\n",
+            arg_num, GET_MODE_NAME (mode), named, GET_MODE_SIZE (mode), debstr);
+
+  return ret;
+}
+
+\f
+/* A C statement (sans semicolon) to update the summarizer variable CUM to
+   advance past an argument in the argument list.  The values MODE, TYPE and
+   NAMED describe that argument.  Once this is done, the variable CUM is
+   suitable for analyzing the *following* argument with `FUNCTION_ARG', etc.
+
+   This macro need not do anything if the argument in question was passed on
+   the stack.  The compiler knows how to track the amount of stack space used
+   for arguments without any special help.  */
+
+void
+frv_function_arg_advance (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type ATTRIBUTE_UNUSED;
+     int named;
+{
+  enum machine_mode xmode = (mode == BLKmode) ? SImode : mode;
+  int bytes = GET_MODE_SIZE (xmode);
+  int words = (bytes + UNITS_PER_WORD  - 1) / UNITS_PER_WORD;
+  int arg_num = *cum;
+
+  *cum = arg_num + words;
+
+  if (TARGET_DEBUG_ARG)
+    fprintf (stderr,
+            "function_adv: words = %2d, mode = %4s, named = %d, size = %3d\n",
+            arg_num, GET_MODE_NAME (mode), named, words * UNITS_PER_WORD);
+}
+
+\f
+/* A C expression for the number of words, at the beginning of an argument,
+   must be put in registers.  The value must be zero for arguments that are
+   passed entirely in registers or that are entirely pushed on the stack.
+
+   On some machines, certain arguments must be passed partially in registers
+   and partially in memory.  On these machines, typically the first N words of
+   arguments are passed in registers, and the rest on the stack.  If a
+   multi-word argument (a `double' or a structure) crosses that boundary, its
+   first few words must be passed in registers and the rest must be pushed.
+   This macro tells the compiler when this occurs, and how many of the words
+   should go in registers.
+
+   `FUNCTION_ARG' for these arguments should return the first register to be
+   used by the caller for this argument; likewise `FUNCTION_INCOMING_ARG', for
+   the called function.  */
+
+int
+frv_function_arg_partial_nregs (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type ATTRIBUTE_UNUSED;
+     int named ATTRIBUTE_UNUSED;
+{
+  enum machine_mode xmode = (mode == BLKmode) ? SImode : mode;
+  int bytes = GET_MODE_SIZE (xmode);
+  int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+  int arg_num = *cum;
+  int ret;
+
+  ret = ((arg_num <= LAST_ARG_REGNUM && arg_num + words > LAST_ARG_REGNUM+1)
+        ? LAST_ARG_REGNUM - arg_num + 1
+        : 0);
+
+  if (TARGET_DEBUG_ARG && ret)
+    fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
+
+  return ret;
+
+}
+
+\f
+
+/* A C expression that indicates when an argument must be passed by reference.
+   If nonzero for an argument, a copy of that argument is made in memory and a
+   pointer to the argument is passed instead of the argument itself.  The
+   pointer is passed in whatever way is appropriate for passing a pointer to
+   that type.
+
+   On machines where `REG_PARM_STACK_SPACE' is not defined, a suitable
+   definition of this macro might be
+        #define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED)  \
+          MUST_PASS_IN_STACK (MODE, TYPE)  */
+
+int
+frv_function_arg_pass_by_reference (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
+     enum machine_mode mode;
+     tree type;
+     int named ATTRIBUTE_UNUSED;
+{
+  return MUST_PASS_IN_STACK (mode, type);
+}
+
+/* If defined, a C expression that indicates when it is the called function's
+   responsibility to make a copy of arguments passed by invisible reference.
+   Normally, the caller makes a copy and passes the address of the copy to the
+   routine being called.  When FUNCTION_ARG_CALLEE_COPIES is defined and is
+   nonzero, the caller does not make a copy.  Instead, it passes a pointer to
+   the "live" value.  The called function must not modify this value.  If it
+   can be determined that the value won't be modified, it need not make a copy;
+   otherwise a copy must be made.  */
+
+int
+frv_function_arg_callee_copies (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     tree type ATTRIBUTE_UNUSED;
+     int named ATTRIBUTE_UNUSED;
+{
+  return 0;
+}
+
+/* If defined, a C expression that indicates when it is more desirable to keep
+   an argument passed by invisible reference as a reference, rather than
+   copying it to a pseudo register.  */
+
+int
+frv_function_arg_keep_as_reference (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     tree type ATTRIBUTE_UNUSED;
+     int named ATTRIBUTE_UNUSED;
+{
+  return 0;
+}
+
+\f
+/* Return true if a register is ok to use as a base or index register.  */
+
+static FRV_INLINE int
+frv_regno_ok_for_base_p (regno, strict_p)
+     int regno;
+     int strict_p;
+{
+  if (GPR_P (regno))
+    return TRUE;
+
+  if (strict_p)
+    return (reg_renumber[regno] >= 0 && GPR_P (reg_renumber[regno]));
+
+  if (regno == ARG_POINTER_REGNUM)
+    return TRUE;
+
+  return (regno >= FIRST_PSEUDO_REGISTER);
+}
+
+\f
+/* A C compound statement with a conditional `goto LABEL;' executed if X (an
+   RTX) is a legitimate memory address on the target machine for a memory
+   operand of mode MODE.
+
+   It usually pays to define several simpler macros to serve as subroutines for
+   this one.  Otherwise it may be too complicated to understand.
+
+   This macro must exist in two variants: a strict variant and a non-strict
+   one.  The strict variant is used in the reload pass.  It must be defined so
+   that any pseudo-register that has not been allocated a hard register is
+   considered a memory reference.  In contexts where some kind of register is
+   required, a pseudo-register with no hard register must be rejected.
+
+   The non-strict variant is used in other passes.  It must be defined to
+   accept all pseudo-registers in every context where some kind of register is
+   required.
+
+   Compiler source files that want to use the strict variant of this macro
+   define the macro `REG_OK_STRICT'.  You should use an `#ifdef REG_OK_STRICT'
+   conditional to define the strict variant in that case and the non-strict
+   variant otherwise.
+
+   Subroutines to check for acceptable registers for various purposes (one for
+   base registers, one for index registers, and so on) are typically among the
+   subroutines used to define `GO_IF_LEGITIMATE_ADDRESS'.  Then only these
+   subroutine macros need have two variants; the higher levels of macros may be
+   the same whether strict or not.
+
+   Normally, constant addresses which are the sum of a `symbol_ref' and an
+   integer are stored inside a `const' RTX to mark them as constant.
+   Therefore, there is no need to recognize such sums specifically as
+   legitimate addresses.  Normally you would simply recognize any `const' as
+   legitimate.
+
+   Usually `PRINT_OPERAND_ADDRESS' is not prepared to handle constant sums that
+   are not marked with `const'.  It assumes that a naked `plus' indicates
+   indexing.  If so, then you *must* reject such naked constant sums as
+   illegitimate addresses, so that none of them will be given to
+   `PRINT_OPERAND_ADDRESS'.
+
+   On some machines, whether a symbolic address is legitimate depends on the
+   section that the address refers to.  On these machines, define the macro
+   `ENCODE_SECTION_INFO' to store the information into the `symbol_ref', and
+   then check for it here.  When you see a `const', you will have to look
+   inside it to find the `symbol_ref' in order to determine the section.
+
+   The best way to modify the name string is by adding text to the beginning,
+   with suitable punctuation to prevent any ambiguity.  Allocate the new name
+   in `saveable_obstack'.  You will have to modify `ASM_OUTPUT_LABELREF' to
+   remove and decode the added text and output the name accordingly, and define
+   `STRIP_NAME_ENCODING' to access the original name string.
+
+   You can check the information stored here into the `symbol_ref' in the
+   definitions of the macros `GO_IF_LEGITIMATE_ADDRESS' and
+   `PRINT_OPERAND_ADDRESS'.  */
+
+int
+frv_legitimate_address_p (mode, x, strict_p, condexec_p)
+     enum machine_mode mode;
+     rtx x;
+     int strict_p;
+     int condexec_p;
+{
+  rtx x0, x1;
+  int ret = 0;
+  HOST_WIDE_INT value;
+  unsigned regno0;
+
+  switch (GET_CODE (x))
+    {
+    default:
+      break;
+
+    case SUBREG:
+      x = SUBREG_REG (x);
+      if (GET_CODE (x) != REG)
+        break;
+
+      /* fall through */
+
+    case REG:
+      ret = frv_regno_ok_for_base_p (REGNO (x), strict_p);
+      break;
+
+    case PRE_MODIFY:
+      x0 = XEXP (x, 0);
+      x1 = XEXP (x, 1);
+      if (GET_CODE (x0) != REG
+         || ! frv_regno_ok_for_base_p (REGNO (x0), strict_p)
+         || GET_CODE (x1) != PLUS
+         || ! rtx_equal_p (x0, XEXP (x1, 0))
+         || GET_CODE (XEXP (x1, 1)) != REG
+         || ! frv_regno_ok_for_base_p (REGNO (XEXP (x1, 1)), strict_p))
+       break;
+
+      ret = 1;
+      break;
+
+    case CONST_INT:
+      /* 12 bit immediate */
+      if (condexec_p)
+       ret = FALSE;
+      else
+       {
+         ret = IN_RANGE_P (INTVAL (x), -2048, 2047);
+
+         /* If we can't use load/store double operations, make sure we can
+            address the second word.  */
+         if (ret && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+           ret = IN_RANGE_P (INTVAL (x) + GET_MODE_SIZE (mode) - 1,
+                             -2048, 2047);
+       }
+      break;
+
+    case PLUS:
+      x0 = XEXP (x, 0);
+      x1 = XEXP (x, 1);
+
+      if (GET_CODE (x0) == SUBREG)
+       x0 = SUBREG_REG (x0);
+
+      if (GET_CODE (x0) != REG)
+       break;
+
+      regno0 = REGNO (x0);
+      if (!frv_regno_ok_for_base_p (regno0, strict_p))
+       break;
+
+      switch (GET_CODE (x1))
+       {
+       default:
+         break;
+
+       case SUBREG:
+         x1 = SUBREG_REG (x1);
+         if (GET_CODE (x1) != REG)
+           break;
+
+         /* fall through */
+
+       case REG:
+         /* Do not allow reg+reg addressing for modes > 1 word if we can't depend
+            on having move double instructions */
+         if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+           ret = FALSE;
+         else
+           ret = frv_regno_ok_for_base_p (REGNO (x1), strict_p);
+         break;
+
+       case CONST_INT:
+          /* 12 bit immediate */
+         if (condexec_p)
+           ret = FALSE;
+         else
+           {
+             value = INTVAL (x1);
+             ret = IN_RANGE_P (value, -2048, 2047);
+
+             /* If we can't use load/store double operations, make sure we can
+                address the second word.  */
+             if (ret && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+               ret = IN_RANGE_P (value + GET_MODE_SIZE (mode) - 1, -2048, 2047);
+           }
+         break;
+
+       case SYMBOL_REF:
+         if (!condexec_p
+             && regno0 == SDA_BASE_REG
+             && symbol_ref_small_data_p (x1))
+           ret = TRUE;
+         break;
+
+       case CONST:
+         if (!condexec_p && regno0 == SDA_BASE_REG && const_small_data_p (x1))
+           ret = TRUE;
+         break;
+
+       }
+      break;
+    }
+
+  if (TARGET_DEBUG_ADDR)
+    {
+      fprintf (stderr, "\n========== GO_IF_LEGITIMATE_ADDRESS, mode = %s, result = %d, addresses are %sstrict%s\n",
+              GET_MODE_NAME (mode), ret, (strict_p) ? "" : "not ",
+              (condexec_p) ? ", inside conditional code" : "");
+      debug_rtx (x);
+    }
+
+  return ret;
+}
+
+\f
+/* A C compound statement that attempts to replace X with a valid memory
+   address for an operand of mode MODE.  WIN will be a C statement label
+   elsewhere in the code; the macro definition may use
+
+        GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN);
+
+   to avoid further processing if the address has become legitimate.
+
+   X will always be the result of a call to `break_out_memory_refs', and OLDX
+   will be the operand that was given to that function to produce X.
+
+   The code generated by this macro should not alter the substructure of X.  If
+   it transforms X into a more legitimate form, it should assign X (which will
+   always be a C variable) a new value.
+
+   It is not necessary for this macro to come up with a legitimate address.
+   The compiler has standard ways of doing so in all cases.  In fact, it is
+   safe for this macro to do nothing.  But often a machine-dependent strategy
+   can generate better code.  */
+
+rtx
+frv_legitimize_address (x, oldx, mode)
+     rtx x;
+     rtx oldx ATTRIBUTE_UNUSED;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  rtx ret = NULL_RTX;
+
+  /* Don't try to legitimize addreses if we are not optimizing, since the
+     address we generate is not a general operand, and will horribly mess
+     things up when force_reg is called to try and put it in a register because
+     we aren't optimizing.  */
+  if (optimize
+      && ((GET_CODE (x) == SYMBOL_REF && symbol_ref_small_data_p (x))
+         || (GET_CODE (x) == CONST && const_small_data_p (x))))
+    {
+      ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, SDA_BASE_REG), x);
+      if (flag_pic)
+       cfun->uses_pic_offset_table = TRUE;
+    }
+
+  if (TARGET_DEBUG_ADDR && ret != NULL_RTX)
+    {
+      fprintf (stderr, "\n========== LEGITIMIZE_ADDRESS, mode = %s, modified address\n",
+              GET_MODE_NAME (mode));
+      debug_rtx (ret);
+    }
+
+  return ret;
+}
+
+/* Return 1 if operand is a valid FRV address.  CONDEXEC_P is true if
+   the operand is used by a predicated instruction.  */
+
+static int
+frv_legitimate_memory_operand (op, mode, condexec_p)
+      rtx op;
+      enum machine_mode mode;
+      int condexec_p;
+{
+  return ((GET_MODE (op) == mode || mode == VOIDmode)
+         && GET_CODE (op) == MEM
+         && frv_legitimate_address_p (mode, XEXP (op, 0),
+                                      reload_completed, condexec_p));
+}
+
+\f
+/* Return 1 is OP is a memory operand, or will be turned into one by
+   reload.  */
+
+int frv_load_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (reload_in_progress)
+    {
+      rtx tmp = op;
+      if (GET_CODE (tmp) == SUBREG)
+       tmp = SUBREG_REG (tmp);
+      if (GET_CODE (tmp) == REG
+         && REGNO (tmp) >= FIRST_PSEUDO_REGISTER)
+       op = reg_equiv_memory_loc[REGNO (tmp)];
+    }
+
+  return op && memory_operand (op, mode);
+}
+
+
+/* Return 1 if operand is a GPR register or a FPR register.  */
+
+int gpr_or_fpr_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+       return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER)
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Return 1 if operand is a GPR register or 12 bit signed immediate.  */
+
+int gpr_or_int12_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  if (GET_CODE (op) == CONST_INT)
+    return IN_RANGE_P (INTVAL (op), -2048, 2047);
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+       return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  return GPR_OR_PSEUDO_P (REGNO (op));
+}
+
+/* Return 1 if operand is a GPR register, or a FPR register, or a 12 bit
+   signed immediate.  */
+
+int gpr_fpr_or_int12_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_CODE (op) == CONST_INT)
+    return IN_RANGE_P (INTVAL (op), -2048, 2047);
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+       return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER)
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Return 1 if operand is a register or 6 bit signed immediate.  */
+
+int fpr_or_int6_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  if (GET_CODE (op) == CONST_INT)
+    return IN_RANGE_P (INTVAL (op), -32, 31);
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+       return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  return FPR_OR_PSEUDO_P (REGNO (op));
+}
+
+/* Return 1 if operand is a register or 10 bit signed immediate.  */
+
+int gpr_or_int10_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  if (GET_CODE (op) == CONST_INT)
+    return IN_RANGE_P (INTVAL (op), -512, 511);
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+       return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  return GPR_OR_PSEUDO_P (REGNO (op));
+}
+
+/* Return 1 if operand is a register or an integer immediate.  */
+
+int gpr_or_int_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  if (GET_CODE (op) == CONST_INT)
+    return TRUE;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+       return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  return GPR_OR_PSEUDO_P (REGNO (op));
+}
+
+/* Return 1 if operand is a 12 bit signed immediate.  */
+
+int int12_operand (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (op) != CONST_INT)
+    return FALSE;
+
+  return IN_RANGE_P (INTVAL (op), -2048, 2047);
+}
+
+/* Return 1 if operand is a 6 bit signed immediate.  */
+
+int int6_operand (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (op) != CONST_INT)
+    return FALSE;
+
+  return IN_RANGE_P (INTVAL (op), -32, 31);
+}
+
+/* Return 1 if operand is a 5 bit signed immediate.  */
+
+int int5_operand (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), -16, 15);
+}
+
+/* Return 1 if operand is a 5 bit unsigned immediate.  */
+
+int uint5_operand (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 31);
+}
+
+/* Return 1 if operand is a 4 bit unsigned immediate.  */
+
+int uint4_operand (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 15);
+}
+
+/* Return 1 if operand is a 1 bit unsigned immediate (0 or 1).  */
+
+int uint1_operand (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 1);
+}
+
+/* Return 1 if operand is an integer constant that takes 2 instructions
+   to load up and can be split into sethi/setlo instructions..  */
+
+int int_2word_operand (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  HOST_WIDE_INT value;
+  REAL_VALUE_TYPE rv;
+  long l;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      break;
+
+    case LABEL_REF:
+      return (flag_pic == 0);
+
+    case CONST:
+      /* small data references are already 1 word */
+      return (flag_pic == 0) && (! const_small_data_p (op));
+
+    case SYMBOL_REF:
+      /* small data references are already 1 word */
+      return (flag_pic == 0) && (! symbol_ref_small_data_p (op));
+
+    case CONST_INT:
+      return ! IN_RANGE_P (INTVAL (op), -32768, 32767);
+
+    case CONST_DOUBLE:
+      if (GET_MODE (op) == SFmode)
+       {
+         REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+         REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+         value = l;
+         return ! IN_RANGE_P (value, -32768, 32767);
+       }
+      else if (GET_MODE (op) == VOIDmode)
+       {
+         value = CONST_DOUBLE_LOW (op);
+         return ! IN_RANGE_P (value, -32768, 32767);
+       }
+      break;
+    }
+
+  return FALSE;
+}
+
+/* Return 1 if operand is the pic address register.  */
+int
+pic_register_operand (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (! flag_pic)
+    return FALSE;
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  if (REGNO (op) != PIC_REGNO)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return 1 if operand is a symbolic reference when a PIC option is specified
+   that takes 3 seperate instructions to form.  */
+
+int pic_symbolic_operand (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (! flag_pic)
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      break;
+
+    case LABEL_REF:
+      return TRUE;
+
+    case SYMBOL_REF:
+      /* small data references are already 1 word */
+      return ! symbol_ref_small_data_p (op);
+
+    case CONST:
+      /* small data references are already 1 word */
+      return ! const_small_data_p (op);
+    }
+
+  return FALSE;
+}
+
+/* Return 1 if operand is the small data register.  */
+int
+small_data_register_operand (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  if (REGNO (op) != SDA_BASE_REG)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return 1 if operand is a symbolic reference to a small data area static or
+   global object.  */
+
+int small_data_symbolic_operand (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  switch (GET_CODE (op))
+    {
+    default:
+      break;
+
+    case CONST:
+      return const_small_data_p (op);
+
+    case SYMBOL_REF:
+      return symbol_ref_small_data_p (op);
+    }
+
+  return FALSE;
+}
+
+/* Return 1 if operand is a 16 bit unsigned immediate */
+
+int uint16_operand (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (op) != CONST_INT)
+    return FALSE;
+
+  return IN_RANGE_P (INTVAL (op), 0, 0xffff);
+}
+
+/* Return 1 if operand is an integer constant with the bottom 16 bits clear */
+
+int upper_int16_operand (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (op) != CONST_INT)
+    return FALSE;
+
+  return ((INTVAL (op) & 0xffff) == 0);
+}
+
+/* Return true if operand is a GPR register. */
+
+int
+integer_register_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+       return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  return GPR_OR_PSEUDO_P (REGNO (op));
+}
+
+/* Return true if operand is a GPR register.  Do not allow SUBREG's
+   here, in order to prevent a combine bug.  */
+
+int
+gpr_no_subreg_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  return GPR_OR_PSEUDO_P (REGNO (op));
+}
+
+/* Return true if operand is a FPR register. */
+
+int
+fpr_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+        return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  return FPR_OR_PSEUDO_P (REGNO (op));
+}
+
+/* Return true if operand is an even GPR or FPR register. */
+
+int
+even_reg_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+        return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    return TRUE;
+
+  if (GPR_P (regno))
+    return (((regno - GPR_FIRST) & 1) == 0);
+
+  if (FPR_P (regno))
+    return (((regno - FPR_FIRST) & 1) == 0);
+
+  return FALSE;
+}
+
+/* Return true if operand is an odd GPR register. */
+
+int
+odd_reg_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+        return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  /* assume that reload will give us an even register */
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    return FALSE;
+
+  if (GPR_P (regno))
+    return (((regno - GPR_FIRST) & 1) != 0);
+
+  if (FPR_P (regno))
+    return (((regno - FPR_FIRST) & 1) != 0);
+
+  return FALSE;
+}
+
+/* Return true if operand is an even GPR register. */
+
+int
+even_gpr_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+        return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    return TRUE;
+
+  if (! GPR_P (regno))
+    return FALSE;
+
+  return (((regno - GPR_FIRST) & 1) == 0);
+}
+
+/* Return true if operand is an odd GPR register. */
+
+int
+odd_gpr_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+        return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  /* assume that reload will give us an even register */
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    return FALSE;
+
+  if (! GPR_P (regno))
+    return FALSE;
+
+  return (((regno - GPR_FIRST) & 1) != 0);
+}
+
+/* Return true if operand is a quad aligned FPR register. */
+
+int
+quad_fpr_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+        return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    return TRUE;
+
+  if (! FPR_P (regno))
+    return FALSE;
+
+  return (((regno - FPR_FIRST) & 3) == 0);
+}
+
+/* Return true if operand is an even FPR register. */
+
+int
+even_fpr_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+        return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    return TRUE;
+
+  if (! FPR_P (regno))
+    return FALSE;
+
+  return (((regno - FPR_FIRST) & 1) == 0);
+}
+
+/* Return true if operand is an odd FPR register. */
+
+int
+odd_fpr_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+        return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  /* assume that reload will give us an even register */
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    return FALSE;
+
+  if (! FPR_P (regno))
+    return FALSE;
+
+  return (((regno - FPR_FIRST) & 1) != 0);
+}
+
+/* Return true if operand is a 2 word memory address that can be loaded in one
+   instruction to load or store.  We assume the stack and frame pointers are
+   suitably aligned, and variables in the small data area.  FIXME -- at some we
+   should recognize other globals and statics. We can't assume that any old
+   pointer is aligned, given that arguments could be passed on an odd word on
+   the stack and the address taken and passed through to another function.  */
+
+int
+dbl_memory_one_insn_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  rtx addr;
+  rtx addr_reg;
+
+  if (! TARGET_DWORD)
+    return FALSE;
+
+  if (GET_CODE (op) != MEM)
+    return FALSE;
+
+  if (mode != VOIDmode && GET_MODE_SIZE (mode) != 2*UNITS_PER_WORD)
+    return FALSE;
+
+  addr = XEXP (op, 0);
+  if (GET_CODE (addr) == REG)
+    addr_reg = addr;
+
+  else if (GET_CODE (addr) == PLUS)
+    {
+      rtx addr0 = XEXP (addr, 0);
+      rtx addr1 = XEXP (addr, 1);
+
+      if (GET_CODE (addr0) != REG)
+       return FALSE;
+
+      if (plus_small_data_p (addr0, addr1))
+       return TRUE;
+
+      if (GET_CODE (addr1) != CONST_INT)
+       return FALSE;
+
+      if ((INTVAL (addr1) & 7) != 0)
+       return FALSE;
+
+      addr_reg = addr0;
+    }
+
+  else
+    return FALSE;
+
+  if (addr_reg == frame_pointer_rtx || addr_reg == stack_pointer_rtx)
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Return true if operand is a 2 word memory address that needs to
+   use two instructions to load or store.  */
+
+int
+dbl_memory_two_insn_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_CODE (op) != MEM)
+    return FALSE;
+
+  if (mode != VOIDmode && GET_MODE_SIZE (mode) != 2*UNITS_PER_WORD)
+    return FALSE;
+
+  if (! TARGET_DWORD)
+    return TRUE;
+
+  return ! dbl_memory_one_insn_operand (op, mode);
+}
+
+/* Return true if operand is something that can be an output for a move
+   operation.  */
+
+int
+move_destination_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  rtx subreg;
+  enum rtx_code code;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      break;
+
+    case SUBREG:
+      if (GET_MODE (op) != mode && mode != VOIDmode)
+        return FALSE;
+
+      subreg = SUBREG_REG (op);
+      code = GET_CODE (subreg);
+      if (code == MEM)
+       return frv_legitimate_address_p (mode, XEXP (subreg, 0),
+                                        reload_completed, FALSE);
+
+      return (code == REG);
+
+    case REG:
+      if (GET_MODE (op) != mode && mode != VOIDmode)
+        return FALSE;
+
+      return TRUE;
+
+    case MEM:
+      if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
+        return TRUE;
+
+      return frv_legitimate_memory_operand (op, mode, FALSE);
+    }
+
+  return FALSE;
+}
+
+/* Return true if operand is something that can be an input for a move
+   operation.  */
+
+int
+move_source_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  rtx subreg;
+  enum rtx_code code;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      break;
+
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
+    case LABEL_REF:
+    case CONST:
+      return immediate_operand (op, mode);
+
+    case SUBREG:
+      if (GET_MODE (op) != mode && mode != VOIDmode)
+        return FALSE;
+
+      subreg = SUBREG_REG (op);
+      code = GET_CODE (subreg);
+      if (code == MEM)
+       return frv_legitimate_address_p (mode, XEXP (subreg, 0),
+                                        reload_completed, FALSE);
+
+      return (code == REG);
+
+    case REG:
+      if (GET_MODE (op) != mode && mode != VOIDmode)
+        return FALSE;
+
+      return TRUE;
+
+    case MEM:
+      if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
+        return TRUE;
+
+      return frv_legitimate_memory_operand (op, mode, FALSE);
+    }
+
+  return FALSE;
+}
+
+/* Return true if operand is something that can be an output for a conditional
+   move operation.  */
+
+int
+condexec_dest_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  rtx subreg;
+  enum rtx_code code;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      break;
+
+    case SUBREG:
+      if (GET_MODE (op) != mode && mode != VOIDmode)
+        return FALSE;
+
+      subreg = SUBREG_REG (op);
+      code = GET_CODE (subreg);
+      if (code == MEM)
+       return frv_legitimate_address_p (mode, XEXP (subreg, 0),
+                                        reload_completed, TRUE);
+
+      return (code == REG);
+
+    case REG:
+      if (GET_MODE (op) != mode && mode != VOIDmode)
+        return FALSE;
+
+      return TRUE;
+
+    case MEM:
+      if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
+        return TRUE;
+
+      return frv_legitimate_memory_operand (op, mode, TRUE);
+    }
+
+  return FALSE;
+}
+
+/* Return true if operand is something that can be an input for a conditional
+   move operation.  */
+
+int
+condexec_source_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  rtx subreg;
+  enum rtx_code code;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      break;
+
+    case CONST_INT:
+    case CONST_DOUBLE:
+      return ZERO_P (op);
+
+    case SUBREG:
+      if (GET_MODE (op) != mode && mode != VOIDmode)
+        return FALSE;
+
+      subreg = SUBREG_REG (op);
+      code = GET_CODE (subreg);
+      if (code == MEM)
+       return frv_legitimate_address_p (mode, XEXP (subreg, 0),
+                                        reload_completed, TRUE);
+
+      return (code == REG);
+
+    case REG:
+      if (GET_MODE (op) != mode && mode != VOIDmode)
+        return FALSE;
+
+      return TRUE;
+
+    case MEM:
+      if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
+        return TRUE;
+
+      return frv_legitimate_memory_operand (op, mode, TRUE);
+    }
+
+  return FALSE;
+}
+
+/* Return true if operand is a register of any flavor or a 0 of the
+   appropriate type.  */
+
+int
+reg_or_0_operand (op, mode)
+     rtx op;
+      enum machine_mode mode;
+{
+  switch (GET_CODE (op))
+    {
+    default:
+      break;
+
+    case REG:
+    case SUBREG:
+      if (GET_MODE (op) != mode && mode != VOIDmode)
+       return FALSE;
+
+      return register_operand (op, mode);
+
+    case CONST_INT:
+    case CONST_DOUBLE:
+      return ZERO_P (op);
+    }
+
+  return FALSE;
+}
+
+/* Return true if operand is the link register */
+
+int
+lr_operand (op, mode)
+     rtx op;
+      enum machine_mode mode;
+{
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (REGNO (op) != LR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return true if operand is a gpr register or a valid memory operation.  */
+
+int
+gpr_or_memory_operand (op, mode)
+     rtx op;
+      enum machine_mode mode;
+{
+  return (integer_register_operand (op, mode)
+         || frv_legitimate_memory_operand (op, mode, FALSE));
+}
+
+/* Return true if operand is a fpr register or a valid memory operation.  */
+
+int
+fpr_or_memory_operand (op, mode)
+     rtx op;
+      enum machine_mode mode;
+{
+  return (fpr_operand (op, mode)
+         || frv_legitimate_memory_operand (op, mode, FALSE));
+}
+
+/* Return true if operand is an icc register */
+
+int
+icc_operand (op, mode)
+     rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  return ICC_OR_PSEUDO_P (regno);
+}
+
+/* Return true if operand is an fcc register */
+
+int
+fcc_operand (op, mode)
+     rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  return FCC_OR_PSEUDO_P (regno);
+}
+
+/* Return true if operand is either an fcc or icc register */
+
+int
+cc_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  if (CC_OR_PSEUDO_P (regno))
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Return true if operand is an integer CCR register */
+
+int
+icr_operand (op, mode)
+     rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  return ICR_OR_PSEUDO_P (regno);
+}
+
+/* Return true if operand is an fcc register */
+
+int
+fcr_operand (op, mode)
+     rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  return FCR_OR_PSEUDO_P (regno);
+}
+
+/* Return true if operand is either an fcc or icc register */
+
+int
+cr_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  if (CR_OR_PSEUDO_P (regno))
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Return true if operand is a memory reference suitable for a call.  */
+
+int
+call_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT)
+    return FALSE;
+
+  if (GET_CODE (op) == SYMBOL_REF)
+    return TRUE;
+
+  /* Note this doesn't allow reg+reg or reg+imm12 addressing (which should
+     never occur anyway), but prevents reload from not handling the case
+     properly of a call through a pointer on a function that calls
+     vfork/setjmp, etc. due to the need to flush all of the registers to stack.  */
+  return gpr_or_int12_operand (op, mode);
+}
+
+/* Return true if operator is an kind of relational operator */
+
+int
+relational_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  rtx op0;
+  rtx op1;
+  int regno;
+
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case EQ:
+    case NE:
+    case LE:
+    case LT:
+    case GE:
+    case GT:
+    case LEU:
+    case LTU:
+    case GEU:
+    case GTU:
+      break;
+    }
+
+  op1 = XEXP (op, 1);
+  if (op1 != const0_rtx)
+    return FALSE;
+
+  op0 = XEXP (op, 0);
+  if (GET_CODE (op0) != REG)
+    return FALSE;
+
+  regno = REGNO (op0);
+  switch (GET_MODE (op0))
+    {
+    default:
+      break;
+
+    case CCmode:
+    case CC_UNSmode:
+      return ICC_OR_PSEUDO_P (regno);
+
+    case CC_FPmode:
+      return FCC_OR_PSEUDO_P (regno);
+
+    case CC_CCRmode:
+      return CR_OR_PSEUDO_P (regno);
+    }
+
+  return FALSE;
+}
+
+/* Return true if operator is a signed integer relational operator */
+
+int
+signed_relational_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  rtx op0;
+  rtx op1;
+  int regno;
+
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case EQ:
+    case NE:
+    case LE:
+    case LT:
+    case GE:
+    case GT:
+      break;
+    }
+
+  op1 = XEXP (op, 1);
+  if (op1 != const0_rtx)
+    return FALSE;
+
+  op0 = XEXP (op, 0);
+  if (GET_CODE (op0) != REG)
+    return FALSE;
+
+  regno = REGNO (op0);
+  if (GET_MODE (op0) == CCmode && ICC_OR_PSEUDO_P (regno))
+    return TRUE;
+
+  if (GET_MODE (op0) == CC_CCRmode && CR_OR_PSEUDO_P (regno))
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Return true if operator is a signed integer relational operator */
+
+int
+unsigned_relational_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  rtx op0;
+  rtx op1;
+  int regno;
+
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case LEU:
+    case LTU:
+    case GEU:
+    case GTU:
+      break;
+    }
+
+  op1 = XEXP (op, 1);
+  if (op1 != const0_rtx)
+    return FALSE;
+
+  op0 = XEXP (op, 0);
+  if (GET_CODE (op0) != REG)
+    return FALSE;
+
+  regno = REGNO (op0);
+  if (GET_MODE (op0) == CC_UNSmode && ICC_OR_PSEUDO_P (regno))
+    return TRUE;
+
+  if (GET_MODE (op0) == CC_CCRmode && CR_OR_PSEUDO_P (regno))
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Return true if operator is a floating point relational operator */
+
+int
+float_relational_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  rtx op0;
+  rtx op1;
+  int regno;
+
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case EQ: case NE:
+    case LE: case LT:
+    case GE: case GT:
+#if 0
+    case UEQ: case UNE:
+    case ULE: case ULT:
+    case UGE: case UGT:
+    case ORDERED:
+    case UNORDERED:
+#endif
+      break;
+    }
+
+  op1 = XEXP (op, 1);
+  if (op1 != const0_rtx)
+    return FALSE;
+
+  op0 = XEXP (op, 0);
+  if (GET_CODE (op0) != REG)
+    return FALSE;
+
+  regno = REGNO (op0);
+  if (GET_MODE (op0) == CC_FPmode && FCC_OR_PSEUDO_P (regno))
+    return TRUE;
+
+  if (GET_MODE (op0) == CC_CCRmode && CR_OR_PSEUDO_P (regno))
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Return true if operator is EQ/NE of a conditional execution register.  */
+
+int
+ccr_eqne_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  enum machine_mode op_mode = GET_MODE (op);
+  rtx op0;
+  rtx op1;
+  int regno;
+
+  if (mode != VOIDmode && op_mode != mode)
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case EQ:
+    case NE:
+      break;
+    }
+
+  op1 = XEXP (op, 1);
+  if (op1 != const0_rtx)
+    return FALSE;
+
+  op0 = XEXP (op, 0);
+  if (GET_CODE (op0) != REG)
+    return FALSE;
+
+  regno = REGNO (op0);
+  if (op_mode == CC_CCRmode && CR_OR_PSEUDO_P (regno))
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Return true if operator is a minimum or maximum operator (both signed and
+   unsigned).  */
+
+int
+minmax_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case SMIN:
+    case SMAX:
+    case UMIN:
+    case UMAX:
+      break;
+    }
+
+  if (! integer_register_operand (XEXP (op, 0), mode))
+    return FALSE;
+
+  if (! gpr_or_int10_operand (XEXP (op, 1), mode))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return true if operator is an integer binary operator that can executed
+   conditionally and takes 1 cycle.  */
+
+int
+condexec_si_binary_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  enum machine_mode op_mode = GET_MODE (op);
+
+  if (mode != VOIDmode && op_mode != mode)
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case PLUS:
+    case MINUS:
+    case AND:
+    case IOR:
+    case XOR:
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
+      return TRUE;
+    }
+}
+
+/* Return true if operator is an integer binary operator that can be
+   executed conditionally by a media instruction.  */
+
+int
+condexec_si_media_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  enum machine_mode op_mode = GET_MODE (op);
+
+  if (mode != VOIDmode && op_mode != mode)
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case AND:
+    case IOR:
+    case XOR:
+      return TRUE;
+    }
+}
+
+/* Return true if operator is an integer division operator that can executed
+   conditionally.  */
+
+int
+condexec_si_divide_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  enum machine_mode op_mode = GET_MODE (op);
+
+  if (mode != VOIDmode && op_mode != mode)
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case DIV:
+    case UDIV:
+      return TRUE;
+    }
+}
+
+/* Return true if operator is an integer unary operator that can executed
+   conditionally.  */
+
+int
+condexec_si_unary_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  enum machine_mode op_mode = GET_MODE (op);
+
+  if (mode != VOIDmode && op_mode != mode)
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case NEG:
+    case NOT:
+      return TRUE;
+    }
+}
+
+/* Return true if operator is a conversion-type expression that can be
+   evaluated conditionally by floating-point instructions.  */
+
+int
+condexec_sf_conv_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  enum machine_mode op_mode = GET_MODE (op);
+
+  if (mode != VOIDmode && op_mode != mode)
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case NEG:
+    case ABS:
+      return TRUE;
+    }
+}
+
+/* Return true if operator is an addition or subtraction expression.
+   Such expressions can be evaluated conditionally by floating-point
+   instructions.  */
+
+int
+condexec_sf_add_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  enum machine_mode op_mode = GET_MODE (op);
+
+  if (mode != VOIDmode && op_mode != mode)
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case PLUS:
+    case MINUS:
+      return TRUE;
+    }
+}
+
+/* Return true if the memory operand is one that can be conditionally
+   executed.  */
+
+int
+condexec_memory_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  enum machine_mode op_mode = GET_MODE (op);
+  rtx addr;
+
+  if (mode != VOIDmode && op_mode != mode)
+    return FALSE;
+
+  switch (op_mode)
+    {
+    default:
+      return FALSE;
+
+    case QImode:
+    case HImode:
+    case SImode:
+    case SFmode:
+      break;
+    }
+
+  if (GET_CODE (op) != MEM)
+    return FALSE;
+
+  addr = XEXP (op, 0);
+  if (GET_CODE (addr) == ADDRESSOF)
+    return TRUE;
+
+  return frv_legitimate_address_p (mode, addr, reload_completed, TRUE);
+}
+
+/* Return true if operator is an integer binary operator that can be combined
+   with a setcc operation.  Do not allow the arithmetic operations that could
+   potentially overflow since the FR-V sets the condition code based on the
+   "true" value of the result, not the result after truncating to a 32-bit
+   register.  */
+
+int
+intop_compare_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  enum machine_mode op_mode = GET_MODE (op);
+
+  if (mode != VOIDmode && op_mode != mode)
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case AND:
+    case IOR:
+    case XOR:
+    case ASHIFTRT:
+    case LSHIFTRT:
+      break;
+    }
+
+  if (! integer_register_operand (XEXP (op, 0), SImode))
+    return FALSE;
+
+  if (! gpr_or_int10_operand (XEXP (op, 1), SImode))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return true if operator is an integer binary operator that can be combined
+   with a setcc operation inside of a conditional execution.  */
+
+int
+condexec_intop_cmp_operator (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  enum machine_mode op_mode = GET_MODE (op);
+
+  if (mode != VOIDmode && op_mode != mode)
+    return FALSE;
+
+  switch (GET_CODE (op))
+    {
+    default:
+      return FALSE;
+
+    case AND:
+    case IOR:
+    case XOR:
+    case ASHIFTRT:
+    case LSHIFTRT:
+      break;
+    }
+
+  if (! integer_register_operand (XEXP (op, 0), SImode))
+    return FALSE;
+
+  if (! integer_register_operand (XEXP (op, 1), SImode))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return 1 if operand is a valid ACC register number */
+
+int
+acc_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+       return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  return ACC_OR_PSEUDO_P (regno);
+}
+
+/* Return 1 if operand is a valid even ACC register number */
+
+int
+even_acc_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+       return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  return (ACC_OR_PSEUDO_P (regno) && ((regno - ACC_FIRST) & 1) == 0);
+}
+
+/* Return 1 if operand is zero or four */
+
+int
+quad_acc_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+       return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  regno = REGNO (op);
+  return (ACC_OR_PSEUDO_P (regno) && ((regno - ACC_FIRST) & 3) == 0);
+}
+
+/* Return 1 if operand is a valid ACCG register number */
+
+int
+accg_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (op)) != REG)
+       return register_operand (op, mode);
+
+      op = SUBREG_REG (op);
+    }
+
+  if (GET_CODE (op) != REG)
+    return FALSE;
+
+  return ACCG_OR_PSEUDO_P (REGNO (op));
+}
+
+\f
+/* Return true if the bare return instruction can be used outside of the
+   epilog code.  For frv, we only do it if there was no stack allocation.  */
+
+int
+direct_return_p ()
+{
+  frv_stack_t *info;
+
+  if (!reload_completed)
+    return FALSE;
+
+  info = frv_stack_info ();
+  return (info->total_size == 0);
+}
+
+\f
+/* Emit code to handle a MOVSI, adding in the small data register or pic
+   register if needed to load up addresses.  Return TRUE if the appropriate
+   instructions are emitted.  */
+
+int
+frv_emit_movsi (dest, src)
+     rtx dest;
+     rtx src;
+{
+  int base_regno = -1;
+
+  if (!reload_in_progress
+      && !reload_completed
+      && !register_operand (dest, SImode)
+      && (!reg_or_0_operand (src, SImode)
+            /* Virtual registers will almost always be replaced by an
+               add instruction, so expose this to CSE by copying to
+               an intermediate register */
+         || (GET_CODE (src) == REG
+             && IN_RANGE_P (REGNO (src),
+                            FIRST_VIRTUAL_REGISTER,
+                            LAST_VIRTUAL_REGISTER))))
+    {
+      emit_insn (gen_rtx_SET (VOIDmode, dest, copy_to_mode_reg (SImode, src)));
+      return TRUE;
+    }
+
+  /* Explicitly add in the PIC or small data register if needed.  */
+  switch (GET_CODE (src))
+    {
+    default:
+      break;
+
+    case LABEL_REF:
+      if (flag_pic)
+       base_regno = PIC_REGNO;
+
+      break;
+
+    case CONST:
+      if (const_small_data_p (src))
+       base_regno = SDA_BASE_REG;
+
+      else if (flag_pic)
+       base_regno = PIC_REGNO;
+
+      break;
+
+    case SYMBOL_REF:
+      if (symbol_ref_small_data_p (src))
+       base_regno = SDA_BASE_REG;
+
+      else if (flag_pic)
+       base_regno = PIC_REGNO;
+
+      break;
+    }
+
+  if (base_regno >= 0)
+    {
+      emit_insn (gen_rtx_SET (VOIDmode, dest,
+                             gen_rtx_PLUS (Pmode,
+                                           gen_rtx_REG (Pmode, base_regno),
+                                           src)));
+
+      if (base_regno == PIC_REGNO)
+       cfun->uses_pic_offset_table = TRUE;
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+\f
+/* Return a string to output a single word move.  */
+
+const char *
+output_move_single (operands, insn)
+     rtx operands[];
+     rtx insn;
+{
+  rtx dest = operands[0];
+  rtx src  = operands[1];
+
+  if (GET_CODE (dest) == REG)
+    {
+      int dest_regno = REGNO (dest);
+      enum machine_mode mode = GET_MODE (dest);
+
+      if (GPR_P (dest_regno))
+       {
+         if (GET_CODE (src) == REG)
+           {
+             /* gpr <- some sort of register */
+             int src_regno = REGNO (src);
+
+             if (GPR_P (src_regno))
+               return "mov %1, %0";
+
+             else if (FPR_P (src_regno))
+               return "movfg %1, %0";
+
+             else if (SPR_P (src_regno))
+               return "movsg %1, %0";
+           }
+
+         else if (GET_CODE (src) == MEM)
+           {
+             /* gpr <- memory */
+             switch (mode)
+               {
+               default:
+                 break;
+
+               case QImode:
+                 return "ldsb%I1%U1 %M1,%0";
+
+               case HImode:
+                 return "ldsh%I1%U1 %M1,%0";
+
+               case SImode:
+               case SFmode:
+                 return "ld%I1%U1 %M1, %0";
+               }
+           }
+
+         else if (GET_CODE (src) == CONST_INT
+                  || GET_CODE (src) == CONST_DOUBLE)
+           {
+             /* gpr <- integer/floating constant */
+             HOST_WIDE_INT value;
+
+             if (GET_CODE (src) == CONST_INT)
+               value = INTVAL (src);
+
+             else if (mode == SFmode)
+               {
+                 REAL_VALUE_TYPE rv;
+                 long l;
+
+                 REAL_VALUE_FROM_CONST_DOUBLE (rv, src);
+                 REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+                 value = l;
+               }
+
+             else
+               value = CONST_DOUBLE_LOW (src);
+
+             if (IN_RANGE_P (value, -32768, 32767))
+               return "setlos %1, %0";
+
+             return "#";
+           }
+
+          else if (GET_CODE (src) == SYMBOL_REF
+                  || GET_CODE (src) == LABEL_REF
+                  || GET_CODE (src) == CONST)
+           {
+             /* Silently fix up instances where the small data pointer is not
+                 used in the address.  */
+             if (small_data_symbolic_operand (src, GET_MODE (src)))
+               return "addi %@, #gprel12(%1), %0";
+
+             return "#";
+           }
+       }
+
+      else if (FPR_P (dest_regno))
+       {
+         if (GET_CODE (src) == REG)
+           {
+             /* fpr <- some sort of register */
+             int src_regno = REGNO (src);
+
+             if (GPR_P (src_regno))
+               return "movgf %1, %0";
+
+             else if (FPR_P (src_regno))
+               {
+                 if (TARGET_HARD_FLOAT)
+                   return "fmovs %1, %0";
+                 else
+                   return "mor %1, %1, %0";
+               }
+           }
+
+         else if (GET_CODE (src) == MEM)
+           {
+             /* fpr <- memory */
+             switch (mode)
+               {
+               default:
+                 break;
+
+               case QImode:
+                 return "ldbf%I1%U1 %M1,%0";
+
+               case HImode:
+                 return "ldhf%I1%U1 %M1,%0";
+
+               case SImode:
+               case SFmode:
+                 return "ldf%I1%U1 %M1, %0";
+               }
+           }
+
+         else if (ZERO_P (src))
+           return "movgf %., %0";
+       }
+
+      else if (SPR_P (dest_regno))
+       {
+         if (GET_CODE (src) == REG)
+           {
+             /* spr <- some sort of register */
+             int src_regno = REGNO (src);
+
+             if (GPR_P (src_regno))
+               return "movgs %1, %0";
+           }
+       }
+    }
+
+  else if (GET_CODE (dest) == MEM)
+    {
+      if (GET_CODE (src) == REG)
+       {
+         int src_regno = REGNO (src);
+         enum machine_mode mode = GET_MODE (dest);
+
+         if (GPR_P (src_regno))
+           {
+             switch (mode)
+               {
+               default:
+                 break;
+
+               case QImode:
+                 return "stb%I0%U0 %1, %M0";
+
+               case HImode:
+                 return "sth%I0%U0 %1, %M0";
+
+               case SImode:
+               case SFmode:
+                 return "st%I0%U0 %1, %M0";
+               }
+           }
+
+         else if (FPR_P (src_regno))
+           {
+             switch (mode)
+               {
+               default:
+                 break;
+
+               case QImode:
+                 return "stbf%I0%U0 %1, %M0";
+
+               case HImode:
+                 return "sthf%I0%U0 %1, %M0";
+
+               case SImode:
+               case SFmode:
+                 return "stf%I0%U0 %1, %M0";
+               }
+           }
+       }
+
+      else if (ZERO_P (src))
+       {
+         switch (GET_MODE (dest))
+           {
+           default:
+             break;
+
+           case QImode:
+             return "stb%I0%U0 %., %M0";
+
+           case HImode:
+             return "sth%I0%U0 %., %M0";
+
+           case SImode:
+           case SFmode:
+             return "st%I0%U0 %., %M0";
+           }
+       }
+    }
+
+  fatal_insn ("Bad output_move_single operand", insn);
+  return "";
+}
+
+\f
+/* Return a string to output a double word move.  */
+
+const char *
+output_move_double (operands, insn)
+     rtx operands[];
+     rtx insn;
+{
+  rtx dest = operands[0];
+  rtx src  = operands[1];
+  enum machine_mode mode = GET_MODE (dest);
+
+  if (GET_CODE (dest) == REG)
+    {
+      int dest_regno = REGNO (dest);
+
+      if (GPR_P (dest_regno))
+       {
+         if (GET_CODE (src) == REG)
+           {
+             /* gpr <- some sort of register */
+             int src_regno = REGNO (src);
+
+             if (GPR_P (src_regno))
+               return "#";
+
+             else if (FPR_P (src_regno))
+               {
+                 if (((dest_regno - GPR_FIRST) & 1) == 0
+                     && ((src_regno - FPR_FIRST) & 1) == 0)
+                   return "movfgd %1, %0";
+
+                 return "#";
+               }
+           }
+
+         else if (GET_CODE (src) == MEM)
+           {
+             /* gpr <- memory */
+             if (dbl_memory_one_insn_operand (src, mode))
+               return "ldd%I1%U1 %M1, %0";
+
+             return "#";
+           }
+
+         else if (GET_CODE (src) == CONST_INT
+                  || GET_CODE (src) == CONST_DOUBLE)
+           return "#";
+       }
+
+      else if (FPR_P (dest_regno))
+       {
+         if (GET_CODE (src) == REG)
+           {
+             /* fpr <- some sort of register */
+             int src_regno = REGNO (src);
+
+             if (GPR_P (src_regno))
+               {
+                 if (((dest_regno - FPR_FIRST) & 1) == 0
+                     && ((src_regno - GPR_FIRST) & 1) == 0)
+                   return "movgfd %1, %0";
+
+                 return "#";
+               }
+
+             else if (FPR_P (src_regno))
+               {
+                 if (TARGET_DOUBLE
+                     && ((dest_regno - FPR_FIRST) & 1) == 0
+                     && ((src_regno - FPR_FIRST) & 1) == 0)
+                   return "fmovd %1, %0";
+
+                 return "#";
+               }
+           }
+
+         else if (GET_CODE (src) == MEM)
+           {
+             /* fpr <- memory */
+             if (dbl_memory_one_insn_operand (src, mode))
+               return "lddf%I1%U1 %M1, %0";
+
+             return "#";
+           }
+
+         else if (ZERO_P (src))
+           return "#";
+       }
+    }
+
+  else if (GET_CODE (dest) == MEM)
+    {
+      if (GET_CODE (src) == REG)
+       {
+         int src_regno = REGNO (src);
+
+         if (GPR_P (src_regno))
+           {
+             if (((src_regno - GPR_FIRST) & 1) == 0
+                 && dbl_memory_one_insn_operand (dest, mode))
+               return "std%I0%U0 %1, %M0";
+
+             return "#";
+           }
+
+         if (FPR_P (src_regno))
+           {
+             if (((src_regno - FPR_FIRST) & 1) == 0
+                 && dbl_memory_one_insn_operand (dest, mode))
+               return "stdf%I0%U0 %1, %M0";
+
+             return "#";
+           }
+       }
+
+      else if (ZERO_P (src))
+       {
+         if (dbl_memory_one_insn_operand (dest, mode))
+           return "std%I0%U0 %., %M0";
+
+         return "#";
+       }
+    }
+
+  fatal_insn ("Bad output_move_double operand", insn);
+  return "";
+}
+
+\f
+/* Return a string to output a single word conditional move.
+   Operand0 -- EQ/NE of ccr register and 0
+   Operand1 -- CCR register
+   Operand2 -- destination
+   Operand3 -- source  */
+
+const char *
+output_condmove_single (operands, insn)
+     rtx operands[];
+     rtx insn;
+{
+  rtx dest = operands[2];
+  rtx src  = operands[3];
+
+  if (GET_CODE (dest) == REG)
+    {
+      int dest_regno = REGNO (dest);
+      enum machine_mode mode = GET_MODE (dest);
+
+      if (GPR_P (dest_regno))
+       {
+         if (GET_CODE (src) == REG)
+           {
+             /* gpr <- some sort of register */
+             int src_regno = REGNO (src);
+
+             if (GPR_P (src_regno))
+               return "cmov %z3, %2, %1, %e0";
+
+             else if (FPR_P (src_regno))
+               return "cmovfg %3, %2, %1, %e0";
+           }
+
+         else if (GET_CODE (src) == MEM)
+           {
+             /* gpr <- memory */
+             switch (mode)
+               {
+               default:
+                 break;
+
+               case QImode:
+                 return "cldsb%I3%U3 %M3, %2, %1, %e0";
+
+               case HImode:
+                 return "cldsh%I3%U3 %M3, %2, %1, %e0";
+
+               case SImode:
+               case SFmode:
+                 return "cld%I3%U3 %M3, %2, %1, %e0";
+               }
+           }
+
+         else if (ZERO_P (src))
+           return "cmov %., %2, %1, %e0";
+       }
+
+      else if (FPR_P (dest_regno))
+       {
+         if (GET_CODE (src) == REG)
+           {
+             /* fpr <- some sort of register */
+             int src_regno = REGNO (src);
+
+             if (GPR_P (src_regno))
+               return "cmovgf %3, %2, %1, %e0";
+
+             else if (FPR_P (src_regno))
+               {
+                 if (TARGET_HARD_FLOAT)
+                   return "cfmovs %3,%2,%1,%e0";
+                 else
+                   return "cmor %3, %3, %2, %1, %e0";
+               }
+           }
+
+         else if (GET_CODE (src) == MEM)
+           {
+             /* fpr <- memory */
+             if (mode == SImode || mode == SFmode)
+               return "cldf%I3%U3 %M3, %2, %1, %e0";
+           }
+
+         else if (ZERO_P (src))
+           return "cmovgf %., %2, %1, %e0";
+       }
+    }
+
+  else if (GET_CODE (dest) == MEM)
+    {
+      if (GET_CODE (src) == REG)
+       {
+         int src_regno = REGNO (src);
+         enum machine_mode mode = GET_MODE (dest);
+
+         if (GPR_P (src_regno))
+           {
+             switch (mode)
+               {
+               default:
+                 break;
+
+               case QImode:
+                 return "cstb%I2%U2 %3, %M2, %1, %e0";
+
+               case HImode:
+                 return "csth%I2%U2 %3, %M2, %1, %e0";
+
+               case SImode:
+               case SFmode:
+                 return "cst%I2%U2 %3, %M2, %1, %e0";
+               }
+           }
+
+         else if (FPR_P (src_regno) && (mode == SImode || mode == SFmode))
+           return "cstf%I2%U2 %3, %M2, %1, %e0";
+       }
+
+      else if (ZERO_P (src))
+       {
+         enum machine_mode mode = GET_MODE (dest);
+         switch (mode)
+           {
+           default:
+             break;
+
+           case QImode:
+             return "cstb%I2%U2 %., %M2, %1, %e0";
+
+           case HImode:
+             return "csth%I2%U2 %., %M2, %1, %e0";
+
+           case SImode:
+           case SFmode:
+             return "cst%I2%U2 %., %M2, %1, %e0";
+           }
+       }
+    }
+
+  fatal_insn ("Bad output_condmove_single operand", insn);
+  return "";
+}
+
+\f
+/* Emit the appropriate code to do a comparison, returning the register the
+   comparison was done it.  */
+
+static rtx
+frv_emit_comparison (test, op0, op1)
+     enum rtx_code test;
+     rtx op0;
+     rtx op1;
+{
+  enum machine_mode cc_mode;
+  rtx cc_reg;
+
+  /* Floating point doesn't have comparison against a constant */
+  if (GET_MODE (op0) == CC_FPmode && GET_CODE (op1) != REG)
+    op1 = force_reg (GET_MODE (op0), op1);
+
+  /* Possibly disable using anything but a fixed register in order to work
+     around cse moving comparisons past function calls.  */
+  cc_mode = SELECT_CC_MODE (test, op0, op1);
+  cc_reg = ((TARGET_ALLOC_CC)
+           ? gen_reg_rtx (cc_mode)
+           : gen_rtx_REG (cc_mode,
+                          (cc_mode == CC_FPmode) ? FCC_FIRST : ICC_FIRST));
+
+  emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
+                         gen_rtx_COMPARE (cc_mode, op0, op1)));
+
+  return cc_reg;
+}
+
+\f
+/* Emit code for a conditional branch.  The comparison operands were previously
+   stored in frv_compare_op0 and frv_compare_op1.
+
+   XXX: I originally wanted to add a clobber of a CCR register to use in
+   conditional execution, but that confuses the rest of the compiler.  */
+
+int
+frv_emit_cond_branch (test, label)
+     enum rtx_code test;
+     rtx label;
+{
+  rtx test_rtx;
+  rtx label_ref;
+  rtx if_else;
+  rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1);
+  enum machine_mode cc_mode = GET_MODE (cc_reg);
+
+  /* Branches generate:
+       (set (pc)
+            (if_then_else (<test>, <cc_reg>, (const_int 0))
+                           (label_ref <branch_label>)
+                           (pc))) */
+  label_ref = gen_rtx_LABEL_REF (VOIDmode, label);
+  test_rtx = gen_rtx (test, cc_mode, cc_reg, const0_rtx);
+  if_else = gen_rtx_IF_THEN_ELSE (cc_mode, test_rtx, label_ref, pc_rtx);
+  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, if_else));
+  return TRUE;
+}
+
+\f
+/* Emit code to set a gpr to 1/0 based on a comparison.  The comparison
+   operands were previously stored in frv_compare_op0 and frv_compare_op1.  */
+
+int
+frv_emit_scc (test, target)
+     enum rtx_code test;
+     rtx target;
+{
+  rtx set;
+  rtx test_rtx;
+  rtx clobber;
+  rtx cr_reg;
+  rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1);
+
+  /* SCC instructions generate:
+       (parallel [(set <target> (<test>, <cc_reg>, (const_int 0))
+                  (clobber (<ccr_reg>))])  */
+  test_rtx = gen_rtx_fmt_ee (test, SImode, cc_reg, const0_rtx);
+  set = gen_rtx_SET (VOIDmode, target, test_rtx);
+
+  cr_reg = ((TARGET_ALLOC_CC)
+           ? gen_reg_rtx (CC_CCRmode)
+           : gen_rtx_REG (CC_CCRmode,
+                          ((GET_MODE (cc_reg) == CC_FPmode)
+                           ? FCR_FIRST
+                           : ICR_FIRST)));
+
+  clobber = gen_rtx_CLOBBER (VOIDmode, cr_reg);
+  emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));
+  return TRUE;
+}
+
+\f
+/* Split a SCC instruction into component parts, returning a SEQUENCE to hold
+   the seperate insns.  */
+
+rtx
+frv_split_scc (dest, test, cc_reg, cr_reg, value)
+     rtx dest;
+     rtx test;
+     rtx cc_reg;
+     rtx cr_reg;
+     HOST_WIDE_INT value;
+{
+  rtx ret;
+
+  start_sequence ();
+
+  /* Set the appropriate CCR bit.  */
+  emit_insn (gen_rtx_SET (VOIDmode,
+                         cr_reg,
+                         gen_rtx_fmt_ee (GET_CODE (test),
+                                         GET_MODE (cr_reg),
+                                         cc_reg,
+                                         const0_rtx)));
+
+  /* Move the value into the destination.  */
+  emit_move_insn (dest, GEN_INT (value));
+
+  /* Move 0 into the destination if the test failed */
+  emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                               gen_rtx_EQ (GET_MODE (cr_reg),
+                                           cr_reg,
+                                           const0_rtx),
+                               gen_rtx_SET (VOIDmode, dest, const0_rtx)));
+
+  /* Finish up, return sequence.  */
+  ret = get_insns ();
+  end_sequence ();
+  return ret;
+}
+
+\f
+/* Emit the code for a conditional move, return TRUE if we could do the
+   move.  */
+
+int
+frv_emit_cond_move (dest, test_rtx, src1, src2)
+     rtx dest;
+     rtx test_rtx;
+     rtx src1;
+     rtx src2;
+{
+  rtx set;
+  rtx clobber_cc;
+  rtx test2;
+  rtx cr_reg;
+  rtx if_rtx;
+  enum rtx_code test = GET_CODE (test_rtx);
+  rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1);
+  enum machine_mode cc_mode = GET_MODE (cc_reg);
+
+  /* Conditional move instructions generate:
+       (parallel [(set <target>
+                       (if_then_else (<test> <cc_reg> (const_int 0))
+                                     <src1>
+                                     <src2>))
+                  (clobber (<ccr_reg>))])  */
+
+  /* Handle various cases of conditional move involving two constants.  */
+  if (GET_CODE (src1) == CONST_INT && GET_CODE (src2) == CONST_INT)
+    {
+      HOST_WIDE_INT value1 = INTVAL (src1);
+      HOST_WIDE_INT value2 = INTVAL (src2);
+
+      /* having 0 as one of the constants can be done by loading the other
+         constant, and optionally moving in gr0.  */
+      if (value1 == 0 || value2 == 0)
+       ;
+
+      /* If the first value is within an addi range and also the difference
+         between the two fits in an addi's range, load up the difference, then
+         conditionally move in 0, and then unconditionally add the first
+        value.  */
+      else if (IN_RANGE_P (value1, -2048, 2047)
+              && IN_RANGE_P (value2 - value1, -2048, 2047))
+       ;
+
+      /* If neither condition holds, just force the constant into a
+        register.  */
+      else
+       {
+         src1 = force_reg (GET_MODE (dest), src1);
+         src2 = force_reg (GET_MODE (dest), src2);
+       }
+    }
+
+  /* If one value is a register, insure the other value is either 0 or a
+     register.  */
+  else
+    {
+      if (GET_CODE (src1) == CONST_INT && INTVAL (src1) != 0)
+       src1 = force_reg (GET_MODE (dest), src1);
+
+      if (GET_CODE (src2) == CONST_INT && INTVAL (src2) != 0)
+       src2 = force_reg (GET_MODE (dest), src2);
+    }
+
+  test2 = gen_rtx_fmt_ee (test, cc_mode, cc_reg, const0_rtx);
+  if_rtx = gen_rtx_IF_THEN_ELSE (GET_MODE (dest), test2, src1, src2);
+
+  set = gen_rtx_SET (VOIDmode, dest, if_rtx);
+
+  cr_reg = ((TARGET_ALLOC_CC)
+           ? gen_reg_rtx (CC_CCRmode)
+           : gen_rtx_REG (CC_CCRmode,
+                          (cc_mode == CC_FPmode) ? FCR_FIRST : ICR_FIRST));
+
+  clobber_cc = gen_rtx_CLOBBER (VOIDmode, cr_reg);
+  emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber_cc)));
+  return TRUE;
+}
+
+\f
+/* Split a conditonal move into constituent parts, returning a SEQUENCE
+   containing all of the insns.  */
+
+rtx
+frv_split_cond_move (operands)
+     rtx operands[];
+{
+  rtx dest     = operands[0];
+  rtx test     = operands[1];
+  rtx cc_reg   = operands[2];
+  rtx src1     = operands[3];
+  rtx src2     = operands[4];
+  rtx cr_reg   = operands[5];
+  rtx ret;
+  enum machine_mode cr_mode = GET_MODE (cr_reg);
+
+  start_sequence ();
+
+  /* Set the appropriate CCR bit.  */
+  emit_insn (gen_rtx_SET (VOIDmode,
+                         cr_reg,
+                         gen_rtx_fmt_ee (GET_CODE (test),
+                                         GET_MODE (cr_reg),
+                                         cc_reg,
+                                         const0_rtx)));
+
+  /* Handle various cases of conditional move involving two constants.  */
+  if (GET_CODE (src1) == CONST_INT && GET_CODE (src2) == CONST_INT)
+    {
+      HOST_WIDE_INT value1 = INTVAL (src1);
+      HOST_WIDE_INT value2 = INTVAL (src2);
+
+      /* having 0 as one of the constants can be done by loading the other
+         constant, and optionally moving in gr0.  */
+      if (value1 == 0)
+       {
+         emit_move_insn (dest, src2);
+         emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                                       gen_rtx_NE (cr_mode, cr_reg,
+                                                   const0_rtx),
+                                       gen_rtx_SET (VOIDmode, dest, src1)));
+       }
+
+      else if (value2 == 0)
+       {
+         emit_move_insn (dest, src1);
+         emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                                       gen_rtx_EQ (cr_mode, cr_reg,
+                                                   const0_rtx),
+                                       gen_rtx_SET (VOIDmode, dest, src2)));
+       }
+
+      /* If the first value is within an addi range and also the difference
+         between the two fits in an addi's range, load up the difference, then
+         conditionally move in 0, and then unconditionally add the first
+        value.  */
+      else if (IN_RANGE_P (value1, -2048, 2047)
+              && IN_RANGE_P (value2 - value1, -2048, 2047))
+       {
+         rtx dest_si = ((GET_MODE (dest) == SImode)
+                        ? dest
+                        : gen_rtx_SUBREG (SImode, dest, 0));
+
+         emit_move_insn (dest_si, GEN_INT (value2 - value1));
+         emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                                       gen_rtx_NE (cr_mode, cr_reg,
+                                                   const0_rtx),
+                                       gen_rtx_SET (VOIDmode, dest_si,
+                                                    const0_rtx)));
+         emit_insn (gen_addsi3 (dest_si, dest_si, src1));
+       }
+
+      else
+       abort ();
+    }
+  else
+    {
+      /* Emit the conditional move for the test being true if needed.  */
+      if (! rtx_equal_p (dest, src1))
+       emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                                     gen_rtx_NE (cr_mode, cr_reg, const0_rtx),
+                                     gen_rtx_SET (VOIDmode, dest, src1)));
+
+      /* Emit the conditional move for the test being false if needed.  */
+      if (! rtx_equal_p (dest, src2))
+       emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                                     gen_rtx_EQ (cr_mode, cr_reg, const0_rtx),
+                                     gen_rtx_SET (VOIDmode, dest, src2)));
+    }
+
+  /* Finish up, return sequence.  */
+  ret = get_insns ();
+  end_sequence ();
+  return ret;
+}
+
+\f
+/* Split (set DEST SOURCE), where DEST is a double register and SOURCE is a
+   memory location that is not known to be dword-aligned.  */
+void
+frv_split_double_load (dest, source)
+     rtx dest;
+     rtx source;
+{
+  int regno = REGNO (dest);
+  rtx dest1 = gen_highpart (SImode, dest);
+  rtx dest2 = gen_lowpart (SImode, dest);
+  rtx address = XEXP (source, 0);
+
+  /* If the address is pre-modified, load the lower-numbered register
+     first, then load the other register using an integer offset from
+     the modified base register.  This order should always be safe,
+     since the pre-modification cannot affect the same registers as the
+     load does.
+
+     The situation for other loads is more complicated.  Loading one
+     of the registers could affect the value of ADDRESS, so we must
+     be careful which order we do them in.  */
+  if (GET_CODE (address) == PRE_MODIFY
+      || ! refers_to_regno_p (regno, regno + 1, address, NULL))
+    {
+      /* It is safe to load the lower-numbered register first.  */
+      emit_move_insn (dest1, change_address (source, SImode, NULL));
+      emit_move_insn (dest2, frv_index_memory (source, SImode, 1));
+    }
+  else
+    {
+      /* ADDRESS is not pre-modified and the address depends on the
+         lower-numbered register.  Load the higher-numbered register
+         first.  */
+      emit_move_insn (dest2, frv_index_memory (source, SImode, 1));
+      emit_move_insn (dest1, change_address (source, SImode, NULL));
+    }
+}
+
+/* Split (set DEST SOURCE), where DEST refers to a dword memory location
+   and SOURCE is either a double register or the constant zero.  */
+void
+frv_split_double_store (dest, source)
+     rtx dest;
+     rtx source;
+{
+  rtx dest1 = change_address (dest, SImode, NULL);
+  rtx dest2 = frv_index_memory (dest, SImode, 1);
+  if (ZERO_P (source))
+    {
+      emit_move_insn (dest1, CONST0_RTX (SImode));
+      emit_move_insn (dest2, CONST0_RTX (SImode));
+    }
+  else
+    {
+      emit_move_insn (dest1, gen_highpart (SImode, source));
+      emit_move_insn (dest2, gen_lowpart (SImode, source));
+    }
+}
+
+\f
+/* Split a min/max operation returning a SEQUENCE containing all of the
+   insns.  */
+
+rtx
+frv_split_minmax (operands)
+     rtx operands[];
+{
+  rtx dest     = operands[0];
+  rtx minmax   = operands[1];
+  rtx src1     = operands[2];
+  rtx src2     = operands[3];
+  rtx cc_reg   = operands[4];
+  rtx cr_reg   = operands[5];
+  rtx ret;
+  enum rtx_code test_code;
+  enum machine_mode cr_mode = GET_MODE (cr_reg);
+
+  start_sequence ();
+
+  /* Figure out which test to use */
+  switch (GET_CODE (minmax))
+    {
+    default:
+      abort ();
+
+    case SMIN: test_code = LT;  break;
+    case SMAX: test_code = GT;  break;
+    case UMIN: test_code = LTU; break;
+    case UMAX: test_code = GTU; break;
+    }
+
+  /* Issue the compare instruction.  */
+  emit_insn (gen_rtx_SET (VOIDmode,
+                         cc_reg,
+                         gen_rtx_COMPARE (GET_MODE (cc_reg),
+                                          src1, src2)));
+
+  /* Set the appropriate CCR bit.  */
+  emit_insn (gen_rtx_SET (VOIDmode,
+                         cr_reg,
+                         gen_rtx_fmt_ee (test_code,
+                                         GET_MODE (cr_reg),
+                                         cc_reg,
+                                         const0_rtx)));
+
+  /* If are taking the min/max of a non-zero constant, load that first, and
+     then do a conditional move of the other value.  */
+  if (GET_CODE (src2) == CONST_INT && INTVAL (src2) != 0)
+    {
+      if (rtx_equal_p (dest, src1))
+       abort ();
+
+      emit_move_insn (dest, src2);
+      emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                                   gen_rtx_NE (cr_mode, cr_reg, const0_rtx),
+                                   gen_rtx_SET (VOIDmode, dest, src1)));
+    }
+
+  /* Otherwise, do each half of the move.  */
+  else
+    {
+      /* Emit the conditional move for the test being true if needed.  */
+      if (! rtx_equal_p (dest, src1))
+       emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                                     gen_rtx_NE (cr_mode, cr_reg, const0_rtx),
+                                     gen_rtx_SET (VOIDmode, dest, src1)));
+
+      /* Emit the conditional move for the test being false if needed.  */
+      if (! rtx_equal_p (dest, src2))
+       emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                                     gen_rtx_EQ (cr_mode, cr_reg, const0_rtx),
+                                     gen_rtx_SET (VOIDmode, dest, src2)));
+    }
+
+  /* Finish up, return sequence.  */
+  ret = get_insns ();
+  end_sequence ();
+  return ret;
+}
+
+\f
+/* Split an integer abs operation returning a SEQUENCE containing all of the
+   insns.  */
+
+rtx
+frv_split_abs (operands)
+     rtx operands[];
+{
+  rtx dest     = operands[0];
+  rtx src      = operands[1];
+  rtx cc_reg   = operands[2];
+  rtx cr_reg   = operands[3];
+  rtx ret;
+
+  start_sequence ();
+
+  /* Issue the compare < 0 instruction.  */
+  emit_insn (gen_rtx_SET (VOIDmode,
+                         cc_reg,
+                         gen_rtx_COMPARE (CCmode, src, const0_rtx)));
+
+  /* Set the appropriate CCR bit.  */
+  emit_insn (gen_rtx_SET (VOIDmode,
+                         cr_reg,
+                         gen_rtx_fmt_ee (LT, CC_CCRmode, cc_reg, const0_rtx)));
+
+  /* Emit the conditional negate if the value is negative */
+  emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                               gen_rtx_NE (CC_CCRmode, cr_reg, const0_rtx),
+                               gen_negsi2 (dest, src)));
+
+  /* Emit the conditional move for the test being false if needed.  */
+  if (! rtx_equal_p (dest, src))
+    emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                                 gen_rtx_EQ (CC_CCRmode, cr_reg, const0_rtx),
+                                 gen_rtx_SET (VOIDmode, dest, src)));
+
+  /* Finish up, return sequence.  */
+  ret = get_insns ();
+  end_sequence ();
+  return ret;
+}
+
+\f
+/* An internal function called by for_each_rtx to clear in a hard_reg set each
+   register used in an insn.  */
+
+static int
+frv_clear_registers_used (ptr, data)
+     rtx *ptr;
+     void *data;
+{
+  if (GET_CODE (*ptr) == REG)
+    {
+      int regno = REGNO (*ptr);
+      HARD_REG_SET *p_regs = (HARD_REG_SET *)data;
+
+      if (regno < FIRST_PSEUDO_REGISTER)
+       {
+         int reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (*ptr));
+
+         while (regno < reg_max)
+           {
+             CLEAR_HARD_REG_BIT (*p_regs, regno);
+             regno++;
+           }
+       }
+    }
+
+  return 0;
+}
+
+\f
+/* Initialize the extra fields provided by IFCVT_EXTRA_FIELDS.  */
+
+/* On the FR-V, we don't have any extra fields per se, but it is useful hook to
+   initialize the static storage.  */
+void
+frv_ifcvt_init_extra_fields (ce_info)
+     ce_if_block_t *ce_info ATTRIBUTE_UNUSED;
+{
+  frv_ifcvt.added_insns_list = NULL_RTX;
+  frv_ifcvt.cur_scratch_regs = 0;
+  frv_ifcvt.num_nested_cond_exec = 0;
+  frv_ifcvt.cr_reg = NULL_RTX;
+  frv_ifcvt.nested_cc_reg = NULL_RTX;
+  frv_ifcvt.extra_int_cr = NULL_RTX;
+  frv_ifcvt.extra_fp_cr = NULL_RTX;
+  frv_ifcvt.last_nested_if_cr = NULL_RTX;
+}
+
+\f
+/* Internal function to add a potenial insn to the list of insns to be inserted
+   if the conditional execution conversion is successful.  */
+
+static void
+frv_ifcvt_add_insn (pattern, insn, before_p)
+     rtx pattern;
+     rtx insn;
+     int before_p;
+{
+  rtx link = alloc_EXPR_LIST (VOIDmode, pattern, insn);
+
+  link->jump = before_p;       /* mark to add this before or after insn */
+  frv_ifcvt.added_insns_list = alloc_EXPR_LIST (VOIDmode, link,
+                                               frv_ifcvt.added_insns_list);
+
+  if (TARGET_DEBUG_COND_EXEC)
+    {
+      fprintf (stderr,
+              "\n:::::::::: frv_ifcvt_add_insn: add the following %s insn %d:\n",
+              (before_p) ? "before" : "after",
+              (int)INSN_UID (insn));
+
+      debug_rtx (pattern);
+    }
+}
+
+\f
+/* A C expression to modify the code described by the conditional if
+   information CE_INFO, possibly updating the tests in TRUE_EXPR, and
+   FALSE_EXPR for converting if-then and if-then-else code to conditional
+   instructions.  Set either TRUE_EXPR or FALSE_EXPR to a null pointer if the
+   tests cannot be converted.  */
+
+void
+frv_ifcvt_modify_tests (ce_info, p_true, p_false)
+     ce_if_block_t *ce_info;
+     rtx *p_true;
+     rtx *p_false;
+{
+  basic_block test_bb = ce_info->test_bb;      /* test basic block */
+  basic_block then_bb = ce_info->then_bb;      /* THEN */
+  basic_block else_bb = ce_info->else_bb;      /* ELSE or NULL */
+  basic_block join_bb = ce_info->join_bb;      /* join block or NULL */
+  rtx true_expr = *p_true;
+  rtx cr;
+  rtx cc;
+  rtx nested_cc;
+  enum machine_mode mode = GET_MODE (true_expr);
+  int j;
+  basic_block *bb;
+  int num_bb;
+  frv_tmp_reg_t *tmp_reg = &frv_ifcvt.tmp_reg;
+  rtx check_insn;
+  rtx sub_cond_exec_reg;
+  enum rtx_code code;
+  enum rtx_code code_true;
+  enum rtx_code code_false;
+  enum reg_class cc_class;
+  enum reg_class cr_class;
+  int cc_first;
+  int cc_last;
+
+  /* Make sure we are only dealing with hard registers.  Also honor the
+     -mno-cond-exec switch, and -mno-nested-cond-exec switches if
+     applicable.  */
+  if (!reload_completed || TARGET_NO_COND_EXEC
+      || (TARGET_NO_NESTED_CE && ce_info->pass > 1))
+    goto fail;
+
+  /* Figure out which registers we can allocate for our own purposes.  Only
+     consider registers that are not preserved across function calls and are
+     not fixed.  However, allow the ICC/ICR temporary registers to be allocated
+     if we did not need to use them in reloading other registers. */
+  memset ((PTR) &tmp_reg->regs, 0, sizeof (tmp_reg->regs));
+  COPY_HARD_REG_SET (tmp_reg->regs, call_used_reg_set);
+  AND_COMPL_HARD_REG_SET (tmp_reg->regs, fixed_reg_set);
+  SET_HARD_REG_BIT (tmp_reg->regs, ICC_TEMP);
+  SET_HARD_REG_BIT (tmp_reg->regs, ICR_TEMP);
+
+  /* If this is a nested IF, we need to discover whether the CC registers that
+     are set/used inside of the block are used anywhere else.  If not, we can
+     change them to be the CC register that is paired with the CR register that
+     controls the outermost IF block.  */
+  if (ce_info->pass > 1)
+    {
+      CLEAR_HARD_REG_SET (frv_ifcvt.nested_cc_ok_rewrite);
+      for (j = CC_FIRST; j <= CC_LAST; j++)
+       if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
+         {
+           if (REGNO_REG_SET_P (then_bb->global_live_at_start, j))
+             continue;
+
+           if (else_bb && REGNO_REG_SET_P (else_bb->global_live_at_start, j))
+             continue;
+
+           if (join_bb && REGNO_REG_SET_P (join_bb->global_live_at_start, j))
+             continue;
+
+           SET_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite, j);
+         }
+    }
+
+  for (j = 0; j < frv_ifcvt.cur_scratch_regs; j++)
+    frv_ifcvt.scratch_regs[j] = NULL_RTX;
+
+  frv_ifcvt.added_insns_list = NULL_RTX;
+  frv_ifcvt.cur_scratch_regs = 0;
+
+  bb = (basic_block *) alloca ((2 + ce_info->num_multiple_test_blocks)
+                              * sizeof (basic_block));
+
+  if (join_bb)
+    {
+      int regno;
+
+      /* Remove anything live at the beginning of the join block from being
+         available for allocation.  */
+      EXECUTE_IF_SET_IN_REG_SET (join_bb->global_live_at_start, 0, regno,
+                                {
+                                  if (regno < FIRST_PSEUDO_REGISTER)
+                                    CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
+                                });
+    }
+
+  /* Add in all of the blocks in multiple &&/|| blocks to be scanned.  */
+  num_bb = 0;
+  if (ce_info->num_multiple_test_blocks)
+    {
+      basic_block multiple_test_bb = ce_info->last_test_bb;
+
+      while (multiple_test_bb != test_bb)
+       {
+         bb[num_bb++] = multiple_test_bb;
+         multiple_test_bb = multiple_test_bb->pred->src;
+       }
+    }
+
+  /* Add in the THEN and ELSE blocks to be scanned.  */
+  bb[num_bb++] = then_bb;
+  if (else_bb)
+    bb[num_bb++] = else_bb;
+
+  sub_cond_exec_reg = NULL_RTX;
+  frv_ifcvt.num_nested_cond_exec = 0;
+
+  /* Scan all of the blocks for registers that must not be allocated.  */
+  for (j = 0; j < num_bb; j++)
+    {
+      rtx last_insn = bb[j]->end;
+      rtx insn = bb[j]->head;
+      int regno;
+
+      if (rtl_dump_file)
+       fprintf (rtl_dump_file, "Scanning %s block %d, start %d, end %d\n",
+                (bb[j] == else_bb) ? "else" : ((bb[j] == then_bb) ? "then" : "test"),
+                (int) bb[j]->index,
+                (int) INSN_UID (bb[j]->head),
+                (int) INSN_UID (bb[j]->end));
+
+      /* Anything live at the beginning of the block is obviously unavailable
+         for allocation.  */
+      EXECUTE_IF_SET_IN_REG_SET (bb[j]->global_live_at_start, 0, regno,
+                                {
+                                  if (regno < FIRST_PSEUDO_REGISTER)
+                                    CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
+                                });
+
+      /* loop through the insns in the block.  */
+      for (;;)
+       {
+         /* Mark any new registers that are created as being unavailable for
+             allocation.  Also see if the CC register used in nested IFs can be
+             reallocated.  */
+         if (INSN_P (insn))
+           {
+             rtx pattern;
+             rtx set;
+             int skip_nested_if = FALSE;
+
+             for_each_rtx (&PATTERN (insn), frv_clear_registers_used,
+                           (void *)&tmp_reg->regs);
+
+             pattern = PATTERN (insn);
+             if (GET_CODE (pattern) == COND_EXEC)
+               {
+                 rtx reg = XEXP (COND_EXEC_TEST (pattern), 0);
+
+                 if (reg != sub_cond_exec_reg)
+                   {
+                     sub_cond_exec_reg = reg;
+                     frv_ifcvt.num_nested_cond_exec++;
+                   }
+               }
+
+             set = single_set_pattern (pattern);
+             if (set)
+               {
+                 rtx dest = SET_DEST (set);
+                 rtx src = SET_SRC (set);
+
+                 if (GET_CODE (dest) == REG)
+                   {
+                     int regno = REGNO (dest);
+                     enum rtx_code src_code = GET_CODE (src);
+
+                     if (CC_P (regno) && src_code == COMPARE)
+                       skip_nested_if = TRUE;
+
+                     else if (CR_P (regno)
+                              && (src_code == IF_THEN_ELSE
+                                  || GET_RTX_CLASS (src_code) == '<'))
+                       skip_nested_if = TRUE;
+                   }
+               }
+
+             if (! skip_nested_if)
+               for_each_rtx (&PATTERN (insn), frv_clear_registers_used,
+                             (void *)&frv_ifcvt.nested_cc_ok_rewrite);
+           }
+
+         if (insn == last_insn)
+           break;
+
+         insn = NEXT_INSN (insn);
+       }
+    }
+
+  /* If this is a nested if, rewrite the CC registers that are available to
+     include the ones that can be rewritten, to increase the chance of being
+     able to allocate a paired CC/CR register combination.  */
+  if (ce_info->pass > 1)
+    {
+      for (j = CC_FIRST; j <= CC_LAST; j++)
+       if (TEST_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite, j))
+         SET_HARD_REG_BIT (tmp_reg->regs, j);
+       else
+         CLEAR_HARD_REG_BIT (tmp_reg->regs, j);
+    }
+
+  if (rtl_dump_file)
+    {
+      int num_gprs = 0;
+      fprintf (rtl_dump_file, "Available GPRs: ");
+
+      for (j = GPR_FIRST; j <= GPR_LAST; j++)
+       if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
+         {
+           fprintf (rtl_dump_file, " %d [%s]", j, reg_names[j]);
+           if (++num_gprs > GPR_TEMP_NUM+2)
+             break;
+         }
+
+      fprintf (rtl_dump_file, "%s\nAvailable CRs:  ",
+              (num_gprs > GPR_TEMP_NUM+2) ? " ..." : "");
+
+      for (j = CR_FIRST; j <= CR_LAST; j++)
+       if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
+         fprintf (rtl_dump_file, " %d [%s]", j, reg_names[j]);
+
+      fputs ("\n", rtl_dump_file);
+
+      if (ce_info->pass > 1)
+       {
+         fprintf (rtl_dump_file, "Modifiable CCs: ");
+         for (j = CC_FIRST; j <= CC_LAST; j++)
+           if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
+             fprintf (rtl_dump_file, " %d [%s]", j, reg_names[j]);
+
+         fprintf (rtl_dump_file, "\n%d nested COND_EXEC statements\n",
+                  frv_ifcvt.num_nested_cond_exec);
+       }
+    }
+
+  /* Allocate the appropriate temporary condition code register.  Try to
+     allocate the ICR/FCR register that corresponds to the ICC/FCC register so
+     that conditional cmp's can be done.  */
+  if (mode == CCmode || mode == CC_UNSmode)
+    {
+      cr_class = ICR_REGS;
+      cc_class = ICC_REGS;
+      cc_first = ICC_FIRST;
+      cc_last = ICC_LAST;
+    }
+  else if (mode == CC_FPmode)
+    {
+      cr_class = FCR_REGS;
+      cc_class = FCC_REGS;
+      cc_first = FCC_FIRST;
+      cc_last = FCC_LAST;
+    }
+  else
+    {
+      cc_first = cc_last = 0;
+      cr_class = cc_class = NO_REGS;
+    }
+
+  cc = XEXP (true_expr, 0);
+  nested_cc = cr = NULL_RTX;
+  if (cc_class != NO_REGS)
+    {
+      /* For nested IFs and &&/||, see if we can find a CC and CR register pair
+         so we can execute a csubcc/caddcc/cfcmps instruction.  */
+      int cc_regno;
+
+      for (cc_regno = cc_first; cc_regno <= cc_last; cc_regno++)
+       {
+         int cr_regno = cc_regno - CC_FIRST + CR_FIRST;
+
+         if (TEST_HARD_REG_BIT (frv_ifcvt.tmp_reg.regs, cc_regno)
+             && TEST_HARD_REG_BIT (frv_ifcvt.tmp_reg.regs, cr_regno))
+           {
+             frv_ifcvt.tmp_reg.next_reg[ (int)cr_class ] = cr_regno;
+             cr = frv_alloc_temp_reg (tmp_reg, cr_class, CC_CCRmode, TRUE,
+                                      TRUE);
+
+             frv_ifcvt.tmp_reg.next_reg[ (int)cc_class ] = cc_regno;
+             nested_cc = frv_alloc_temp_reg (tmp_reg, cc_class, CCmode,
+                                                 TRUE, TRUE);
+             break;
+           }
+       }
+    }
+
+  if (! cr)
+    {
+      if (rtl_dump_file)
+       fprintf (rtl_dump_file, "Could not allocate a CR temporary register\n");
+
+      goto fail;
+    }
+
+  if (rtl_dump_file)
+    fprintf (rtl_dump_file,
+            "Will use %s for conditional execution, %s for nested comparisons\n",
+            reg_names[ REGNO (cr)],
+            (nested_cc) ? reg_names[ REGNO (nested_cc) ] : "<none>");
+
+  /* Set the CCR bit.  Note for integer tests, we reverse the condition so that
+     in an IF-THEN-ELSE sequence, we are testing the TRUE case against the CCR
+     bit being true.  We don't do this for floating point, because of NaNs.  */
+  code = GET_CODE (true_expr);
+  if (GET_MODE (cc) != CC_FPmode)
+    {
+      code = reverse_condition (code);
+      code_true = EQ;
+      code_false = NE;
+    }
+  else
+    {
+      code_true = NE;
+      code_false = EQ;
+    }
+
+  check_insn = gen_rtx_SET (VOIDmode, cr,
+                           gen_rtx_fmt_ee (code, CC_CCRmode, cc, const0_rtx));
+
+  /* Record the check insn to be inserted later.  */
+  frv_ifcvt_add_insn (check_insn, test_bb->end, TRUE);
+
+  /* Update the tests.  */
+  frv_ifcvt.cr_reg = cr;
+  frv_ifcvt.nested_cc_reg = nested_cc;
+  *p_true = gen_rtx_fmt_ee (code_true, CC_CCRmode, cr, const0_rtx);
+  *p_false = gen_rtx_fmt_ee (code_false, CC_CCRmode, cr, const0_rtx);
+  return;
+
+  /* Fail, don't do this conditional execution.  */
+ fail:
+  *p_true = NULL_RTX;
+  *p_false = NULL_RTX;
+  if (rtl_dump_file)
+    fprintf (rtl_dump_file, "Disabling this conditional execution.\n");
+
+  return;
+}
+
+\f
+/* A C expression to modify the code described by the conditional if
+   information CE_INFO, for the basic block BB, possibly updating the tests in
+   TRUE_EXPR, and FALSE_EXPR for converting the && and || parts of if-then or
+   if-then-else code to conditional instructions.  Set either TRUE_EXPR or
+   FALSE_EXPR to a null pointer if the tests cannot be converted.  */
+
+/* p_true and p_false are given expressions of the form:
+
+       (and (eq:CC_CCR (reg:CC_CCR)
+                       (const_int 0))
+            (eq:CC (reg:CC)
+                   (const_int 0))) */
+
+void
+frv_ifcvt_modify_multiple_tests (ce_info, bb, p_true, p_false)
+     ce_if_block_t *ce_info;
+     basic_block bb;
+     rtx *p_true;
+     rtx *p_false;
+{
+  rtx old_true = XEXP (*p_true, 0);
+  rtx old_false = XEXP (*p_false, 0);
+  rtx true_expr = XEXP (*p_true, 1);
+  rtx false_expr = XEXP (*p_false, 1);
+  rtx test_expr;
+  rtx old_test;
+  rtx cr = XEXP (old_true, 0);
+  rtx check_insn;
+  rtx new_cr = NULL_RTX;
+  rtx *p_new_cr = (rtx *)0;
+  rtx if_else;
+  rtx compare;
+  rtx cc;
+  enum reg_class cr_class;
+  enum machine_mode mode = GET_MODE (true_expr);
+  rtx (*logical_func)(rtx, rtx, rtx);
+
+  if (TARGET_DEBUG_COND_EXEC)
+    {
+      fprintf (stderr,
+              "\n:::::::::: frv_ifcvt_modify_multiple_tests, before modification for %s\ntrue insn:\n",
+              ce_info->and_and_p ? "&&" : "||");
+
+      debug_rtx (*p_true);
+
+      fputs ("\nfalse insn:\n", stderr);
+      debug_rtx (*p_false);
+    }
+
+  if (TARGET_NO_MULTI_CE)
+    goto fail;
+
+  if (GET_CODE (cr) != REG)
+    goto fail;
+      
+  if (mode == CCmode || mode == CC_UNSmode)
+    {
+      cr_class = ICR_REGS;
+      p_new_cr = &frv_ifcvt.extra_int_cr;
+    }
+  else if (mode == CC_FPmode)
+    {
+      cr_class = FCR_REGS;
+      p_new_cr = &frv_ifcvt.extra_fp_cr;
+    }
+  else
+    goto fail;
+
+  /* Allocate a temp CR, reusing a previously allocated temp CR if we have 3 or
+     more &&/|| tests.  */
+  new_cr = *p_new_cr;
+  if (! new_cr)
+    {
+      new_cr = *p_new_cr = frv_alloc_temp_reg (&frv_ifcvt.tmp_reg, cr_class,
+                                              CC_CCRmode, TRUE, TRUE);
+      if (! new_cr)
+       goto fail;
+    }
+
+  if (ce_info->and_and_p)
+    {
+      old_test = old_false;
+      test_expr = true_expr;
+      logical_func = (GET_CODE (old_true) == EQ) ? gen_andcr : gen_andncr;
+      *p_true = gen_rtx_NE (CC_CCRmode, cr, const0_rtx);
+      *p_false = gen_rtx_EQ (CC_CCRmode, cr, const0_rtx);
+    }
+  else
+    {
+      old_test = old_false;
+      test_expr = false_expr;
+      logical_func = (GET_CODE (old_false) == EQ) ? gen_orcr : gen_orncr;
+      *p_true = gen_rtx_EQ (CC_CCRmode, cr, const0_rtx);
+      *p_false = gen_rtx_NE (CC_CCRmode, cr, const0_rtx);
+    }
+
+  /* First add the andcr/andncr/orcr/orncr, which will be added after the
+     conditional check instruction, due to frv_ifcvt_add_insn being a LIFO
+     stack.  */
+  frv_ifcvt_add_insn ((*logical_func) (cr, cr, new_cr), bb->end, TRUE);
+
+  /* Now add the conditional check insn.  */
+  cc = XEXP (test_expr, 0);
+  compare = gen_rtx_fmt_ee (GET_CODE (test_expr), CC_CCRmode, cc, const0_rtx);
+  if_else = gen_rtx_IF_THEN_ELSE (CC_CCRmode, old_test, compare, const0_rtx);
+
+  check_insn = gen_rtx_SET (VOIDmode, new_cr, if_else);
+
+  /* add the new check insn to the list of check insns that need to be
+     inserted.  */
+  frv_ifcvt_add_insn (check_insn, bb->end, TRUE);
+
+  if (TARGET_DEBUG_COND_EXEC)
+    {
+      fputs ("\n:::::::::: frv_ifcvt_modify_multiple_tests, after modification\ntrue insn:\n",
+            stderr);
+
+      debug_rtx (*p_true);
+
+      fputs ("\nfalse insn:\n", stderr);
+      debug_rtx (*p_false);
+    }
+
+  return;
+
+ fail:
+  *p_true = *p_false = NULL_RTX;
+
+  /* If we allocated a CR register, release it. */
+  if (new_cr)
+    {
+      CLEAR_HARD_REG_BIT (frv_ifcvt.tmp_reg.regs, REGNO (new_cr));
+      *p_new_cr = NULL_RTX;
+    }
+
+  if (TARGET_DEBUG_COND_EXEC)
+    fputs ("\n:::::::::: frv_ifcvt_modify_multiple_tests, failed.\n", stderr);
+
+  return;
+}
+
+\f
+/* Return a register which will be loaded with a value if an IF block is
+   converted to conditional execution.  This is used to rewrite instructions
+   that use constants to ones that just use registers.  */
+
+static rtx
+frv_ifcvt_load_value (value, insn)
+     rtx value;
+     rtx insn ATTRIBUTE_UNUSED;
+{
+  int num_alloc = frv_ifcvt.cur_scratch_regs;
+  int i;
+  rtx reg;
+
+  /* We know gr0 == 0, so replace any errant uses.  */
+  if (value == const0_rtx)
+    return gen_rtx_REG (SImode, GPR_FIRST);
+
+  /* First search all registers currently loaded to see if we have an
+     applicable constant.  */
+  if (CONSTANT_P (value)
+      || (GET_CODE (value) == REG && REGNO (value) == LR_REGNO))
+    {
+      for (i = 0; i < num_alloc; i++)
+       {
+         if (rtx_equal_p (SET_SRC (frv_ifcvt.scratch_regs[i]), value))
+           return SET_DEST (frv_ifcvt.scratch_regs[i]);
+       }
+    }
+
+  /* Have we exhausted the number of registers available? */
+  if (num_alloc >= GPR_TEMP_NUM)
+    {
+      if (rtl_dump_file)
+       fprintf (rtl_dump_file, "Too many temporary registers allocated\n");
+
+      return NULL_RTX;
+    }
+
+  /* Allocate the new register.  */
+  reg = frv_alloc_temp_reg (&frv_ifcvt.tmp_reg, GPR_REGS, SImode, TRUE, TRUE);
+  if (! reg)
+    {
+      if (rtl_dump_file)
+       fputs ("Could not find a scratch register\n", rtl_dump_file);
+
+      return NULL_RTX;
+    }
+
+  frv_ifcvt.cur_scratch_regs++;
+  frv_ifcvt.scratch_regs[num_alloc] = gen_rtx_SET (VOIDmode, reg, value);
+
+  if (rtl_dump_file)
+    {
+      if (GET_CODE (value) == CONST_INT)
+       fprintf (rtl_dump_file, "Register %s will hold %ld\n",
+                reg_names[ REGNO (reg)], (long)INTVAL (value));
+
+      else if (GET_CODE (value) == REG && REGNO (value) == LR_REGNO)
+       fprintf (rtl_dump_file, "Register %s will hold LR\n",
+                reg_names[ REGNO (reg)]);
+
+      else
+       fprintf (rtl_dump_file, "Register %s will hold a saved value\n",
+                reg_names[ REGNO (reg)]);
+    }
+
+  return reg;
+}
+
+\f
+/* Update a MEM used in conditional code that might contain an offset to put
+   the offset into a scratch register, so that the conditional load/store
+   operations can be used.  This function returns the original pointer if the
+   MEM is valid to use in conditional code, NULL if we can't load up the offset
+   into a temporary register, or the new MEM if we were successful.  */
+
+static rtx
+frv_ifcvt_rewrite_mem (mem, mode, insn)
+     rtx mem;
+     enum machine_mode mode;
+     rtx insn;
+{
+  rtx addr = XEXP (mem, 0);
+
+  if (!frv_legitimate_address_p (mode, addr, reload_completed, TRUE))
+    {
+      if (GET_CODE (addr) == PLUS)
+       {
+         rtx addr_op0 = XEXP (addr, 0);
+         rtx addr_op1 = XEXP (addr, 1);
+
+         if (plus_small_data_p (addr_op0, addr_op1))
+           addr = frv_ifcvt_load_value (addr, insn);
+
+         else if (GET_CODE (addr_op0) == REG && CONSTANT_P (addr_op1))
+           {
+             rtx reg = frv_ifcvt_load_value (addr_op1, insn);
+             if (!reg)
+               return NULL_RTX;
+
+             addr = gen_rtx_PLUS (Pmode, addr_op0, reg);
+           }
+
+         else
+           return NULL_RTX;
+       }
+
+      else if (CONSTANT_P (addr))
+       addr = frv_ifcvt_load_value (addr, insn);
+
+      else
+       return NULL_RTX;
+
+      if (addr == NULL_RTX)
+       return NULL_RTX;
+
+      else if (XEXP (mem, 0) != addr)
+       return change_address (mem, mode, addr);
+    }
+
+  return mem;
+}
+
+\f
+/* Given a PATTERN, return a SET expression if this PATTERN has only a single
+   SET, possibly conditionally executed.  It may also have CLOBBERs, USEs.  */
+
+static rtx
+single_set_pattern (pattern)
+     rtx pattern;
+{
+  rtx set;
+  int i;
+
+  if (GET_CODE (pattern) == COND_EXEC)
+    pattern = COND_EXEC_CODE (pattern);
+
+  if (GET_CODE (pattern) == SET)
+    return pattern;
+
+  else if (GET_CODE (pattern) == PARALLEL)
+    {
+      for (i = 0, set = 0; i < XVECLEN (pattern, 0); i++)
+       {
+         rtx sub = XVECEXP (pattern, 0, i);
+
+         switch (GET_CODE (sub))
+           {
+           case USE:
+           case CLOBBER:
+             break;
+
+           case SET:
+             if (set)
+               return 0;
+             else
+               set = sub;
+             break;
+
+           default:
+             return 0;
+           }
+       }
+      return set;
+    }
+
+  return 0;
+}
+
+\f
+/* A C expression to modify the code described by the conditional if
+   information CE_INFO with the new PATTERN in INSN.  If PATTERN is a null
+   pointer after the IFCVT_MODIFY_INSN macro executes, it is assumed that that
+   insn cannot be converted to be executed conditionally.  */
+
+rtx
+frv_ifcvt_modify_insn (ce_info, pattern, insn)
+     ce_if_block_t *ce_info ATTRIBUTE_UNUSED;
+     rtx pattern;
+     rtx insn;
+{
+  rtx orig_ce_pattern = pattern;
+  rtx set;
+  rtx op0;
+  rtx op1;
+  rtx test;
+
+  if (GET_CODE (pattern) != COND_EXEC)
+    abort ();
+
+  test = COND_EXEC_TEST (pattern);
+  if (GET_CODE (test) == AND)
+    {
+      rtx cr = frv_ifcvt.cr_reg;
+      rtx test_reg;
+
+      op0 = XEXP (test, 0);
+      if (! rtx_equal_p (cr, XEXP (op0, 0)))
+       goto fail;
+
+      op1 = XEXP (test, 1);
+      test_reg = XEXP (op1, 0);
+      if (GET_CODE (test_reg) != REG)
+       goto fail;
+
+      /* Is this the first nested if block in this sequence?  If so, generate
+         an andcr or andncr.  */
+      if (! frv_ifcvt.last_nested_if_cr)
+       {
+         rtx and_op;
+
+         frv_ifcvt.last_nested_if_cr = test_reg;
+         if (GET_CODE (op0) == NE)
+           and_op = gen_andcr (test_reg, cr, test_reg);
+         else
+           and_op = gen_andncr (test_reg, cr, test_reg);
+
+         frv_ifcvt_add_insn (and_op, insn, TRUE);
+       }
+
+      /* If this isn't the first statement in the nested if sequence, see if we
+         are dealing with the same register.  */
+      else if (! rtx_equal_p (test_reg, frv_ifcvt.last_nested_if_cr))
+       goto fail;
+
+      COND_EXEC_TEST (pattern) = test = op1;
+    }
+
+  /* If this isn't a nested if, reset state variables.  */
+  else
+    {
+      frv_ifcvt.last_nested_if_cr = NULL_RTX;
+    }
+
+  set = single_set_pattern (pattern);
+  if (set)
+    {
+      rtx dest = SET_DEST (set);
+      rtx src = SET_SRC (set);
+      enum machine_mode mode = GET_MODE (dest);
+
+      /* Check for normal binary operators */
+      if (mode == SImode
+         && (GET_RTX_CLASS (GET_CODE (src)) == '2'
+             || GET_RTX_CLASS (GET_CODE (src)) == 'c'))
+       {
+         op0 = XEXP (src, 0);
+         op1 = XEXP (src, 1);
+
+         /* Special case load of small data address which looks like:
+            r16+symbol_ref */
+         if (GET_CODE (src) == PLUS && plus_small_data_p (op0, op1))
+           {
+             src = frv_ifcvt_load_value (src, insn);
+             if (src)
+               COND_EXEC_CODE (pattern) = gen_rtx_SET (VOIDmode, dest, src);
+             else
+               goto fail;
+           }
+
+         else if (integer_register_operand (op0, SImode) && CONSTANT_P (op1))
+           {
+             op1 = frv_ifcvt_load_value (op1, insn);
+             if (op1)
+               COND_EXEC_CODE (pattern)
+                 = gen_rtx_SET (VOIDmode, dest, gen_rtx_fmt_ee (GET_CODE (src),
+                                                                GET_MODE (src),
+                                                                op0, op1));
+             else
+               goto fail;
+           }
+       }
+
+      /* For multiply by a constant, we need to handle the sign extending
+         correctly.  Add a USE of the value after the multiply to prevent flow
+         from cratering because only one register out of the two were used.  */
+      else if (mode == DImode && GET_CODE (src) == MULT)
+       {
+         op0 = XEXP (src, 0);
+         op1 = XEXP (src, 1);
+         if (GET_CODE (op0) == SIGN_EXTEND && GET_CODE (op1) == CONST_INT)
+           {
+             op1 = frv_ifcvt_load_value (op1, insn);
+             if (op1)
+               {
+                 op1 = gen_rtx_SIGN_EXTEND (DImode, op1);
+                 COND_EXEC_CODE (pattern)
+                   = gen_rtx_SET (VOIDmode, dest,
+                                  gen_rtx_MULT (DImode, op0, op1));
+               }
+             else
+               goto fail;
+           }
+
+         frv_ifcvt_add_insn (gen_rtx_USE (VOIDmode, dest), insn, FALSE);
+       }
+
+      /* If we are just loading a constant created for a nested conditional
+         execution statement, just load the constant without any conditional
+         execution, since we know that the constant will not interfere with any
+         other registers.  */
+      else if (frv_ifcvt.scratch_insns_bitmap
+              && bitmap_bit_p (frv_ifcvt.scratch_insns_bitmap,
+                               INSN_UID (insn)))
+       pattern = set;
+
+      else if (mode == QImode || mode == HImode || mode == SImode
+              || mode == SFmode)
+       {
+         int changed_p = FALSE;
+
+         /* Check for just loading up a constant */
+         if (CONSTANT_P (src) && integer_register_operand (dest, mode))
+           {
+             src = frv_ifcvt_load_value (src, insn);
+             if (!src)
+               goto fail;
+
+             changed_p = TRUE;
+           }
+
+         /* See if we need to fix up stores */
+         if (GET_CODE (dest) == MEM)
+           {
+             rtx new_mem = frv_ifcvt_rewrite_mem (dest, mode, insn);
+
+             if (!new_mem)
+               goto fail;
+
+             else if (new_mem != dest)
+               {
+                 changed_p = TRUE;
+                 dest = new_mem;
+               }
+           }
+
+         /* See if we need to fix up loads */
+         if (GET_CODE (src) == MEM)
+           {
+             rtx new_mem = frv_ifcvt_rewrite_mem (src, mode, insn);
+
+             if (!new_mem)
+               goto fail;
+
+             else if (new_mem != src)
+               {
+                 changed_p = TRUE;
+                 src = new_mem;
+               }
+           }
+
+         /* If either src or destination changed, redo SET.  */
+         if (changed_p)
+           COND_EXEC_CODE (pattern) = gen_rtx_SET (VOIDmode, dest, src);
+       }
+
+      /* Rewrite a nested set cccr in terms of IF_THEN_ELSE.  Also deal with
+         rewriting the CC register to be the same as the paired CC/CR register
+         for nested ifs.  */
+      else if (mode == CC_CCRmode && GET_RTX_CLASS (GET_CODE (src)) == '<')
+       {
+         int regno = REGNO (XEXP (src, 0));
+         rtx if_else;
+
+         if (ce_info->pass > 1
+             && regno != (int)REGNO (frv_ifcvt.nested_cc_reg)
+             && TEST_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite, regno))
+           {
+             src = gen_rtx_fmt_ee (GET_CODE (src),
+                                   CC_CCRmode,
+                                   frv_ifcvt.nested_cc_reg,
+                                   XEXP (src, 1));
+           }
+
+         if_else = gen_rtx_IF_THEN_ELSE (CC_CCRmode, test, src, const0_rtx);
+         pattern = gen_rtx_SET (VOIDmode, dest, if_else);
+       }
+
+      /* Remap a nested compare instruction to use the paired CC/CR reg.  */
+      else if (ce_info->pass > 1
+              && GET_CODE (dest) == REG
+              && CC_P (REGNO (dest))
+              && REGNO (dest) != REGNO (frv_ifcvt.nested_cc_reg)
+              && TEST_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite,
+                                    REGNO (dest))
+              && GET_CODE (src) == COMPARE)
+       {
+         PUT_MODE (frv_ifcvt.nested_cc_reg, GET_MODE (dest));
+         COND_EXEC_CODE (pattern)
+           = gen_rtx_SET (VOIDmode, frv_ifcvt.nested_cc_reg, copy_rtx (src));
+       }
+    }
+
+  if (TARGET_DEBUG_COND_EXEC)
+    {
+      rtx orig_pattern = PATTERN (insn);
+
+      PATTERN (insn) = pattern;
+      fprintf (stderr,
+              "\n:::::::::: frv_ifcvt_modify_insn: pass = %d, insn after modification:\n",
+              ce_info->pass);
+
+      debug_rtx (insn);
+      PATTERN (insn) = orig_pattern;
+    }
+
+  return pattern;
+
+ fail:
+  if (TARGET_DEBUG_COND_EXEC)
+    {
+      rtx orig_pattern = PATTERN (insn);
+
+      PATTERN (insn) = orig_ce_pattern;
+      fprintf (stderr,
+              "\n:::::::::: frv_ifcvt_modify_insn: pass = %d, insn could not be modified:\n",
+              ce_info->pass);
+
+      debug_rtx (insn);
+      PATTERN (insn) = orig_pattern;
+    }
+
+  return NULL_RTX;
+}
+
+\f
+/* A C expression to perform any final machine dependent modifications in
+   converting code to conditional execution in the code described by the
+   conditional if information CE_INFO.  */
+
+void
+frv_ifcvt_modify_final (ce_info)
+     ce_if_block_t *ce_info ATTRIBUTE_UNUSED;
+{
+  rtx existing_insn;
+  rtx check_insn;
+  rtx p = frv_ifcvt.added_insns_list;
+  int i;
+
+  /* Loop inserting the check insns.  The last check insn is the first test,
+     and is the appropriate place to insert constants.  */
+  if (! p)
+    abort ();
+
+  do
+    {
+      rtx check_and_insert_insns = XEXP (p, 0);
+      rtx old_p = p;
+
+      check_insn = XEXP (check_and_insert_insns, 0);
+      existing_insn = XEXP (check_and_insert_insns, 1);
+      p = XEXP (p, 1);
+
+      /* The jump bit is used to say that the new insn is to be inserted BEFORE
+         the existing insn, otherwise it is to be inserted AFTER.  */
+      if (check_and_insert_insns->jump)
+       {
+         emit_insn_before (check_insn, existing_insn);
+         check_and_insert_insns->jump = 0;
+       }
+      else
+       emit_insn_after (check_insn, existing_insn);
+
+      free_EXPR_LIST_node (check_and_insert_insns);
+      free_EXPR_LIST_node (old_p);
+    }
+  while (p != NULL_RTX);
+
+  /* Load up any constants needed into temp gprs */
+  for (i = 0; i < frv_ifcvt.cur_scratch_regs; i++)
+    {
+      rtx insn = emit_insn_before (frv_ifcvt.scratch_regs[i], existing_insn);
+      if (! frv_ifcvt.scratch_insns_bitmap)
+       frv_ifcvt.scratch_insns_bitmap = BITMAP_XMALLOC ();
+      bitmap_set_bit (frv_ifcvt.scratch_insns_bitmap, INSN_UID (insn));
+      frv_ifcvt.scratch_regs[i] = NULL_RTX;
+    }
+
+  frv_ifcvt.added_insns_list = NULL_RTX;
+  frv_ifcvt.cur_scratch_regs = 0;
+}
+
+\f
+/* A C expression to cancel any machine dependent modifications in converting
+   code to conditional execution in the code described by the conditional if
+   information CE_INFO.  */
+
+void
+frv_ifcvt_modify_cancel (ce_info)
+     ce_if_block_t *ce_info ATTRIBUTE_UNUSED;
+{
+  int i;
+  rtx p = frv_ifcvt.added_insns_list;
+
+  /* Loop freeing up the EXPR_LIST's allocated.  */
+  while (p != NULL_RTX)
+    {
+      rtx check_and_jump = XEXP (p, 0);
+      rtx old_p = p;
+
+      p = XEXP (p, 1);
+      free_EXPR_LIST_node (check_and_jump);
+      free_EXPR_LIST_node (old_p);
+    }
+
+  /* Release any temporary gprs allocated.  */
+  for (i = 0; i < frv_ifcvt.cur_scratch_regs; i++)
+    frv_ifcvt.scratch_regs[i] = NULL_RTX;
+
+  frv_ifcvt.added_insns_list = NULL_RTX;
+  frv_ifcvt.cur_scratch_regs = 0;
+  return;
+}
+\f
+/* A C expression for the size in bytes of the trampoline, as an integer.
+   The template is:
+
+       setlo #0, <jmp_reg>
+       setlo #0, <static_chain>
+       sethi #0, <jmp_reg>
+       sethi #0, <static_chain>
+       jmpl @(gr0,<jmp_reg>) */
+
+int
+frv_trampoline_size ()
+{
+  return 5 /* instructions */ * 4 /* instruction size */;
+}
+
+\f
+/* A C statement to initialize the variable parts of a trampoline.  ADDR is an
+   RTX for the address of the trampoline; FNADDR is an RTX for the address of
+   the nested function; STATIC_CHAIN is an RTX for the static chain value that
+   should be passed to the function when it is called.
+
+   The template is:
+
+       setlo #0, <jmp_reg>
+       setlo #0, <static_chain>
+       sethi #0, <jmp_reg>
+       sethi #0, <static_chain>
+       jmpl @(gr0,<jmp_reg>) */
+
+void
+frv_initialize_trampoline (addr, fnaddr, static_chain)
+     rtx addr;
+     rtx fnaddr;
+     rtx static_chain;
+{
+  rtx sc_reg = force_reg (Pmode, static_chain);
+
+  emit_library_call (gen_rtx_SYMBOL_REF (SImode, "__trampoline_setup"),
+                    FALSE, VOIDmode, 4,
+                    addr, Pmode,
+                    GEN_INT (frv_trampoline_size ()), SImode,
+                    fnaddr, Pmode,
+                    sc_reg, Pmode);
+}
+
+\f
+/* Many machines have some registers that cannot be copied directly to or from
+   memory or even from other types of registers.  An example is the `MQ'
+   register, which on most machines, can only be copied to or from general
+   registers, but not memory.  Some machines allow copying all registers to and
+   from memory, but require a scratch register for stores to some memory
+   locations (e.g., those with symbolic address on the RT, and those with
+   certain symbolic address on the Sparc when compiling PIC).  In some cases,
+   both an intermediate and a scratch register are required.
+
+   You should define these macros to indicate to the reload phase that it may
+   need to allocate at least one register for a reload in addition to the
+   register to contain the data.  Specifically, if copying X to a register
+   CLASS in MODE requires an intermediate register, you should define
+   `SECONDARY_INPUT_RELOAD_CLASS' to return the largest register class all of
+   whose registers can be used as intermediate registers or scratch registers.
+
+   If copying a register CLASS in MODE to X requires an intermediate or scratch
+   register, `SECONDARY_OUTPUT_RELOAD_CLASS' should be defined to return the
+   largest register class required.  If the requirements for input and output
+   reloads are the same, the macro `SECONDARY_RELOAD_CLASS' should be used
+   instead of defining both macros identically.
+
+   The values returned by these macros are often `GENERAL_REGS'.  Return
+   `NO_REGS' if no spare register is needed; i.e., if X can be directly copied
+   to or from a register of CLASS in MODE without requiring a scratch register.
+   Do not define this macro if it would always return `NO_REGS'.
+
+   If a scratch register is required (either with or without an intermediate
+   register), you should define patterns for `reload_inM' or `reload_outM', as
+   required..  These patterns, which will normally be implemented with a
+   `define_expand', should be similar to the `movM' patterns, except that
+   operand 2 is the scratch register.
+
+   Define constraints for the reload register and scratch register that contain
+   a single register class.  If the original reload register (whose class is
+   CLASS) can meet the constraint given in the pattern, the value returned by
+   these macros is used for the class of the scratch register.  Otherwise, two
+   additional reload registers are required.  Their classes are obtained from
+   the constraints in the insn pattern.
+
+   X might be a pseudo-register or a `subreg' of a pseudo-register, which could
+   either be in a hard register or in memory.  Use `true_regnum' to find out;
+   it will return -1 if the pseudo is in memory and the hard register number if
+   it is in a register.
+
+   These macros should not be used in the case where a particular class of
+   registers can only be copied to memory and not to another class of
+   registers.  In that case, secondary reload registers are not needed and
+   would not be helpful.  Instead, a stack location must be used to perform the
+   copy and the `movM' pattern should use memory as a intermediate storage.
+   This case often occurs between floating-point and general registers.  */
+
+enum reg_class
+frv_secondary_reload_class (class, mode, x, in_p)
+     enum reg_class class;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     rtx x;
+     int in_p ATTRIBUTE_UNUSED;
+{
+  enum reg_class ret;
+
+  switch (class)
+    {
+    default:
+      ret = NO_REGS;
+      break;
+
+      /* Accumulators/Accumulator guard registers need to go through floating
+         point registers.  */
+    case QUAD_REGS:
+    case EVEN_REGS:
+    case GPR_REGS:
+      ret = NO_REGS;
+      if (x && GET_CODE (x) == REG)
+       {
+         int regno = REGNO (x);
+
+         if (ACC_P (regno) || ACCG_P (regno))
+           ret = FPR_REGS;
+       }
+      break;
+
+      /* Non-zero constants should be loaded into an FPR through a GPR.  */
+    case QUAD_FPR_REGS:
+    case FEVEN_REGS:
+    case FPR_REGS:
+      if (x && CONSTANT_P (x) && !ZERO_P (x))
+       ret = GPR_REGS;
+      else
+       ret = NO_REGS;
+      break;
+
+      /* All of these types need gpr registers.  */
+    case ICC_REGS:
+    case FCC_REGS:
+    case CC_REGS:
+    case ICR_REGS:
+    case FCR_REGS:
+    case CR_REGS:
+    case LCR_REG:
+    case LR_REG:
+      ret = GPR_REGS;
+      break;
+
+      /* The accumulators need fpr registers */
+    case ACC_REGS:
+    case EVEN_ACC_REGS:
+    case QUAD_ACC_REGS:
+    case ACCG_REGS:
+      ret = FPR_REGS;
+      break;
+    }
+
+  return ret;
+}
+
+\f
+/* A C expression whose value is nonzero if pseudos that have been assigned to
+   registers of class CLASS would likely be spilled because registers of CLASS
+   are needed for spill registers.
+
+   The default value of this macro returns 1 if CLASS has exactly one register
+   and zero otherwise.  On most machines, this default should be used.  Only
+   define this macro to some other expression if pseudo allocated by
+   `local-alloc.c' end up in memory because their hard registers were needed
+   for spill registers.  If this macro returns nonzero for those classes, those
+   pseudos will only be allocated by `global.c', which knows how to reallocate
+   the pseudo to another register.  If there would not be another register
+   available for reallocation, you should not change the definition of this
+   macro since the only effect of such a definition would be to slow down
+   register allocation.  */
+
+int
+frv_class_likely_spilled_p (class)
+     enum reg_class class;
+{
+  switch (class)
+    {
+    default:
+      break;
+
+    case ICC_REGS:
+    case FCC_REGS:
+    case CC_REGS:
+    case ICR_REGS:
+    case FCR_REGS:
+    case CR_REGS:
+    case LCR_REG:
+    case LR_REG:
+    case SPR_REGS:
+    case QUAD_ACC_REGS:
+    case EVEN_ACC_REGS:
+    case ACC_REGS:
+    case ACCG_REGS:
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+\f
+/* An expression for the alignment of a structure field FIELD if the
+   alignment computed in the usual way is COMPUTED.  GNU CC uses this
+   value instead of the value in `BIGGEST_ALIGNMENT' or
+   `BIGGEST_FIELD_ALIGNMENT', if defined, for structure fields only.  */
+
+/* The definition type of the bit field data is either char, short, long or
+   long long. The maximum bit size is the number of bits of its own type.
+
+   The bit field data is assigned to a storage unit that has an adequate size
+   for bit field data retention and is located at the smallest address.
+
+   Consecutive bit field data are packed at consecutive bits having the same
+   storage unit, with regard to the type, beginning with the MSB and continuing
+   toward the LSB.
+
+   If a field to be assigned lies over a bit field type boundary, its
+   assignment is completed by aligning it with a boundary suitable for the
+   type.
+
+   When a bit field having a bit length of 0 is declared, it is forcibly
+   assigned to the next storage unit.
+
+   e.g)
+       struct {
+               int     a:2;
+               int     b:6;
+               char    c:4;
+               int     d:10;
+               int      :0;
+               int     f:2;
+       } x;
+
+               +0        +1        +2        +3
+       &x      00000000  00000000  00000000  00000000
+               MLM----L
+               a    b
+       &x+4    00000000  00000000  00000000  00000000
+               M--L
+               c
+       &x+8    00000000  00000000  00000000  00000000
+               M----------L
+               d
+       &x+12   00000000  00000000  00000000  00000000
+               ML
+               f
+*/
+
+int
+frv_adjust_field_align (field, computed)
+     tree field;
+     int computed;
+{
+  /* C++ provides a null DECL_CONTEXT if the bit field is wider than its
+     type.  */
+  if (DECL_BIT_FIELD (field) && DECL_CONTEXT (field))
+    {
+      tree parent = DECL_CONTEXT (field);
+      tree prev = NULL_TREE;
+      tree cur;
+
+      /* Loop finding the previous field to the current one */
+      for (cur = TYPE_FIELDS (parent); cur && cur != field; cur = TREE_CHAIN (cur))
+       {
+         if (TREE_CODE (cur) != FIELD_DECL)
+           continue;
+
+         prev = cur;
+       }
+
+      if (!cur)
+       abort ();
+
+      /* If this isn't a :0 field and if the previous element is a bitfield
+        also, see if the type is different, if so, we will need to align the
+        bitfield to the next boundary */
+      if (prev
+         && ! DECL_PACKED (field)
+         && ! integer_zerop (DECL_SIZE (field))
+         && DECL_BIT_FIELD_TYPE (field) != DECL_BIT_FIELD_TYPE (prev))
+       {
+         int prev_align = TYPE_ALIGN (TREE_TYPE (prev));
+         int cur_align  = TYPE_ALIGN (TREE_TYPE (field));
+         computed = (prev_align > cur_align) ? prev_align : cur_align;
+       }
+    }
+
+  return computed;
+}
+
+\f
+/* A C expression that is nonzero if it is permissible to store a value of mode
+   MODE in hard register number REGNO (or in several registers starting with
+   that one).  For a machine where all registers are equivalent, a suitable
+   definition is
+
+        #define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+
+   It is not necessary for this macro to check for the numbers of fixed
+   registers, because the allocation mechanism considers them to be always
+   occupied.
+
+   On some machines, double-precision values must be kept in even/odd register
+   pairs.  The way to implement that is to define this macro to reject odd
+   register numbers for such modes.
+
+   The minimum requirement for a mode to be OK in a register is that the
+   `movMODE' instruction pattern support moves between the register and any
+   other hard register for which the mode is OK; and that moving a value into
+   the register and back out not alter it.
+
+   Since the same instruction used to move `SImode' will work for all narrower
+   integer modes, it is not necessary on any machine for `HARD_REGNO_MODE_OK'
+   to distinguish between these modes, provided you define patterns `movhi',
+   etc., to take advantage of this.  This is useful because of the interaction
+   between `HARD_REGNO_MODE_OK' and `MODES_TIEABLE_P'; it is very desirable for
+   all integer modes to be tieable.
+
+   Many machines have special registers for floating point arithmetic.  Often
+   people assume that floating point machine modes are allowed only in floating
+   point registers.  This is not true.  Any registers that can hold integers
+   can safely *hold* a floating point machine mode, whether or not floating
+   arithmetic can be done on it in those registers.  Integer move instructions
+   can be used to move the values.
+
+   On some machines, though, the converse is true: fixed-point machine modes
+   may not go in floating registers.  This is true if the floating registers
+   normalize any value stored in them, because storing a non-floating value
+   there would garble it.  In this case, `HARD_REGNO_MODE_OK' should reject
+   fixed-point machine modes in floating registers.  But if the floating
+   registers do not automatically normalize, if you can store any bit pattern
+   in one and retrieve it unchanged without a trap, then any machine mode may
+   go in a floating register, so you can define this macro to say so.
+
+   The primary significance of special floating registers is rather that they
+   are the registers acceptable in floating point arithmetic instructions.
+   However, this is of no concern to `HARD_REGNO_MODE_OK'.  You handle it by
+   writing the proper constraints for those instructions.
+
+   On some machines, the floating registers are especially slow to access, so
+   that it is better to store a value in a stack frame than in such a register
+   if floating point arithmetic is not being done.  As long as the floating
+   registers are not in class `GENERAL_REGS', they will not be used unless some
+   pattern's constraint asks for one.  */
+
+int
+frv_hard_regno_mode_ok (regno, mode)
+     int regno;
+     enum machine_mode mode;
+{
+  int base;
+  int mask;
+
+  switch (mode)
+    {
+    case CCmode:
+    case CC_UNSmode:
+      return ICC_P (regno) || GPR_P (regno);
+
+    case CC_CCRmode:
+      return CR_P (regno) || GPR_P (regno);
+
+    case CC_FPmode:
+      return FCC_P (regno) || GPR_P (regno);
+
+    default:
+      break;
+    }
+
+  /* Set BASE to the first register in REGNO's class.  Set MASK to the
+     bits that must be clear in (REGNO - BASE) for the register to be
+     well-aligned.  */
+  if (INTEGRAL_MODE_P (mode) || FLOAT_MODE_P (mode) || VECTOR_MODE_P (mode))
+    {
+      if (ACCG_P (regno))
+       {
+         /* ACCGs store one byte.  Two-byte quantities must start in
+            even-numbered registers, four-byte ones in registers whose
+            numbers are divisible by four, and so on.  */
+         base = ACCG_FIRST;
+         mask = GET_MODE_SIZE (mode) - 1;
+       }
+      else
+       {
+         /* The other registers store one word.  */
+         if (GPR_P (regno))
+           base = GPR_FIRST;
+
+         else if (FPR_P (regno))
+           base = FPR_FIRST;
+
+         else if (ACC_P (regno))
+           base = ACC_FIRST;
+
+         else
+           return 0;
+
+         /* Anything smaller than an SI is OK in any word-sized register.  */
+         if (GET_MODE_SIZE (mode) < 4)
+           return 1;
+
+         mask = (GET_MODE_SIZE (mode) / 4) - 1;
+       }
+      return (((regno - base) & mask) == 0);
+    }
+
+  return 0;
+}
+
+\f
+/* A C expression for the number of consecutive hard registers, starting at
+   register number REGNO, required to hold a value of mode MODE.
+
+   On a machine where all registers are exactly one word, a suitable definition
+   of this macro is
+
+        #define HARD_REGNO_NREGS(REGNO, MODE)            \
+           ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1)  \
+            / UNITS_PER_WORD))  */
+
+/* On the FRV, make the CC_FP mode take 3 words in the integer registers, so
+   that we can build the appropriate instructions to properly reload the
+   values.  Also, make the byte-sized accumulator guards use one guard
+   for each byte.  */
+
+int
+frv_hard_regno_nregs (regno, mode)
+     int regno;
+     enum machine_mode mode;
+{
+  if (ACCG_P (regno))
+    return GET_MODE_SIZE (mode);
+  else
+    return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+}
+
+\f
+/* A C expression for the maximum number of consecutive registers of
+   class CLASS needed to hold a value of mode MODE.
+
+   This is closely related to the macro `HARD_REGNO_NREGS'.  In fact, the value
+   of the macro `CLASS_MAX_NREGS (CLASS, MODE)' should be the maximum value of
+   `HARD_REGNO_NREGS (REGNO, MODE)' for all REGNO values in the class CLASS.
+
+   This macro helps control the handling of multiple-word values in
+   the reload pass.
+
+   This declaration is required.  */
+
+int
+frv_class_max_nregs (class, mode)
+     enum reg_class class;
+     enum machine_mode mode;
+{
+  if (class == ACCG_REGS)
+    /* An N-byte value requires N accumulator guards.  */
+    return GET_MODE_SIZE (mode);
+  else
+    return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+}
+
+\f
+/* A C expression that is nonzero if X is a legitimate constant for an
+   immediate operand on the target machine.  You can assume that X satisfies
+   `CONSTANT_P', so you need not check this.  In fact, `1' is a suitable
+   definition for this macro on machines where anything `CONSTANT_P' is valid.  */
+
+int
+frv_legitimate_constant_p (x)
+     rtx x;
+{
+  enum machine_mode mode = GET_MODE (x);
+
+  /* All of the integer constants are ok */
+  if (GET_CODE (x) != CONST_DOUBLE)
+    return TRUE;
+
+  /* double integer constants are ok */
+  if (mode == VOIDmode || mode == DImode)
+    return TRUE;
+
+  /* 0 is always ok */
+  if (x == CONST0_RTX (mode))
+    return TRUE;
+
+  /* If floating point is just emulated, allow any constant, since it will be
+     constructed in the GPRs */
+  if (!TARGET_HAS_FPRS)
+    return TRUE;
+
+  if (mode == DFmode && !TARGET_DOUBLE)
+    return TRUE;
+
+  /* Otherwise store the constant away and do a load.  */
+  return FALSE;
+}
+\f
+/* A C expression for the cost of moving data from a register in class FROM to
+   one in class TO.  The classes are expressed using the enumeration values
+   such as `GENERAL_REGS'.  A value of 4 is the default; other values are
+   interpreted relative to that.
+
+   It is not required that the cost always equal 2 when FROM is the same as TO;
+   on some machines it is expensive to move between registers if they are not
+   general registers.
+
+   If reload sees an insn consisting of a single `set' between two hard
+   registers, and if `REGISTER_MOVE_COST' applied to their classes returns a
+   value of 2, reload does not check to ensure that the constraints of the insn
+   are met.  Setting a cost of other than 2 will allow reload to verify that
+   the constraints are met.  You should do this if the `movM' pattern's
+   constraints do not allow such copying.  */
+
+#define HIGH_COST 40
+#define MEDIUM_COST 3
+#define LOW_COST 1
+
+int
+frv_register_move_cost (from, to)
+     enum reg_class from;
+     enum reg_class to;
+{
+  switch (from)
+    {
+    default:
+      break;
+
+    case QUAD_REGS:
+    case EVEN_REGS:
+    case GPR_REGS:
+      switch (to)
+       {
+       default:
+         break;
+
+       case QUAD_REGS:
+       case EVEN_REGS:
+       case GPR_REGS:
+         return LOW_COST;
+
+       case FEVEN_REGS:
+       case FPR_REGS:
+         return LOW_COST;
+
+       case LCR_REG:
+       case LR_REG:
+       case SPR_REGS:
+         return LOW_COST;
+       }
+
+    case FEVEN_REGS:
+    case FPR_REGS:
+      switch (to)
+       {
+       default:
+         break;
+
+       case QUAD_REGS:
+       case EVEN_REGS:
+       case GPR_REGS:
+       case ACC_REGS:
+       case EVEN_ACC_REGS:
+       case QUAD_ACC_REGS:
+       case ACCG_REGS:
+         return MEDIUM_COST;
+
+       case FEVEN_REGS:
+       case FPR_REGS:
+         return LOW_COST;
+       }
+
+    case LCR_REG:
+    case LR_REG:
+    case SPR_REGS:
+      switch (to)
+       {
+       default:
+         break;
+
+       case QUAD_REGS:
+       case EVEN_REGS:
+       case GPR_REGS:
+         return MEDIUM_COST;
+       }
+
+    case ACC_REGS:
+    case EVEN_ACC_REGS:
+    case QUAD_ACC_REGS:
+    case ACCG_REGS:
+      switch (to)
+       {
+       default:
+         break;
+
+       case FEVEN_REGS:
+       case FPR_REGS:
+         return MEDIUM_COST;
+
+       }
+    }
+
+  return HIGH_COST;
+}
+\f
+/* Implementation of TARGET_ASM_INTEGER.  In the FRV case we need to
+   use ".picptr" to generate safe relocations for PIC code.  We also
+   need a fixup entry for aligned (non-debugging) code.  */
+
+static bool
+frv_assemble_integer (value, size, aligned_p)
+     rtx value;
+     unsigned int size;
+     int aligned_p;
+{
+  if (flag_pic && size == UNITS_PER_WORD)
+    {
+      if (GET_CODE (value) == CONST
+         || GET_CODE (value) == SYMBOL_REF
+         || GET_CODE (value) == LABEL_REF)
+       {
+         if (aligned_p)
+           {
+             static int label_num = 0;
+             char buf[256];
+             const char *p;
+
+             ASM_GENERATE_INTERNAL_LABEL (buf, "LCP", label_num++);
+             STRIP_NAME_ENCODING (p, buf);
+
+             fprintf (asm_out_file, "%s:\n", p);
+             fprintf (asm_out_file, "%s\n", FIXUP_SECTION_ASM_OP);
+             fprintf (asm_out_file, "\t.picptr\t%s\n", p);
+             fprintf (asm_out_file, "\t.previous\n");
+           }
+         assemble_integer_with_op ("\t.picptr\t", value);
+         return true;
+       }
+      if (!aligned_p)
+       {
+         /* We've set the unaligned SI op to NULL, so we always have to
+            handle the unaligned case here.  */
+         assemble_integer_with_op ("\t.4byte\t", value);
+         return true;
+       }
+    }
+  return default_assemble_integer (value, size, aligned_p);
+}
+
+/* Function to set up the backend function structure.  */
+
+static struct machine_function *
+frv_init_machine_status ()
+{
+  return ggc_alloc_cleared (sizeof (struct machine_function));
+}
+
+\f
+/* Update the register state information, to know about which registers are set
+   or clobbered.  */
+
+static void
+frv_registers_update (x, reg_state, modified, p_num_mod, flag)
+     rtx x;
+     unsigned char reg_state[];
+     int modified[];
+     int *p_num_mod;
+     int flag;
+{
+  int regno, reg_max;
+  rtx reg;
+  rtx cond;
+  const char *format;
+  int length;
+  int j;
+
+  switch (GET_CODE (x))
+    {
+    default:
+      break;
+
+      /* Clobber just modifies a register, it doesn't make it live.  */
+    case CLOBBER:
+      frv_registers_update (XEXP (x, 0), reg_state, modified, p_num_mod,
+                           flag | REGSTATE_MODIFIED);
+      return;
+
+      /* Pre modify updates the first argument, just references the second.  */
+    case PRE_MODIFY:
+    case SET:
+      frv_registers_update (XEXP (x, 0), reg_state, modified, p_num_mod,
+                           flag | REGSTATE_MODIFIED | REGSTATE_LIVE);
+      frv_registers_update (XEXP (x, 1), reg_state, modified, p_num_mod, flag);
+      return;
+
+      /* For COND_EXEC, pass the appropriate flag to evaluate the conditional
+         statement, but just to be sure, make sure it is the type of cond_exec
+         we expect.  */
+    case COND_EXEC:
+      cond = XEXP (x, 0);
+      if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
+         && GET_CODE (XEXP (cond, 0)) == REG
+         && CR_P (REGNO (XEXP (cond, 0)))
+         && GET_CODE (XEXP (cond, 1)) == CONST_INT
+         && INTVAL (XEXP (cond, 1)) == 0
+         && (flag & (REGSTATE_MODIFIED | REGSTATE_IF_EITHER)) == 0)
+       {
+         frv_registers_update (cond, reg_state, modified, p_num_mod, flag);
+         flag |= ((REGNO (XEXP (cond, 0)) - CR_FIRST)
+                  | ((GET_CODE (cond) == NE)
+                     ? REGSTATE_IF_TRUE
+                     : REGSTATE_IF_FALSE));
+
+         frv_registers_update (XEXP (x, 1), reg_state, modified, p_num_mod,
+                               flag);
+         return;
+       }
+      else
+       fatal_insn ("frv_registers_update", x);
+
+      /* MEM resets the modification bits.  */
+    case MEM:
+      flag &= ~REGSTATE_MODIFIED;
+      break;
+
+      /* See if we need to set the modified flag.  */
+    case SUBREG:
+      reg = SUBREG_REG (x);
+      if (GET_CODE (reg) == REG)
+       {
+         regno = subreg_regno (x);
+         reg_max = REGNO (reg) + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+         goto reg_common;
+       }
+      break;
+
+    case REG:
+      regno = REGNO (x);
+      reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+      /* fall through */
+
+    reg_common:
+      if (flag & REGSTATE_MODIFIED)
+       {
+         flag &= REGSTATE_MASK;
+         while (regno < reg_max)
+           {
+             int rs = reg_state[regno];
+
+             if (flag != rs)
+               {
+                 if ((rs & REGSTATE_MODIFIED) == 0)
+                   {
+                     modified[ *p_num_mod ] = regno;
+                     (*p_num_mod)++;
+                   }
+
+                 /* If the previous register state had the register as
+                     modified, possibly in some conditional execution context,
+                     and the current insn modifies in some other context, or
+                     outside of conditional execution, just mark the variable
+                     as modified.  */
+                 else
+                   flag &= ~(REGSTATE_IF_EITHER | REGSTATE_CC_MASK);
+
+                 reg_state[regno] = (rs | flag);
+               }
+             regno++;
+           }
+       }
+      return;
+    }
+
+
+  length = GET_RTX_LENGTH (GET_CODE (x));
+  format = GET_RTX_FORMAT (GET_CODE (x));
+
+  for (j = 0; j < length; ++j)
+    {
+      switch (format[j])
+       {
+       case 'e':
+         frv_registers_update (XEXP (x, j), reg_state, modified, p_num_mod,
+                               flag);
+         break;
+
+       case 'V':
+       case 'E':
+         if (XVEC (x, j) != 0)
+           {
+             int k;
+             for (k = 0; k < XVECLEN (x, j); ++k)
+               frv_registers_update (XVECEXP (x, j, k), reg_state, modified,
+                                     p_num_mod, flag);
+           }
+         break;
+
+       default:
+         /* Nothing to do.  */
+         break;
+       }
+    }
+
+  return;
+}
+
+\f
+/* Return if any registers in a hard register set were used an insn.  */
+
+static int
+frv_registers_used_p (x, reg_state, flag)
+     rtx x;
+     unsigned char reg_state[];
+     int flag;
+{
+  int regno, reg_max;
+  rtx reg;
+  rtx cond;
+  rtx dest;
+  const char *format;
+  int result;
+  int length;
+  int j;
+
+  switch (GET_CODE (x))
+    {
+    default:
+      break;
+
+      /* Skip clobber, that doesn't use the previous value */
+    case CLOBBER:
+      return FALSE;
+
+      /* For SET, if a conditional jump has occurred in the same insn, only
+        allow a set of a CR register if that register is not currently live.
+        This is because on the FR-V, B0/B1 instructions are always last.
+        Otherwise, don't look at the result, except within a MEM, but do look
+        at the source.  */
+    case SET:
+      dest = SET_DEST (x);
+      if (flag & REGSTATE_CONDJUMP
+         && GET_CODE (dest) == REG && CR_P (REGNO (dest))
+         && (reg_state[ REGNO (dest) ] & REGSTATE_LIVE) != 0)
+       return TRUE;
+
+      if (GET_CODE (dest) == MEM)
+       {
+         result = frv_registers_used_p (XEXP (dest, 0), reg_state, flag);
+         if (result)
+           return result;
+       }
+
+      return frv_registers_used_p (SET_SRC (x), reg_state, flag);
+
+      /* For COND_EXEC, pass the appropriate flag to evaluate the conditional
+         statement, but just to be sure, make sure it is the type of cond_exec
+         we expect.  */
+    case COND_EXEC:
+      cond = XEXP (x, 0);
+      if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
+         && GET_CODE (XEXP (cond, 0)) == REG
+         && CR_P (REGNO (XEXP (cond, 0)))
+         && GET_CODE (XEXP (cond, 1)) == CONST_INT
+         && INTVAL (XEXP (cond, 1)) == 0
+         && (flag & (REGSTATE_MODIFIED | REGSTATE_IF_EITHER)) == 0)
+       {
+         result = frv_registers_used_p (cond, reg_state, flag);
+         if (result)
+           return result;
+
+         flag |= ((REGNO (XEXP (cond, 0)) - CR_FIRST)
+                  | ((GET_CODE (cond) == NE)
+                     ? REGSTATE_IF_TRUE
+                     : REGSTATE_IF_FALSE));
+
+         return frv_registers_used_p (XEXP (x, 1), reg_state, flag);
+       }
+      else
+       fatal_insn ("frv_registers_used_p", x);
+
+      /* See if a register or subreg was modified in the same VLIW insn.  */
+    case SUBREG:
+      reg = SUBREG_REG (x);
+      if (GET_CODE (reg) == REG)
+       {
+         regno = subreg_regno (x);
+         reg_max = REGNO (reg) + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+         goto reg_common;
+       }
+      break;
+
+    case REG:
+      regno = REGNO (x);
+      reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+      /* fall through */
+
+    reg_common:
+      while (regno < reg_max)
+       {
+         int rs = reg_state[regno];
+
+         if (rs & REGSTATE_MODIFIED)
+           {
+             int rs_if = rs & REGSTATE_IF_EITHER;
+             int flag_if = flag & REGSTATE_IF_EITHER;
+
+             /* Simple modification, no conditional execution */
+             if ((rs & REGSTATE_IF_EITHER) == 0)
+               return TRUE;
+
+             /* See if the variable is only modified in a conditional
+                execution expression opposite to the conditional execution
+                expression that governs this expression (ie, true vs. false
+                for the same CC register).  If this isn't two halves of the
+                same conditional expression, consider the register
+                modified. */
+             if (((rs_if == REGSTATE_IF_TRUE && flag_if == REGSTATE_IF_FALSE)
+                  || (rs_if == REGSTATE_IF_FALSE && flag_if == REGSTATE_IF_TRUE))
+                 && ((rs & REGSTATE_CC_MASK) == (flag & REGSTATE_CC_MASK)))
+               ;
+             else
+               return TRUE;
+           }
+
+         regno++;
+       }
+      return FALSE;
+    }
+
+
+  length = GET_RTX_LENGTH (GET_CODE (x));
+  format = GET_RTX_FORMAT (GET_CODE (x));
+
+  for (j = 0; j < length; ++j)
+    {
+      switch (format[j])
+       {
+       case 'e':
+         result = frv_registers_used_p (XEXP (x, j), reg_state, flag);
+         if (result != 0)
+           return result;
+         break;
+
+       case 'V':
+       case 'E':
+         if (XVEC (x, j) != 0)
+           {
+             int k;
+             for (k = 0; k < XVECLEN (x, j); ++k)
+               {
+                 result = frv_registers_used_p (XVECEXP (x, j, k), reg_state,
+                                                flag);
+                 if (result != 0)
+                   return result;
+               }
+           }
+         break;
+
+       default:
+         /* Nothing to do.  */
+         break;
+       }
+    }
+
+  return 0;
+}
+
+/* Return if any registers in a hard register set were set in an insn.  */
+
+static int
+frv_registers_set_p (x, reg_state, modify_p)
+     rtx x;
+     unsigned char reg_state[];
+     int modify_p;
+{
+  int regno, reg_max;
+  rtx reg;
+  rtx cond;
+  const char *format;
+  int length;
+  int j;
+
+  switch (GET_CODE (x))
+    {
+    default:
+      break;
+
+    case CLOBBER:
+      return frv_registers_set_p (XEXP (x, 0), reg_state, TRUE);
+
+    case PRE_MODIFY:
+    case SET:
+      return (frv_registers_set_p (XEXP (x, 0), reg_state, TRUE)
+             || frv_registers_set_p (XEXP (x, 1), reg_state, FALSE));
+
+    case COND_EXEC:
+      cond = XEXP (x, 0);
+      /* just to be sure, make sure it is the type of cond_exec we
+         expect.  */
+      if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
+         && GET_CODE (XEXP (cond, 0)) == REG
+         && CR_P (REGNO (XEXP (cond, 0)))
+         && GET_CODE (XEXP (cond, 1)) == CONST_INT
+         && INTVAL (XEXP (cond, 1)) == 0
+         && !modify_p)
+       return frv_registers_set_p (XEXP (x, 1), reg_state, modify_p);
+      else
+       fatal_insn ("frv_registers_set_p", x);
+
+      /* MEM resets the modification bits.  */
+    case MEM:
+      modify_p = FALSE;
+      break;
+
+      /* See if we need to set the modified modify_p.  */
+    case SUBREG:
+      reg = SUBREG_REG (x);
+      if (GET_CODE (reg) == REG)
+       {
+         regno = subreg_regno (x);
+         reg_max = REGNO (reg) + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+         goto reg_common;
+       }
+      break;
+
+    case REG:
+      regno = REGNO (x);
+      reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+      /* fall through */
+
+    reg_common:
+      if (modify_p)
+       while (regno < reg_max)
+         {
+           int rs = reg_state[regno];
+
+           if (rs & REGSTATE_MODIFIED)
+             return TRUE;
+           regno++;
+         }
+      return FALSE;
+    }
+
+
+  length = GET_RTX_LENGTH (GET_CODE (x));
+  format = GET_RTX_FORMAT (GET_CODE (x));
+
+  for (j = 0; j < length; ++j)
+    {
+      switch (format[j])
+       {
+       case 'e':
+         if (frv_registers_set_p (XEXP (x, j), reg_state, modify_p))
+           return TRUE;
+         break;
+
+       case 'V':
+       case 'E':
+         if (XVEC (x, j) != 0)
+           {
+             int k;
+             for (k = 0; k < XVECLEN (x, j); ++k)
+               if (frv_registers_set_p (XVECEXP (x, j, k), reg_state,
+                                        modify_p))
+                 return TRUE;
+           }
+         break;
+
+       default:
+         /* Nothing to do.  */
+         break;
+       }
+    }
+
+  return FALSE;
+}
+
+\f
+/* In rare cases, correct code generation requires extra machine dependent
+   processing between the second jump optimization pass and delayed branch
+   scheduling.  On those machines, define this macro as a C statement to act on
+   the code starting at INSN.  */
+
+/* On the FR-V, this pass is used to rescan the insn chain, and pack
+   conditional branches/calls/jumps, etc. with previous insns where it can.  It
+   does not reorder the instructions.  We assume the scheduler left the flow
+   information in a reasonable state.  */
+
+static void
+frv_pack_insns ()
+{
+  state_t frv_state;                   /* frv state machine */
+  int cur_start_vliw_p;                        /* current insn starts a VLIW insn */
+  int next_start_vliw_p;               /* next insn starts a VLIW insn */
+  int cur_condjump_p;                  /* flag if current insn is a cond jump*/
+  int next_condjump_p;                 /* flag if next insn is a cond jump */
+  rtx insn;
+  rtx link;
+  int j;
+  int num_mod = 0;                     /* # of modified registers */
+  int modified[FIRST_PSEUDO_REGISTER]; /* registers modified in current VLIW */
+                                       /* register state information */
+  unsigned char reg_state[FIRST_PSEUDO_REGISTER];
+
+  /* If we weren't going to pack the insns, don't bother with this pass.  */
+  if (!optimize || !flag_schedule_insns_after_reload || TARGET_NO_VLIW_BRANCH)
+    return;
+
+  switch (frv_cpu_type)
+    {
+    default:
+    case FRV_CPU_FR300:                /* FR300/simple are single issue */
+    case FRV_CPU_SIMPLE:
+      return;
+
+    case FRV_CPU_GENERIC:      /* FR-V and FR500 are multi-issue */
+    case FRV_CPU_FR400:
+    case FRV_CPU_FR500:
+    case FRV_CPU_TOMCAT:
+      break;
+    }
+
+  /* Set up the instruction and register states.  */
+  dfa_start ();
+  frv_state = (state_t) xmalloc (state_size ());
+  memset ((PTR) reg_state, REGSTATE_DEAD, sizeof (reg_state));
+
+  /* Go through the insns, and repack the insns.  */
+  state_reset (frv_state);
+  cur_start_vliw_p = FALSE;
+  next_start_vliw_p = TRUE;
+  cur_condjump_p = 0;
+  next_condjump_p = 0;
+
+  for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn))
+    {
+      enum rtx_code code = GET_CODE (insn);
+      enum rtx_code pattern_code;
+
+      /* For basic block begin notes redo the live information, and skip other
+         notes.  */
+      if (code == NOTE)
+       {
+         if (NOTE_LINE_NUMBER (insn) == (int)NOTE_INSN_BASIC_BLOCK)
+           {
+             regset live;
+
+             for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+               reg_state[j] &= ~ REGSTATE_LIVE;
+
+             live = NOTE_BASIC_BLOCK (insn)->global_live_at_start;
+             EXECUTE_IF_SET_IN_REG_SET(live, 0, j,
+                                       {
+                                         reg_state[j] |= REGSTATE_LIVE;
+                                       });
+           }
+
+         continue;
+       }
+
+      /* things like labels reset everything.  */
+      if (GET_RTX_CLASS (code) != 'i')
+       {
+         next_start_vliw_p = TRUE;
+         continue;
+       }
+
+      /* Clear the VLIW start flag on random USE and CLOBBER insns, which is
+         set on the USE insn that preceeds the return, and potentially on
+         CLOBBERs for setting multiword variables.  Also skip the ADDR_VEC
+         holding the case table labels.  */
+      pattern_code = GET_CODE (PATTERN (insn));
+      if (pattern_code == USE || pattern_code == CLOBBER
+         || pattern_code == ADDR_VEC || pattern_code == ADDR_DIFF_VEC)
+       {
+         CLEAR_VLIW_START (insn);
+         continue;
+       }
+
+      cur_start_vliw_p = next_start_vliw_p;
+      next_start_vliw_p = FALSE;
+
+      cur_condjump_p |= next_condjump_p;
+      next_condjump_p = 0;
+
+      /* Unconditional branches and calls end the current VLIW insn.  */
+      if (code == CALL_INSN)
+       {
+         next_start_vliw_p = TRUE;
+
+         /* On a TOMCAT, calls must be alone in the VLIW insns.  */
+         if (frv_cpu_type == FRV_CPU_TOMCAT)
+           cur_start_vliw_p = TRUE;
+       }
+      else if (code == JUMP_INSN)
+       {
+         if (any_condjump_p (insn))
+           next_condjump_p = REGSTATE_CONDJUMP;
+         else
+           next_start_vliw_p = TRUE;
+       }
+
+      /* Only allow setting a CCR register after a conditional branch.  */
+      else if (((cur_condjump_p & REGSTATE_CONDJUMP) != 0)
+              && get_attr_type (insn) != TYPE_CCR)
+       cur_start_vliw_p = TRUE;
+
+      /* Determine if we need to start a new VLIW instruction.  */
+      if (cur_start_vliw_p
+         /* Do not check for register conflicts in a setlo instruction
+            because any output or true dependencies will be with the
+            partnering sethi instruction, with which it can be packed.
+
+            Although output dependencies are rare they are still
+            possible.  So check output dependencies in VLIW insn. */
+         || (get_attr_type (insn) != TYPE_SETLO
+             && (frv_registers_used_p (PATTERN (insn),
+                                       reg_state,
+                                       cur_condjump_p)
+                 || frv_registers_set_p (PATTERN (insn), reg_state, FALSE)))
+         || state_transition (frv_state, insn) >= 0)
+       {
+         SET_VLIW_START (insn);
+         state_reset (frv_state);
+         state_transition (frv_state, insn);
+         cur_condjump_p = 0;
+
+         /* Update the modified registers.  */
+         for (j = 0; j < num_mod; j++)
+           reg_state[ modified[j] ] &= ~(REGSTATE_CC_MASK
+                                         | REGSTATE_IF_EITHER
+                                         | REGSTATE_MODIFIED);
+
+         num_mod = 0;
+       }
+      else
+       CLEAR_VLIW_START (insn);
+
+      /* Record which registers are modified.  */
+      frv_registers_update (PATTERN (insn), reg_state, modified, &num_mod, 0);
+
+      /* Process the death notices */
+      for (link = REG_NOTES (insn);
+          link != NULL_RTX;
+          link = XEXP (link, 1))
+       {
+         rtx reg = XEXP (link, 0);
+
+         if (REG_NOTE_KIND (link) == REG_DEAD && GET_CODE (reg) == REG)
+           {
+             int regno = REGNO (reg);
+             int n = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+             for (; regno < n; regno++)
+               reg_state[regno] &= ~REGSTATE_LIVE;
+           }
+       }
+    }
+
+  free ((PTR) frv_state);
+  dfa_finish ();
+  return;
+}
+
+\f
+#define def_builtin(name, type, code) \
+  builtin_function ((name), (type), (code), BUILT_IN_MD, NULL, NULL)
+
+struct builtin_description
+{
+  enum insn_code icode;
+  const char *name;
+  enum frv_builtins code;
+  enum rtx_code comparison;
+  unsigned int flag;
+};
+
+/* Media intrinsics that take a single, constant argument.  */
+
+static struct builtin_description bdesc_set[] =
+{
+  { CODE_FOR_mhdsets, "__MHDSETS", FRV_BUILTIN_MHDSETS, 0, 0 }
+};
+
+/* Media intrinsics that take just one argument. */
+
+static struct builtin_description bdesc_1arg[] =
+{
+  { CODE_FOR_mnot, "__MNOT", FRV_BUILTIN_MNOT, 0, 0 },
+  { CODE_FOR_munpackh, "__MUNPACKH", FRV_BUILTIN_MUNPACKH, 0, 0 },
+  { CODE_FOR_mbtoh, "__MBTOH", FRV_BUILTIN_MBTOH, 0, 0 },
+  { CODE_FOR_mhtob, "__MHTOB", FRV_BUILTIN_MHTOB, 0, 0 },
+  { CODE_FOR_mabshs, "__MABSHS", FRV_BUILTIN_MABSHS, 0, 0 }
+};
+
+/* Media intrinsics that take two arguments. */
+
+static struct builtin_description bdesc_2arg[] =
+{
+  { CODE_FOR_mand, "__MAND", FRV_BUILTIN_MAND, 0, 0 },
+  { CODE_FOR_mor, "__MOR", FRV_BUILTIN_MOR, 0, 0 },
+  { CODE_FOR_mxor, "__MXOR", FRV_BUILTIN_MXOR, 0, 0 },
+  { CODE_FOR_maveh, "__MAVEH", FRV_BUILTIN_MAVEH, 0, 0 },
+  { CODE_FOR_msaths, "__MSATHS", FRV_BUILTIN_MSATHS, 0, 0 },
+  { CODE_FOR_msathu, "__MSATHU", FRV_BUILTIN_MSATHU, 0, 0 },
+  { CODE_FOR_maddhss, "__MADDHSS", FRV_BUILTIN_MADDHSS, 0, 0 },
+  { CODE_FOR_maddhus, "__MADDHUS", FRV_BUILTIN_MADDHUS, 0, 0 },
+  { CODE_FOR_msubhss, "__MSUBHSS", FRV_BUILTIN_MSUBHSS, 0, 0 },
+  { CODE_FOR_msubhus, "__MSUBHUS", FRV_BUILTIN_MSUBHUS, 0, 0 },
+  { CODE_FOR_mqaddhss, "__MQADDHSS", FRV_BUILTIN_MQADDHSS, 0, 0 },
+  { CODE_FOR_mqaddhus, "__MQADDHUS", FRV_BUILTIN_MQADDHUS, 0, 0 },
+  { CODE_FOR_mqsubhss, "__MQSUBHSS", FRV_BUILTIN_MQSUBHSS, 0, 0 },
+  { CODE_FOR_mqsubhus, "__MQSUBHUS", FRV_BUILTIN_MQSUBHUS, 0, 0 },
+  { CODE_FOR_mpackh, "__MPACKH", FRV_BUILTIN_MPACKH, 0, 0 },
+  { CODE_FOR_mdpackh, "__MDPACKH", FRV_BUILTIN_MDPACKH, 0, 0 },
+  { CODE_FOR_mcop1, "__Mcop1", FRV_BUILTIN_MCOP1, 0, 0 },
+  { CODE_FOR_mcop2, "__Mcop2", FRV_BUILTIN_MCOP2, 0, 0 },
+  { CODE_FOR_mwcut, "__MWCUT", FRV_BUILTIN_MWCUT, 0, 0 },
+  { CODE_FOR_mqsaths, "__MQSATHS", FRV_BUILTIN_MQSATHS, 0, 0 }
+};
+
+/* Media intrinsics that take two arguments, the first being an ACC number.  */
+
+static struct builtin_description bdesc_cut[] =
+{
+  { CODE_FOR_mcut, "__MCUT", FRV_BUILTIN_MCUT, 0, 0 },
+  { CODE_FOR_mcutss, "__MCUTSS", FRV_BUILTIN_MCUTSS, 0, 0 },
+  { CODE_FOR_mdcutssi, "__MDCUTSSI", FRV_BUILTIN_MDCUTSSI, 0, 0 }
+};
+
+/* Two-argument media intrinsics with an immediate second argument. */
+
+static struct builtin_description bdesc_2argimm[] =
+{
+  { CODE_FOR_mrotli, "__MROTLI", FRV_BUILTIN_MROTLI, 0, 0 },
+  { CODE_FOR_mrotri, "__MROTRI", FRV_BUILTIN_MROTRI, 0, 0 },
+  { CODE_FOR_msllhi, "__MSLLHI", FRV_BUILTIN_MSLLHI, 0, 0 },
+  { CODE_FOR_msrlhi, "__MSRLHI", FRV_BUILTIN_MSRLHI, 0, 0 },
+  { CODE_FOR_msrahi, "__MSRAHI", FRV_BUILTIN_MSRAHI, 0, 0 },
+  { CODE_FOR_mexpdhw, "__MEXPDHW", FRV_BUILTIN_MEXPDHW, 0, 0 },
+  { CODE_FOR_mexpdhd, "__MEXPDHD", FRV_BUILTIN_MEXPDHD, 0, 0 },
+  { CODE_FOR_mdrotli, "__MDROTLI", FRV_BUILTIN_MDROTLI, 0, 0 },
+  { CODE_FOR_mcplhi, "__MCPLHI", FRV_BUILTIN_MCPLHI, 0, 0 },
+  { CODE_FOR_mcpli, "__MCPLI", FRV_BUILTIN_MCPLI, 0, 0 },
+  { CODE_FOR_mhsetlos, "__MHSETLOS", FRV_BUILTIN_MHSETLOS, 0, 0 },
+  { CODE_FOR_mhsetloh, "__MHSETLOH", FRV_BUILTIN_MHSETLOH, 0, 0 },
+  { CODE_FOR_mhsethis, "__MHSETHIS", FRV_BUILTIN_MHSETHIS, 0, 0 },
+  { CODE_FOR_mhsethih, "__MHSETHIH", FRV_BUILTIN_MHSETHIH, 0, 0 },
+  { CODE_FOR_mhdseth, "__MHDSETH", FRV_BUILTIN_MHDSETH, 0, 0 }
+};
+
+/* Media intrinsics that take two arguments and return void, the first argument
+   being a pointer to 4 words in memory. */
+
+static struct builtin_description bdesc_void2arg[] =
+{
+  { CODE_FOR_mdunpackh, "__MDUNPACKH", FRV_BUILTIN_MDUNPACKH, 0, 0 },
+  { CODE_FOR_mbtohe, "__MBTOHE", FRV_BUILTIN_MBTOHE, 0, 0 },
+};
+
+/* Media intrinsics that take three arguments, the first being a const_int that
+   denotes an accumulator, and that return void. */
+
+static struct builtin_description bdesc_void3arg[] =
+{
+  { CODE_FOR_mcpxrs, "__MCPXRS", FRV_BUILTIN_MCPXRS, 0, 0 },
+  { CODE_FOR_mcpxru, "__MCPXRU", FRV_BUILTIN_MCPXRU, 0, 0 },
+  { CODE_FOR_mcpxis, "__MCPXIS", FRV_BUILTIN_MCPXIS, 0, 0 },
+  { CODE_FOR_mcpxiu, "__MCPXIU", FRV_BUILTIN_MCPXIU, 0, 0 },
+  { CODE_FOR_mmulhs, "__MMULHS", FRV_BUILTIN_MMULHS, 0, 0 },
+  { CODE_FOR_mmulhu, "__MMULHU", FRV_BUILTIN_MMULHU, 0, 0 },
+  { CODE_FOR_mmulxhs, "__MMULXHS", FRV_BUILTIN_MMULXHS, 0, 0 },
+  { CODE_FOR_mmulxhu, "__MMULXHU", FRV_BUILTIN_MMULXHU, 0, 0 },
+  { CODE_FOR_mmachs, "__MMACHS", FRV_BUILTIN_MMACHS, 0, 0 },
+  { CODE_FOR_mmachu, "__MMACHU", FRV_BUILTIN_MMACHU, 0, 0 },
+  { CODE_FOR_mmrdhs, "__MMRDHS", FRV_BUILTIN_MMRDHS, 0, 0 },
+  { CODE_FOR_mmrdhu, "__MMRDHU", FRV_BUILTIN_MMRDHU, 0, 0 },
+  { CODE_FOR_mqcpxrs, "__MQCPXRS", FRV_BUILTIN_MQCPXRS, 0, 0 },
+  { CODE_FOR_mqcpxru, "__MQCPXRU", FRV_BUILTIN_MQCPXRU, 0, 0 },
+  { CODE_FOR_mqcpxis, "__MQCPXIS", FRV_BUILTIN_MQCPXIS, 0, 0 },
+  { CODE_FOR_mqcpxiu, "__MQCPXIU", FRV_BUILTIN_MQCPXIU, 0, 0 },
+  { CODE_FOR_mqmulhs, "__MQMULHS", FRV_BUILTIN_MQMULHS, 0, 0 },
+  { CODE_FOR_mqmulhu, "__MQMULHU", FRV_BUILTIN_MQMULHU, 0, 0 },
+  { CODE_FOR_mqmulxhs, "__MQMULXHS", FRV_BUILTIN_MQMULXHS, 0, 0 },
+  { CODE_FOR_mqmulxhu, "__MQMULXHU", FRV_BUILTIN_MQMULXHU, 0, 0 },
+  { CODE_FOR_mqmachs, "__MQMACHS", FRV_BUILTIN_MQMACHS, 0, 0 },
+  { CODE_FOR_mqmachu, "__MQMACHU", FRV_BUILTIN_MQMACHU, 0, 0 },
+  { CODE_FOR_mqxmachs, "__MQXMACHS", FRV_BUILTIN_MQXMACHS, 0, 0 },
+  { CODE_FOR_mqxmacxhs, "__MQXMACXHS", FRV_BUILTIN_MQXMACXHS, 0, 0 },
+  { CODE_FOR_mqmacxhs, "__MQMACXHS", FRV_BUILTIN_MQMACXHS, 0, 0 }
+};
+
+/* Media intrinsics that take two accumulator numbers as argument and
+   return void.  */
+
+static struct builtin_description bdesc_voidacc[] =
+{
+  { CODE_FOR_maddaccs, "__MADDACCS", FRV_BUILTIN_MADDACCS, 0, 0 },
+  { CODE_FOR_msubaccs, "__MSUBACCS", FRV_BUILTIN_MSUBACCS, 0, 0 },
+  { CODE_FOR_masaccs, "__MASACCS", FRV_BUILTIN_MASACCS, 0, 0 },
+  { CODE_FOR_mdaddaccs, "__MDADDACCS", FRV_BUILTIN_MDADDACCS, 0, 0 },
+  { CODE_FOR_mdsubaccs, "__MDSUBACCS", FRV_BUILTIN_MDSUBACCS, 0, 0 },
+  { CODE_FOR_mdasaccs, "__MDASACCS", FRV_BUILTIN_MDASACCS, 0, 0 }
+};
+
+/* Initialize media builtins. */
+
+void
+frv_init_builtins ()
+{
+  tree endlink = void_list_node;
+  tree accumulator = integer_type_node;
+  tree integer = integer_type_node;
+  tree voidt = void_type_node;
+  tree uhalf = short_unsigned_type_node;
+  tree sword1 = long_integer_type_node;
+  tree uword1 = long_unsigned_type_node;
+  tree sword2 = long_long_integer_type_node;
+  tree uword2 = long_long_unsigned_type_node;
+  tree uword4 = build_pointer_type (uword1);
+
+#define UNARY(RET, T1) \
+  build_function_type (RET, tree_cons (NULL_TREE, T1, endlink))
+
+#define BINARY(RET, T1, T2) \
+  build_function_type (RET, tree_cons (NULL_TREE, T1, \
+                           tree_cons (NULL_TREE, T2, endlink)))
+
+#define TRINARY(RET, T1, T2, T3) \
+  build_function_type (RET, tree_cons (NULL_TREE, T1, \
+                           tree_cons (NULL_TREE, T2, \
+                           tree_cons (NULL_TREE, T3, endlink))))
+
+  tree void_ftype_void = build_function_type (voidt, endlink);
+
+  tree void_ftype_acc = UNARY (voidt, accumulator);
+  tree void_ftype_uw4_uw1 = BINARY (voidt, uword4, uword1);
+  tree void_ftype_uw4_uw2 = BINARY (voidt, uword4, uword2);
+  tree void_ftype_acc_uw1 = BINARY (voidt, accumulator, uword1);
+  tree void_ftype_acc_acc = BINARY (voidt, accumulator, accumulator);
+  tree void_ftype_acc_uw1_uw1 = TRINARY (voidt, accumulator, uword1, uword1);
+  tree void_ftype_acc_sw1_sw1 = TRINARY (voidt, accumulator, sword1, sword1);
+  tree void_ftype_acc_uw2_uw2 = TRINARY (voidt, accumulator, uword2, uword2);
+  tree void_ftype_acc_sw2_sw2 = TRINARY (voidt, accumulator, sword2, sword2);
+
+  tree uw1_ftype_uw1 = UNARY (uword1, uword1);
+  tree uw1_ftype_sw1 = UNARY (uword1, sword1);
+  tree uw1_ftype_uw2 = UNARY (uword1, uword2);
+  tree uw1_ftype_acc = UNARY (uword1, accumulator);
+  tree uw1_ftype_uh_uh = BINARY (uword1, uhalf, uhalf);
+  tree uw1_ftype_uw1_uw1 = BINARY (uword1, uword1, uword1);
+  tree uw1_ftype_uw1_int = BINARY (uword1, uword1, integer);
+  tree uw1_ftype_acc_uw1 = BINARY (uword1, accumulator, uword1);
+  tree uw1_ftype_acc_sw1 = BINARY (uword1, accumulator, sword1);
+  tree uw1_ftype_uw2_uw1 = BINARY (uword1, uword2, uword1);
+  tree uw1_ftype_uw2_int = BINARY (uword1, uword2, integer);
+
+  tree sw1_ftype_int = UNARY (sword1, integer);
+  tree sw1_ftype_sw1_sw1 = BINARY (sword1, sword1, sword1);
+  tree sw1_ftype_sw1_int = BINARY (sword1, sword1, integer);
+
+  tree uw2_ftype_uw1 = UNARY (uword2, uword1);
+  tree uw2_ftype_uw1_int = BINARY (uword2, uword1, integer);
+  tree uw2_ftype_uw2_uw2 = BINARY (uword2, uword2, uword2);
+  tree uw2_ftype_uw2_int = BINARY (uword2, uword2, integer);
+  tree uw2_ftype_acc_int = BINARY (uword2, accumulator, integer);
+
+  tree sw2_ftype_sw2_sw2 = BINARY (sword2, sword2, sword2);
+
+  def_builtin ("__MAND", uw1_ftype_uw1_uw1, FRV_BUILTIN_MAND);
+  def_builtin ("__MOR", uw1_ftype_uw1_uw1, FRV_BUILTIN_MOR);
+  def_builtin ("__MXOR", uw1_ftype_uw1_uw1, FRV_BUILTIN_MXOR);
+  def_builtin ("__MNOT", uw1_ftype_uw1, FRV_BUILTIN_MNOT);
+  def_builtin ("__MROTLI", uw1_ftype_uw1_int, FRV_BUILTIN_MROTLI);
+  def_builtin ("__MROTRI", uw1_ftype_uw1_int, FRV_BUILTIN_MROTRI);
+  def_builtin ("__MWCUT", uw1_ftype_uw2_uw1, FRV_BUILTIN_MWCUT);
+  def_builtin ("__MAVEH", uw1_ftype_uw1_uw1, FRV_BUILTIN_MAVEH);
+  def_builtin ("__MSLLHI", uw1_ftype_uw1_int, FRV_BUILTIN_MSLLHI);
+  def_builtin ("__MSRLHI", uw1_ftype_uw1_int, FRV_BUILTIN_MSRLHI);
+  def_builtin ("__MSRAHI", sw1_ftype_sw1_int, FRV_BUILTIN_MSRAHI);
+  def_builtin ("__MSATHS", sw1_ftype_sw1_sw1, FRV_BUILTIN_MSATHS);
+  def_builtin ("__MSATHU", uw1_ftype_uw1_uw1, FRV_BUILTIN_MSATHU);
+  def_builtin ("__MADDHSS", sw1_ftype_sw1_sw1, FRV_BUILTIN_MADDHSS);
+  def_builtin ("__MADDHUS", uw1_ftype_uw1_uw1, FRV_BUILTIN_MADDHUS);
+  def_builtin ("__MSUBHSS", sw1_ftype_sw1_sw1, FRV_BUILTIN_MSUBHSS);
+  def_builtin ("__MSUBHUS", uw1_ftype_uw1_uw1, FRV_BUILTIN_MSUBHUS);
+  def_builtin ("__MMULHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMULHS);
+  def_builtin ("__MMULHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMULHU);
+  def_builtin ("__MMULXHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMULXHS);
+  def_builtin ("__MMULXHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMULXHU);
+  def_builtin ("__MMACHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMACHS);
+  def_builtin ("__MMACHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMACHU);
+  def_builtin ("__MMRDHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMRDHS);
+  def_builtin ("__MMRDHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMRDHU);
+  def_builtin ("__MQADDHSS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQADDHSS);
+  def_builtin ("__MQADDHUS", uw2_ftype_uw2_uw2, FRV_BUILTIN_MQADDHUS);
+  def_builtin ("__MQSUBHSS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQSUBHSS);
+  def_builtin ("__MQSUBHUS", uw2_ftype_uw2_uw2, FRV_BUILTIN_MQSUBHUS);
+  def_builtin ("__MQMULHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMULHS);
+  def_builtin ("__MQMULHU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQMULHU);
+  def_builtin ("__MQMULXHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMULXHS);
+  def_builtin ("__MQMULXHU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQMULXHU);
+  def_builtin ("__MQMACHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMACHS);
+  def_builtin ("__MQMACHU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQMACHU);
+  def_builtin ("__MCPXRS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MCPXRS);
+  def_builtin ("__MCPXRU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MCPXRU);
+  def_builtin ("__MCPXIS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MCPXIS);
+  def_builtin ("__MCPXIU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MCPXIU);
+  def_builtin ("__MQCPXRS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQCPXRS);
+  def_builtin ("__MQCPXRU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQCPXRU);
+  def_builtin ("__MQCPXIS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQCPXIS);
+  def_builtin ("__MQCPXIU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQCPXIU);
+  def_builtin ("__MCUT", uw1_ftype_acc_uw1, FRV_BUILTIN_MCUT);
+  def_builtin ("__MCUTSS", uw1_ftype_acc_sw1, FRV_BUILTIN_MCUTSS);
+  def_builtin ("__MEXPDHW", uw1_ftype_uw1_int, FRV_BUILTIN_MEXPDHW);
+  def_builtin ("__MEXPDHD", uw2_ftype_uw1_int, FRV_BUILTIN_MEXPDHD);
+  def_builtin ("__MPACKH", uw1_ftype_uh_uh, FRV_BUILTIN_MPACKH);
+  def_builtin ("__MUNPACKH", uw2_ftype_uw1, FRV_BUILTIN_MUNPACKH);
+  def_builtin ("__MDPACKH", uw2_ftype_uw2_uw2, FRV_BUILTIN_MDPACKH);
+  def_builtin ("__MDUNPACKH", void_ftype_uw4_uw2, FRV_BUILTIN_MDUNPACKH); 
+  def_builtin ("__MBTOH", uw2_ftype_uw1, FRV_BUILTIN_MBTOH);
+  def_builtin ("__MHTOB", uw1_ftype_uw2, FRV_BUILTIN_MHTOB);
+  def_builtin ("__MBTOHE", void_ftype_uw4_uw1, FRV_BUILTIN_MBTOHE);
+  def_builtin ("__MCLRACC", void_ftype_acc, FRV_BUILTIN_MCLRACC);
+  def_builtin ("__MCLRACCA", void_ftype_void, FRV_BUILTIN_MCLRACCA);
+  def_builtin ("__MRDACC", uw1_ftype_acc, FRV_BUILTIN_MRDACC);
+  def_builtin ("__MRDACCG", uw1_ftype_acc, FRV_BUILTIN_MRDACCG);
+  def_builtin ("__MWTACC", void_ftype_acc_uw1, FRV_BUILTIN_MWTACC);
+  def_builtin ("__MWTACCG", void_ftype_acc_uw1, FRV_BUILTIN_MWTACCG);
+  def_builtin ("__Mcop1", uw1_ftype_uw1_uw1, FRV_BUILTIN_MCOP1);
+  def_builtin ("__Mcop2", uw1_ftype_uw1_uw1, FRV_BUILTIN_MCOP2);
+  def_builtin ("__MTRAP", void_ftype_void, FRV_BUILTIN_MTRAP);
+  def_builtin ("__MQXMACHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQXMACHS);
+  def_builtin ("__MQXMACXHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQXMACXHS);
+  def_builtin ("__MQMACXHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMACXHS);
+  def_builtin ("__MADDACCS", void_ftype_acc_acc, FRV_BUILTIN_MADDACCS);
+  def_builtin ("__MSUBACCS", void_ftype_acc_acc, FRV_BUILTIN_MSUBACCS);
+  def_builtin ("__MASACCS", void_ftype_acc_acc, FRV_BUILTIN_MASACCS);
+  def_builtin ("__MDADDACCS", void_ftype_acc_acc, FRV_BUILTIN_MDADDACCS);
+  def_builtin ("__MDSUBACCS", void_ftype_acc_acc, FRV_BUILTIN_MDSUBACCS);
+  def_builtin ("__MDASACCS", void_ftype_acc_acc, FRV_BUILTIN_MDASACCS);
+  def_builtin ("__MABSHS", uw1_ftype_sw1, FRV_BUILTIN_MABSHS);
+  def_builtin ("__MDROTLI", uw2_ftype_uw2_int, FRV_BUILTIN_MDROTLI);
+  def_builtin ("__MCPLHI", uw1_ftype_uw2_int, FRV_BUILTIN_MCPLHI);
+  def_builtin ("__MCPLI", uw1_ftype_uw2_int, FRV_BUILTIN_MCPLI);
+  def_builtin ("__MDCUTSSI", uw2_ftype_acc_int, FRV_BUILTIN_MDCUTSSI);
+  def_builtin ("__MQSATHS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQSATHS);
+  def_builtin ("__MHSETLOS", sw1_ftype_sw1_int, FRV_BUILTIN_MHSETLOS);
+  def_builtin ("__MHSETHIS", sw1_ftype_sw1_int, FRV_BUILTIN_MHSETHIS);
+  def_builtin ("__MHDSETS", sw1_ftype_int, FRV_BUILTIN_MHDSETS);
+  def_builtin ("__MHSETLOH", uw1_ftype_uw1_int, FRV_BUILTIN_MHSETLOH);
+  def_builtin ("__MHSETHIH", uw1_ftype_uw1_int, FRV_BUILTIN_MHSETHIH);
+  def_builtin ("__MHDSETH", uw1_ftype_uw1_int, FRV_BUILTIN_MHDSETH);
+
+#undef UNARY
+#undef BINARY
+#undef TRINARY
+}
+
+/* Convert an integer constant to an accumulator register.  ICODE is the
+   code of the target instruction, OPNUM is the number of the
+   accumulator operand and OPVAL is the constant integer.  Try both
+   ACC and ACCG registers; only report an error if neither fit the
+   instruction.  */
+
+static rtx
+frv_int_to_acc (icode, opnum, opval)
+     enum insn_code icode;
+     int opnum;
+     rtx opval;
+{
+  rtx reg;
+
+  if (GET_CODE (opval) != CONST_INT)
+    {
+      error ("accumulator is not a constant integer");
+      return NULL_RTX;
+    }
+  if (! IN_RANGE_P (INTVAL (opval), 0, NUM_ACCS - 1))
+    {
+      error ("accumulator number is out of bounds");
+      return NULL_RTX;
+    }
+
+  reg = gen_rtx_REG (insn_data[icode].operand[opnum].mode,
+                    ACC_FIRST + INTVAL (opval));
+  if (! (*insn_data[icode].operand[opnum].predicate) (reg, VOIDmode))
+    REGNO (reg) = ACCG_FIRST + INTVAL (opval);
+
+  if (! (*insn_data[icode].operand[opnum].predicate) (reg, VOIDmode))
+    {
+      error ("inappropriate accumulator for `%s'", insn_data[icode].name);
+      return NULL_RTX;
+    }
+  return reg;
+}
+
+/* If an ACC rtx has mode MODE, return the mode that the matching ACCG
+   should have.  */
+
+static enum machine_mode
+frv_matching_accg_mode (mode)
+     enum machine_mode mode;
+{
+  switch (mode)
+    {
+    case V4SImode:
+      return V4QImode;
+
+    case DImode:
+      return HImode;
+
+    case SImode:
+      return QImode;
+
+    default:
+      abort ();
+    }
+}
+
+/* Return the accumulator guard that should be paired with accumulator
+   register ACC.  The mode of the returned register is in the same
+   class as ACC, but is four times smaller.  */
+
+rtx
+frv_matching_accg_for_acc (acc)
+     rtx acc;
+{
+  return gen_rtx_REG (frv_matching_accg_mode (GET_MODE (acc)),
+                     REGNO (acc) - ACC_FIRST + ACCG_FIRST);
+}
+
+/* Read a value from the head of the tree list pointed to by ARGLISTPTR.
+   Return the value as an rtx and replace *ARGLISTPTR with the tail of the
+   list.  */
+
+static rtx
+frv_read_argument (arglistptr)
+     tree *arglistptr;
+{
+  tree next = TREE_VALUE (*arglistptr);
+  *arglistptr = TREE_CHAIN (*arglistptr);
+  return expand_expr (next, NULL_RTX, VOIDmode, 0);
+}
+
+/* Return true if OPVAL can be used for operand OPNUM of instruction ICODE.
+   The instruction should require a constant operand of some sort.  The
+   function prints an error if OPVAL is not valid.  */
+
+static int
+frv_check_constant_argument (icode, opnum, opval)
+     enum insn_code icode;
+     int opnum;
+     rtx opval;
+{
+  if (GET_CODE (opval) != CONST_INT)
+    {
+      error ("`%s' expects a constant argument", insn_data[icode].name);
+      return FALSE;
+    }
+  if (! (*insn_data[icode].operand[opnum].predicate) (opval, VOIDmode))
+    {
+      error ("constant argument out of range for `%s'", insn_data[icode].name);
+      return FALSE;
+    }
+  return TRUE;
+}
+
+/* Return a legitimate rtx for instruction ICODE's return value.  Use TARGET
+   if it's not null, has the right mode, and satisfies operand 0's
+   predicate.  */
+
+static rtx
+frv_legitimize_target (icode, target)
+     enum insn_code icode;
+     rtx target;
+{
+  enum machine_mode mode = insn_data[icode].operand[0].mode;
+
+  if (! target
+      || GET_MODE (target) != mode
+      || ! (*insn_data[icode].operand[0].predicate) (target, mode))
+    return gen_reg_rtx (mode);
+  else
+    return target;
+}
+
+/* Given that ARG is being passed as operand OPNUM to instruction ICODE,
+   check whether ARG satisfies the operand's contraints.  If it doesn't,
+   copy ARG to a temporary register and return that.  Otherwise return ARG
+   itself.  */
+
+static rtx
+frv_legitimize_argument (icode, opnum, arg)
+     enum insn_code icode;
+     int opnum;
+     rtx arg;
+{
+  enum machine_mode mode = insn_data[icode].operand[opnum].mode;
+
+  if ((*insn_data[icode].operand[opnum].predicate) (arg, mode))
+    return arg;
+  else
+    return copy_to_mode_reg (mode, arg);
+}
+
+/* Expand builtins that take a single, constant argument.  At the moment,
+   only MHDSETS falls into this category.  */
+
+static rtx
+frv_expand_set_builtin (icode, arglist, target)
+     enum insn_code icode;
+     tree arglist;
+     rtx target;
+{
+  rtx pat;
+  rtx op0 = frv_read_argument (&arglist);
+
+  if (! frv_check_constant_argument (icode, 1, op0))
+    return NULL_RTX;
+
+  target = frv_legitimize_target (icode, target);
+  pat = GEN_FCN (icode) (target, op0);
+  if (! pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+  return target;
+}
+
+/* Expand builtins that take one operand. */
+
+static rtx
+frv_expand_unop_builtin (icode, arglist, target)
+     enum insn_code icode;
+     tree arglist;
+     rtx target;
+{
+  rtx pat;
+  rtx op0 = frv_read_argument (&arglist);
+
+  target = frv_legitimize_target (icode, target);
+  op0 = frv_legitimize_argument (icode, 1, op0);
+  pat = GEN_FCN (icode) (target, op0);
+  if (! pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+  return target;
+}
+
+/* Expand builtins that take two operands. */
+
+static rtx
+frv_expand_binop_builtin (icode, arglist, target)
+     enum insn_code icode;
+     tree arglist;
+     rtx target;
+{
+  rtx pat;
+  rtx op0 = frv_read_argument (&arglist);
+  rtx op1 = frv_read_argument (&arglist);
+
+  target = frv_legitimize_target (icode, target);
+  op0 = frv_legitimize_argument (icode, 1, op0);
+  op1 = frv_legitimize_argument (icode, 2, op1);
+  pat = GEN_FCN (icode) (target, op0, op1);
+  if (! pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+  return target;
+}
+
+/* Expand cut-style builtins, which take two operands and an implicit ACCG
+   one. */
+
+static rtx
+frv_expand_cut_builtin (icode, arglist, target)
+     enum insn_code icode;
+     tree arglist;
+     rtx target;
+{
+  rtx pat;
+  rtx op0 = frv_read_argument (&arglist);
+  rtx op1 = frv_read_argument (&arglist);
+  rtx op2;
+
+  target = frv_legitimize_target (icode, target);
+  op0 = frv_int_to_acc (icode, 1, op0);
+  if (! op0)
+    return NULL_RTX;
+
+  if (icode == CODE_FOR_mdcutssi || GET_CODE (op1) == CONST_INT)
+    {
+      if (! frv_check_constant_argument (icode, 2, op1))
+       return NULL_RTX;
+    }
+  else
+    op1 = frv_legitimize_argument (icode, 2, op1);
+
+  op2 = frv_matching_accg_for_acc (op0);
+  pat = GEN_FCN (icode) (target, op0, op1, op2);
+  if (! pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+  return target;
+}
+
+/* Expand builtins that take two operands and the second is immediate. */
+
+static rtx
+frv_expand_binopimm_builtin (icode, arglist, target)
+     enum insn_code icode;
+     tree arglist;
+     rtx target;
+{
+  rtx pat;
+  rtx op0 = frv_read_argument (&arglist);
+  rtx op1 = frv_read_argument (&arglist);
+
+  if (! frv_check_constant_argument (icode, 2, op1))
+    return NULL_RTX;
+
+  target = frv_legitimize_target (icode, target);
+  op0 = frv_legitimize_argument (icode, 1, op0);
+  pat = GEN_FCN (icode) (target, op0, op1);
+  if (! pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+  return target;
+}
+
+/* Expand builtins that take two operands, the first operand being a pointer to
+   ints and return void. */
+
+static rtx
+frv_expand_voidbinop_builtin (icode, arglist)
+     enum insn_code icode;
+     tree arglist;
+{
+  rtx pat;
+  rtx op0 = frv_read_argument (&arglist);
+  rtx op1 = frv_read_argument (&arglist);
+  enum machine_mode mode0 = insn_data[icode].operand[0].mode;
+  rtx addr;
+
+  if (GET_CODE (op0) != MEM)
+    {
+      rtx reg = op0;
+
+      if (! offsettable_address_p (0, mode0, op0))
+       {
+         reg = gen_reg_rtx (Pmode);
+         emit_insn (gen_rtx_SET (VOIDmode, reg, op0));
+       }
+
+      op0 = gen_rtx_MEM (SImode, reg);
+    }
+
+  addr = XEXP (op0, 0);
+  if (! offsettable_address_p (0, mode0, addr))
+    addr = copy_to_mode_reg (Pmode, op0);
+
+  op0 = change_address (op0, V4SImode, addr);
+  op1 = frv_legitimize_argument (icode, 1, op1);
+  pat = GEN_FCN (icode) (op0, op1);
+  if (! pat)
+    return 0;
+
+  emit_insn (pat);
+  return 0;
+}
+
+/* Expand builtins that take three operands and return void.  The first
+   argument must be a constant that describes a pair or quad accumulators.  A
+   fourth argument is created that is the accumulator guard register that
+   corresponds to the accumulator.  */
+
+static rtx
+frv_expand_voidtriop_builtin (icode, arglist)
+     enum insn_code icode;
+     tree arglist;
+{
+  rtx pat;
+  rtx op0 = frv_read_argument (&arglist);
+  rtx op1 = frv_read_argument (&arglist);
+  rtx op2 = frv_read_argument (&arglist);
+  rtx op3;
+
+  op0 = frv_int_to_acc (icode, 0, op0);
+  if (! op0)
+    return NULL_RTX;
+
+  op1 = frv_legitimize_argument (icode, 1, op1);
+  op2 = frv_legitimize_argument (icode, 2, op2);
+  op3 = frv_matching_accg_for_acc (op0);
+  pat = GEN_FCN (icode) (op0, op1, op2, op3);
+  if (! pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+  return NULL_RTX;
+}
+
+/* Expand builtins that perform accumulator-to-accumulator operations.
+   These builtins take two accumulator numbers as argument and return
+   void.  */
+
+static rtx
+frv_expand_voidaccop_builtin (icode, arglist)
+     enum insn_code icode;
+     tree arglist;
+{
+  rtx pat;
+  rtx op0 = frv_read_argument (&arglist);
+  rtx op1 = frv_read_argument (&arglist);
+  rtx op2;
+  rtx op3;
+
+  op0 = frv_int_to_acc (icode, 0, op0);
+  if (! op0)
+    return NULL_RTX;
+
+  op1 = frv_int_to_acc (icode, 1, op1);
+  if (! op1)
+    return NULL_RTX;
+
+  op2 = frv_matching_accg_for_acc (op0);
+  op3 = frv_matching_accg_for_acc (op1);
+  pat = GEN_FCN (icode) (op0, op1, op2, op3);
+  if (! pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+  return NULL_RTX;
+}
+
+/* Expand the MCLRACC builtin.  This builtin takes a single accumulator
+   number as argument.  */
+
+static rtx
+frv_expand_mclracc_builtin (arglist)
+     tree arglist;
+{
+  enum insn_code icode = CODE_FOR_mclracc;
+  rtx pat;
+  rtx op0 = frv_read_argument (&arglist);
+
+  op0 = frv_int_to_acc (icode, 0, op0);
+  if (! op0)
+    return NULL_RTX;
+
+  pat = GEN_FCN (icode) (op0);
+  if (pat)
+    emit_insn (pat);
+
+  return NULL_RTX;
+}
+
+/* Expand builtins that take no arguments.  */
+
+static rtx
+frv_expand_noargs_builtin (icode)
+     enum insn_code icode;
+{
+  rtx pat = GEN_FCN (icode) (GEN_INT (0));
+  if (pat)
+    emit_insn (pat);
+
+  return NULL_RTX;
+}
+
+/* Expand MRDACC and MRDACCG.  These builtins take a single accumulator
+   number or accumulator guard number as argument and return an SI integer.  */
+
+static rtx
+frv_expand_mrdacc_builtin (icode, arglist)
+     enum insn_code icode;
+     tree arglist;
+{
+  rtx pat;
+  rtx target = gen_reg_rtx (SImode);
+  rtx op0 = frv_read_argument (&arglist);
+
+  op0 = frv_int_to_acc (icode, 1, op0);
+  if (! op0)
+    return NULL_RTX;
+
+  pat = GEN_FCN (icode) (target, op0);
+  if (! pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+  return target;
+}
+
+/* Expand MWTACC and MWTACCG.  These builtins take an accumulator or
+   accumulator guard as their first argument and an SImode value as their
+   second.  */
+
+static rtx
+frv_expand_mwtacc_builtin (icode, arglist)
+     enum insn_code icode;
+     tree arglist;
+{
+  rtx pat;
+  rtx op0 = frv_read_argument (&arglist);
+  rtx op1 = frv_read_argument (&arglist);
+
+  op0 = frv_int_to_acc (icode, 0, op0);
+  if (! op0)
+    return NULL_RTX;
+
+  op1 = frv_legitimize_argument (icode, 1, op1);
+  pat = GEN_FCN (icode) (op0, op1);
+  if (pat)
+    emit_insn (pat);
+
+  return NULL_RTX;
+}
+
+/* Expand builtins. */
+
+rtx
+frv_expand_builtin (exp, target, subtarget, mode, ignore)
+     tree exp;
+     rtx target;
+     rtx subtarget ATTRIBUTE_UNUSED;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     int ignore ATTRIBUTE_UNUSED;
+{
+  tree arglist = TREE_OPERAND (exp, 1);
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  unsigned fcode = (unsigned)DECL_FUNCTION_CODE (fndecl);
+  unsigned i;
+  struct builtin_description *d;
+
+  if (! TARGET_MEDIA)
+    {
+      error ("media functions are not available unless -mmedia is used");
+      return NULL_RTX;
+    }
+
+  switch (fcode)
+    {
+    case FRV_BUILTIN_MCOP1:
+    case FRV_BUILTIN_MCOP2:
+    case FRV_BUILTIN_MDUNPACKH:
+    case FRV_BUILTIN_MBTOHE:
+      if (! TARGET_MEDIA_REV1)
+       {
+         error ("this media function is only available on the fr500");
+         return NULL_RTX;
+       }
+      break;
+
+    case FRV_BUILTIN_MQXMACHS:
+    case FRV_BUILTIN_MQXMACXHS:
+    case FRV_BUILTIN_MQMACXHS:
+    case FRV_BUILTIN_MADDACCS:
+    case FRV_BUILTIN_MSUBACCS:
+    case FRV_BUILTIN_MASACCS:
+    case FRV_BUILTIN_MDADDACCS:
+    case FRV_BUILTIN_MDSUBACCS:
+    case FRV_BUILTIN_MDASACCS:
+    case FRV_BUILTIN_MABSHS:
+    case FRV_BUILTIN_MDROTLI:
+    case FRV_BUILTIN_MCPLHI:
+    case FRV_BUILTIN_MCPLI:
+    case FRV_BUILTIN_MDCUTSSI:
+    case FRV_BUILTIN_MQSATHS:
+    case FRV_BUILTIN_MHSETLOS:
+    case FRV_BUILTIN_MHSETLOH:
+    case FRV_BUILTIN_MHSETHIS:
+    case FRV_BUILTIN_MHSETHIH:
+    case FRV_BUILTIN_MHDSETS:
+    case FRV_BUILTIN_MHDSETH:
+      if (! TARGET_MEDIA_REV2)
+       {
+         error ("this media function is only available on the fr400");
+         return NULL_RTX;
+       }
+      break;
+
+    default:
+      break;
+    }
+
+  /* Expand unique builtins. */
+
+  switch (fcode)
+    {
+    case FRV_BUILTIN_MTRAP:
+      return frv_expand_noargs_builtin (CODE_FOR_mtrap);
+
+    case FRV_BUILTIN_MCLRACC:
+      return frv_expand_mclracc_builtin (arglist);
+
+    case FRV_BUILTIN_MCLRACCA:
+      if (TARGET_ACC_8)
+       return frv_expand_noargs_builtin (CODE_FOR_mclracca8);
+      else
+       return frv_expand_noargs_builtin (CODE_FOR_mclracca4);
+
+    case FRV_BUILTIN_MRDACC:
+      return frv_expand_mrdacc_builtin (CODE_FOR_mrdacc, arglist);
+
+    case FRV_BUILTIN_MRDACCG:
+      return frv_expand_mrdacc_builtin (CODE_FOR_mrdaccg, arglist);
+
+    case FRV_BUILTIN_MWTACC:
+      return frv_expand_mwtacc_builtin (CODE_FOR_mwtacc, arglist);
+
+    case FRV_BUILTIN_MWTACCG:
+      return frv_expand_mwtacc_builtin (CODE_FOR_mwtaccg, arglist);
+
+    default:
+      break;
+    }
+
+  /* Expand groups of builtins. */
+
+  for (i = 0, d = bdesc_set; i < sizeof (bdesc_set) / sizeof *d; i++, d++)
+    if (d->code == fcode)
+      return frv_expand_set_builtin (d->icode, arglist, target);
+
+  for (i = 0, d = bdesc_1arg; i < sizeof (bdesc_1arg) / sizeof *d; i++, d++)
+    if (d->code == fcode)
+      return frv_expand_unop_builtin (d->icode, arglist, target);
+
+  for (i = 0, d = bdesc_2arg; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++)
+    if (d->code == fcode)
+      return frv_expand_binop_builtin (d->icode, arglist, target);
+
+  for (i = 0, d = bdesc_cut; i < sizeof (bdesc_cut) / sizeof *d; i++, d++)
+    if (d->code == fcode)
+      return frv_expand_cut_builtin (d->icode, arglist, target);
+
+  for (i = 0, d = bdesc_2argimm;
+       i < sizeof (bdesc_2argimm) / sizeof *d;
+       i++, d++)
+    {
+      if (d->code == fcode)
+       return frv_expand_binopimm_builtin (d->icode, arglist, target);
+    }
+
+  for (i = 0, d = bdesc_void2arg;
+       i < sizeof (bdesc_void2arg) / sizeof *d;
+       i++, d++)
+    {
+      if (d->code == fcode)
+       return frv_expand_voidbinop_builtin (d->icode, arglist);
+    }
+
+  for (i = 0, d = bdesc_void3arg;
+       i < sizeof (bdesc_void3arg) / sizeof *d;
+       i++, d++)
+    {
+      if (d->code == fcode)
+       return frv_expand_voidtriop_builtin (d->icode, arglist);
+    }
+
+  for (i = 0, d = bdesc_voidacc;
+       i < sizeof (bdesc_voidacc) / sizeof *d;
+       i++, d++)
+    {
+      if (d->code == fcode)
+       return frv_expand_voidaccop_builtin (d->icode, arglist);
+    }
+  return 0;
+}
diff --git a/gcc/config/frv/frv.h b/gcc/config/frv/frv.h
new file mode 100644 (file)
index 0000000..2502fc0
--- /dev/null
@@ -0,0 +1,3751 @@
+/* Target macros for the FRV port of GCC.
+   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Contributed by Red Hat 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.
+
+   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.  */
+
+#ifndef __FRV_H__
+#define __FRV_H__
+
+/* Set up System V.4 (aka ELF) defaults.  */
+#include "svr4.h"
+
+\f
+/* Frv general purpose macros.  */
+/* Align an address.  */
+#define ADDR_ALIGN(addr,align) (((addr) + (align) - 1) & ~((align) - 1))
+
+/* Return true if a value is inside a range.  */
+#define IN_RANGE_P(VALUE, LOW, HIGH)                           \
+  (   (((HOST_WIDE_INT)(VALUE)) >= (HOST_WIDE_INT)(LOW))       \
+   && (((HOST_WIDE_INT)(VALUE)) <= ((HOST_WIDE_INT)(HIGH))))
+
+\f
+/* Driver configuration.  */
+
+/* A C expression which determines whether the option `-CHAR' takes arguments.
+   The value should be the number of arguments that option takes-zero, for many
+   options.
+
+   By default, this macro is defined to handle the standard options properly.
+   You need not define it unless you wish to add additional options which take
+   arguments.
+
+   Defined in svr4.h.  */
+#undef  SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR)                                          \
+  (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G')
+
+/* A C expression which determines whether the option `-NAME' takes arguments.
+   The value should be the number of arguments that option takes-zero, for many
+   options.  This macro rather than `SWITCH_TAKES_ARG' is used for
+   multi-character option names.
+
+   By default, this macro is defined as `DEFAULT_WORD_SWITCH_TAKES_ARG', which
+   handles the standard options properly.  You need not define
+   `WORD_SWITCH_TAKES_ARG' unless you wish to add additional options which take
+   arguments.  Any redefinition should call `DEFAULT_WORD_SWITCH_TAKES_ARG' and
+   then check for additional options.
+
+   Defined in svr4.h.  */
+#undef WORD_SWITCH_TAKES_ARG
+
+/* A C string constant that tells the GNU CC driver program options to pass to
+   the assembler.  It can also specify how to translate options you give to GNU
+   CC into options for GNU CC to pass to the assembler.  See the file `sun3.h'
+   for an example of this.
+
+   Do not define this macro if it does not need to do anything.
+
+   Defined in svr4.h.  */
+#undef  ASM_SPEC
+#define ASM_SPEC "\
+%{G*} %{v} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*} \
+%{mtomcat-stats} \
+%{!mno-eflags: \
+    %{mcpu=*} \
+    %{mgpr-*} %{mfpr-*} \
+    %{msoft-float} %{mhard-float} \
+    %{mdword} %{mno-dword} \
+    %{mdouble} %{mno-double} \
+    %{mmedia} %{mno-media} \
+    %{mmuladd} %{mno-muladd} \
+    %{mpack} %{mno-pack} \
+    %{fpic: -mpic} %{fPIC: -mPIC} %{mlibrary-pic}}"
+
+/* Another C string constant used much like `LINK_SPEC'.  The difference
+   between the two is that `STARTFILE_SPEC' is used at the very beginning of
+   the command given to the linker.
+
+   If this macro is not defined, a default is provided that loads the standard
+   C startup file from the usual place.  See `gcc.c'.
+
+   Defined in svr4.h.  */
+#undef  STARTFILE_SPEC
+#define STARTFILE_SPEC "crt0%O%s frvbegin%O%s"
+
+/* Another C string constant used much like `LINK_SPEC'.  The difference
+   between the two is that `ENDFILE_SPEC' is used at the very end of the
+   command given to the linker.
+
+   Do not define this macro if it does not need to do anything.
+
+   Defined in svr4.h.  */
+#undef  ENDFILE_SPEC
+#define ENDFILE_SPEC "frvend%O%s"
+
+/* A C string constant that tells the GNU CC driver program options to pass to
+   CPP.  It can also specify how to translate options you give to GNU CC into
+   options for GNU CC to pass to the CPP.
+
+   Do not define this macro if it does not need to do anything.  */
+
+/* The idea here is to use the -mcpu option to define macros based on the
+   processor's features, using the features of the default processor if
+   no -mcpu option is given.  These macros can then be overridden by
+   other -m options.  */
+#define CPP_SPEC "\
+%{mcpu=frv: %(cpp_frv)} \
+%{mcpu=fr500: %(cpp_fr500)} \
+%{mcpu=fr400: %(cpp_fr400)} \
+%{mcpu=fr300: %(cpp_simple)} \
+%{mcpu=tomcat: %(cpp_fr500)} \
+%{mcpu=simple: %(cpp_simple)} \
+%{!mcpu*: %(cpp_cpu_default)} \
+%{mno-media: -D__FRV_ACC__=0 %{msoft-float: -D__FRV_FPR__=0}} \
+%{mhard-float: -D__FRV_HARD_FLOAT__} \
+%{msoft-float: -U__FRV_HARD_FLOAT__} \
+%{mgpr-32: -U__FRV_GPR__ -D__FRV_GPR__=32} \
+%{mgpr-64: -U__FRV_GPR__ -D__FRV_GPR__=64} \
+%{mfpr-32: -U__FRV_FPR__ -D__FRV_FPR__=32} \
+%{mfpr-64: -U__FRV_FPR__ -D__FRV_FPR__=64} \
+%{macc-4: -U__FRV_ACC__ -D__FRV_ACC__=4} \
+%{macc-8: -U__FRV_ACC__ -D__FRV_ACC__=8} \
+%{mdword: -D__FRV_DWORD__} \
+%{mno-dword: -U__FRV_DWORD__} \
+%{mno-pack: -U__FRV_VLIW__} \
+%{fleading-underscore: -D__FRV_UNDERSCORE__}"
+
+/* CPU defaults.  Each CPU has its own CPP spec that defines the default
+   macros for that CPU.  Each CPU also has its own default target mask.
+
+   CPU         GPRs    FPRs    ACCs    FPU     MulAdd  ldd/std  Issue rate
+   ---         ----    ----    ----    ---     ------  -------  ----------
+   FRV         64      64      8       double  yes     yes      4
+   FR500       64      64      8       single  no      yes      4
+   FR400       32      32      4       none    no      yes      2
+   Simple      32      0       0       none    no      no       1 */
+
+
+#define CPP_FRV_SPEC "\
+-D__FRV_GPR__=64 \
+-D__FRV_FPR__=64 \
+-D__FRV_ACC__=8 \
+-D__FRV_HARD_FLOAT__ \
+-D__FRV_DWORD__ \
+-D__FRV_VLIW__=4"
+
+#define CPP_FR500_SPEC "\
+-D__FRV_GPR__=64 \
+-D__FRV_FPR__=64 \
+-D__FRV_ACC__=8 \
+-D__FRV_HARD_FLOAT__ \
+-D__FRV_DWORD__ \
+-D__FRV_VLIW__=4"
+
+#define CPP_FR400_SPEC "\
+-D__FRV_GPR__=32 \
+-D__FRV_FPR__=32 \
+-D__FRV_ACC__=4 \
+-D__FRV_DWORD__ \
+-D__FRV_VLIW__=2"
+
+#define CPP_SIMPLE_SPEC "\
+-D__FRV_GPR__=32 \
+-D__FRV_FPR__=0 \
+-D__FRV_ACC__=0 \
+%{mmedia: -D__FRV_ACC__=8} \
+%{mhard-float|mmedia: -D__FRV_FPR__=64}"
+
+#define MASK_DEFAULT_FRV       \
+  (MASK_MEDIA                  \
+   | MASK_DOUBLE               \
+   | MASK_MULADD               \
+   | MASK_DWORD                        \
+   | MASK_PACK)
+
+#define MASK_DEFAULT_FR500 \
+  (MASK_MEDIA | MASK_DWORD | MASK_PACK)
+
+#define MASK_DEFAULT_FR400     \
+  (MASK_GPR_32                 \
+   | MASK_FPR_32               \
+   | MASK_MEDIA                        \
+   | MASK_ACC_4                        \
+   | MASK_SOFT_FLOAT           \
+   | MASK_DWORD                        \
+   | MASK_PACK)
+
+#define MASK_DEFAULT_SIMPLE \
+  (MASK_GPR_32 | MASK_SOFT_FLOAT)
+
+/* A C string constant that tells the GNU CC driver program options to pass to
+   `cc1'.  It can also specify how to translate options you give to GNU CC into
+   options for GNU CC to pass to the `cc1'.
+
+   Do not define this macro if it does not need to do anything.  */
+/* For ABI compliance, we need to put bss data into the normal data section.  */
+#define CC1_SPEC "%{G*}"
+
+/* A C string constant that tells the GNU CC driver program options to pass to
+   the linker.  It can also specify how to translate options you give to GNU CC
+   into options for GNU CC to pass to the linker.
+
+   Do not define this macro if it does not need to do anything.
+
+   Defined in svr4.h.  */
+/* Override the svr4.h version with one that dispenses without the svr4
+   shared library options, notably -G.  */
+#undef LINK_SPEC
+#define LINK_SPEC "\
+%{h*} %{v:-V} \
+%{b} %{Wl,*:%*} \
+%{static:-dn -Bstatic} \
+%{shared:-Bdynamic} \
+%{symbolic:-Bsymbolic} \
+%{G*} \
+%{YP,*} \
+%{Qy:} %{!Qn:-Qy}"
+
+/* Another C string constant used much like `LINK_SPEC'.  The difference
+   between the two is that `LIB_SPEC' is used at the end of the command given
+   to the linker.
+
+   If this macro is not defined, a default is provided that loads the standard
+   C library from the usual place.  See `gcc.c'.
+
+   Defined in svr4.h.  */
+
+#undef  LIB_SPEC
+#define LIB_SPEC "--start-group -lc -lsim --end-group"
+
+/* This macro defines names of additional specifications to put in the specs
+   that can be used in various specifications like CC1_SPEC.  Its definition
+   is an initializer with a subgrouping for each command option.
+
+   Each subgrouping contains a string constant, that defines the
+   specification name, and a string constant that used by the GNU CC driver
+   program.
+
+   Do not define this macro if it does not need to do anything.  */
+
+#ifndef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS
+#endif
+
+#define EXTRA_SPECS                                                    \
+  { "cpp_frv",         CPP_FRV_SPEC },                                 \
+  { "cpp_fr500",       CPP_FR500_SPEC },                               \
+  { "cpp_fr400",       CPP_FR400_SPEC },                               \
+  { "cpp_simple",      CPP_SIMPLE_SPEC },                              \
+  { "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC },                         \
+  SUBTARGET_EXTRA_SPECS
+
+#ifndef CPP_CPU_DEFAULT_SPEC
+#define CPP_CPU_DEFAULT_SPEC   CPP_FR500_SPEC
+#define CPU_TYPE               FRV_CPU_FR500
+#endif
+
+/* Allow us to easily change the default for -malloc-cc.  */
+#ifndef        DEFAULT_NO_ALLOC_CC
+#define MASK_DEFAULT_ALLOC_CC  MASK_ALLOC_CC
+#else
+#define MASK_DEFAULT_ALLOC_CC  0
+#endif
+
+/* Run-time target specifications */
+
+/* Define this to be a string constant containing `-D' options to define the
+   predefined macros that identify this machine and system.  These macros will
+   be predefined unless the `-ansi' option is specified.
+
+   In addition, a parallel set of macros are predefined, whose names are made
+   by appending `__' at the beginning and at the end.  These `__' macros are
+   permitted by the ANSI standard, so they are predefined regardless of whether
+   `-ansi' is specified.  */
+
+#define CPP_PREDEFINES "-D__frv__ -Amachine(frv)"
+
+\f
+/* This declaration should be present.  */
+extern int target_flags;
+
+/* This series of macros is to allow compiler command arguments to enable or
+   disable the use of optional features of the target machine.  For example,
+   one machine description serves both the 68000 and the 68020; a command
+   argument tells the compiler whether it should use 68020-only instructions or
+   not.  This command argument works by means of a macro `TARGET_68020' that
+   tests a bit in `target_flags'.
+
+   Define a macro `TARGET_FEATURENAME' for each such option.  Its definition
+   should test a bit in `target_flags'; for example:
+
+        #define TARGET_68020 (target_flags & 1)
+
+   One place where these macros are used is in the condition-expressions of
+   instruction patterns.  Note how `TARGET_68020' appears frequently in the
+   68000 machine description file, `m68k.md'.  Another place they are used is
+   in the definitions of the other macros in the `MACHINE.h' file.  */
+
+#define MASK_GPR_32         0x00000001 /* Limit gprs to 32 registers */
+#define MASK_FPR_32         0x00000002 /* Limit fprs to 32 registers */
+#define MASK_SOFT_FLOAT             0x00000004 /* Use software floating point */
+#define MASK_ALLOC_CC       0x00000008 /* Dynamically allocate icc/fcc's */
+#define MASK_DWORD          0x00000010 /* Change ABi to allow dbl word insns*/
+#define MASK_DOUBLE         0x00000020 /* Use double precision instructions */
+#define MASK_MEDIA          0x00000040 /* Use media instructions */
+#define MASK_MULADD         0x00000080 /* Use multiply add/subtract insns */
+#define MASK_LIBPIC         0x00000100 /* -fpic that can be linked w/o pic */
+#define MASK_ACC_4          0x00000200 /* Only use four media accumulators */
+#define MASK_PACK           0x00000400 /* Set to enable packed output */
+
+                                       /* put debug masks up high */
+#define MASK_DEBUG_ARG      0x40000000 /* debug argument handling */
+#define MASK_DEBUG_ADDR             0x20000000 /* debug go_if_legitimate_address */
+#define MASK_DEBUG_STACK     0x10000000        /* debug stack frame */
+#define MASK_DEBUG          0x08000000 /* general debugging switch */
+#define MASK_DEBUG_LOC      0x04000000 /* optimize line # table */
+#define MASK_DEBUG_COND_EXEC 0x02000000        /* debug cond exec code */
+#define MASK_NO_COND_MOVE    0x01000000        /* disable conditional moves */
+#define MASK_NO_SCC         0x00800000 /* disable set conditional codes */
+#define MASK_NO_COND_EXEC    0x00400000        /* disable conditional execution */
+#define MASK_NO_VLIW_BRANCH  0x00200000        /* disable repacking branches */
+#define MASK_NO_MULTI_CE     0x00100000        /* disable multi-level cond exec */
+#define MASK_NO_NESTED_CE    0x00080000        /* disable nested cond exec */
+
+#define MASK_DEFAULT           MASK_DEFAULT_ALLOC_CC
+
+#define TARGET_GPR_32          ((target_flags & MASK_GPR_32) != 0)
+#define TARGET_FPR_32          ((target_flags & MASK_FPR_32) != 0)
+#define TARGET_SOFT_FLOAT      ((target_flags & MASK_SOFT_FLOAT) != 0)
+#define TARGET_ALLOC_CC                ((target_flags & MASK_ALLOC_CC) != 0)
+#define TARGET_DWORD           ((target_flags & MASK_DWORD) != 0)
+#define TARGET_DOUBLE          ((target_flags & MASK_DOUBLE) != 0)
+#define TARGET_MEDIA           ((target_flags & MASK_MEDIA) != 0)
+#define TARGET_MULADD          ((target_flags & MASK_MULADD) != 0)
+#define TARGET_LIBPIC          ((target_flags & MASK_LIBPIC) != 0)
+#define TARGET_ACC_4           ((target_flags & MASK_ACC_4) != 0)
+#define TARGET_DEBUG_ARG       ((target_flags & MASK_DEBUG_ARG) != 0)
+#define TARGET_DEBUG_ADDR      ((target_flags & MASK_DEBUG_ADDR) != 0)
+#define TARGET_DEBUG_STACK     ((target_flags & MASK_DEBUG_STACK) != 0)
+#define TARGET_DEBUG           ((target_flags & MASK_DEBUG) != 0)
+#define TARGET_DEBUG_LOC       ((target_flags & MASK_DEBUG_LOC) != 0)
+#define TARGET_DEBUG_COND_EXEC ((target_flags & MASK_DEBUG_COND_EXEC) != 0)
+#define TARGET_NO_COND_MOVE    ((target_flags & MASK_NO_COND_MOVE) != 0)
+#define TARGET_NO_SCC          ((target_flags & MASK_NO_SCC) != 0)
+#define TARGET_NO_COND_EXEC    ((target_flags & MASK_NO_COND_EXEC) != 0)
+#define TARGET_NO_VLIW_BRANCH  ((target_flags & MASK_NO_VLIW_BRANCH) != 0)
+#define TARGET_NO_MULTI_CE     ((target_flags & MASK_NO_MULTI_CE) != 0)
+#define TARGET_NO_NESTED_CE    ((target_flags & MASK_NO_NESTED_CE) != 0)
+#define TARGET_PACK            ((target_flags & MASK_PACK) != 0)
+
+#define TARGET_GPR_64          (! TARGET_GPR_32)
+#define TARGET_FPR_64          (! TARGET_FPR_32)
+#define TARGET_HARD_FLOAT      (! TARGET_SOFT_FLOAT)
+#define TARGET_FIXED_CC                (! TARGET_ALLOC_CC)
+#define TARGET_COND_MOVE       (! TARGET_NO_COND_MOVE)
+#define TARGET_SCC             (! TARGET_NO_SCC)
+#define TARGET_COND_EXEC       (! TARGET_NO_COND_EXEC)
+#define TARGET_VLIW_BRANCH     (! TARGET_NO_VLIW_BRANCH)
+#define TARGET_MULTI_CE                (! TARGET_NO_MULTI_CE)
+#define TARGET_NESTED_CE       (! TARGET_NO_NESTED_CE)
+#define TARGET_ACC_8           (! TARGET_ACC_4)
+
+#define TARGET_HAS_FPRS                (TARGET_HARD_FLOAT || TARGET_MEDIA)
+
+#define NUM_GPRS               (TARGET_GPR_32? 32 : 64)
+#define NUM_FPRS               (!TARGET_HAS_FPRS? 0 : TARGET_FPR_32? 32 : 64)
+#define NUM_ACCS               (!TARGET_MEDIA? 0 : TARGET_ACC_4? 4 : 8)
+
+/* Macros to identify the blend of media instructions available.  Revision 1
+   is the one found on the FR500.  Revision 2 includes the changes made for
+   the FR400.
+
+   Treat the generic processor as a revision 1 machine for now, for
+   compatibility with earlier releases.  */
+
+#define TARGET_MEDIA_REV1                                      \
+  (TARGET_MEDIA                                                        \
+   && (frv_cpu_type == FRV_CPU_GENERIC                         \
+       || frv_cpu_type == FRV_CPU_FR500))
+
+#define TARGET_MEDIA_REV2                                      \
+  (TARGET_MEDIA && frv_cpu_type == FRV_CPU_FR400)
+
+/* This macro defines names of command options to set and clear bits in
+   `target_flags'.  Its definition is an initializer with a subgrouping for
+   each command option.
+
+   Each subgrouping contains a string constant, that defines the option name,
+   a number, which contains the bits to set in `target_flags', and an optional
+   second string which is the textual description that will be displayed when
+   the user passes --help on the command line.  If the number entry is negative
+   then the specified bits will be cleared instead of being set.  If the second
+   string entry is present but empty, then no help information will be displayed
+   for that option, but it will not count as an undocumented option.  The actual
+   option name, asseen on the command line is made by appending `-m' to the
+   specified name.
+
+   One of the subgroupings should have a null string.  The number in this
+   grouping is the default value for `target_flags'.  Any target options act
+   starting with that value.
+
+   Here is an example which defines `-m68000' and `-m68020' with opposite
+   meanings, and picks the latter as the default:
+
+        #define TARGET_SWITCHES \
+          { { "68020",  1, ""},      \
+            { "68000", -1, "Compile for the m68000"},     \
+            { "",       1, }}
+
+   This declaration must be present.  */
+
+#define TARGET_SWITCHES                                                            \
+{{ "gpr-32",             MASK_GPR_32,          "Only use 32 gprs"},        \
+ { "gpr-64",            -MASK_GPR_32,          "Use 64 gprs"},             \
+ { "fpr-32",             MASK_FPR_32,          "Only use 32 fprs"},        \
+ { "fpr-64",            -MASK_FPR_32,          "Use 64 fprs"},             \
+ { "hard-float",        -MASK_SOFT_FLOAT,      "Use hardware floating point" },\
+ { "soft-float",         MASK_SOFT_FLOAT,      "Use software floating point" },\
+ { "alloc-cc",           MASK_ALLOC_CC,        "Dynamically allocate cc's" }, \
+ { "fixed-cc",          -MASK_ALLOC_CC,        "Just use icc0/fcc0" },     \
+ { "dword",              MASK_DWORD,           "Change ABI to allow double word insns" }, \
+ { "no-dword",          -MASK_DWORD,           "Do not use double word insns" }, \
+ { "double",             MASK_DOUBLE,          "Use fp double instructions" }, \
+ { "no-double",                 -MASK_DOUBLE,          "Do not use fp double insns" }, \
+ { "media",              MASK_MEDIA,           "Use media instructions" }, \
+ { "no-media",          -MASK_MEDIA,           "Do not use media insns" }, \
+ { "muladd",             MASK_MULADD,          "Use multiply add/subtract instructions" }, \
+ { "no-muladd",                 -MASK_MULADD,          "Do not use multiply add/subtract insns" }, \
+ { "library-pic",        MASK_LIBPIC,          "PIC support for building libraries" }, \
+ { "acc-4",              MASK_ACC_4,           "Use 4 media accumulators" }, \
+ { "acc-8",             -MASK_ACC_4,           "Use 8 media accumulators" }, \
+ { "pack",               MASK_PACK,            "Pack VLIW instructions" }, \
+ { "no-pack",           -MASK_PACK,            "Do not pack VLIW instructions" }, \
+ { "no-eflags",                  0,                    "Do not mark ABI switches in e_flags" }, \
+ { "debug-arg",                  MASK_DEBUG_ARG,       "Internal debug switch" },  \
+ { "debug-addr",         MASK_DEBUG_ADDR,      "Internal debug switch" },  \
+ { "debug-stack",        MASK_DEBUG_STACK,     "Internal debug switch" },  \
+ { "debug",              MASK_DEBUG,           "Internal debug switch" },  \
+ { "debug-cond-exec",    MASK_DEBUG_COND_EXEC, "Internal debug switch" },  \
+ { "debug-loc",                  MASK_DEBUG_LOC,       "Internal debug switch" },  \
+ { "cond-move",                 -MASK_NO_COND_MOVE,    "Enable conditional moves" },  \
+ { "no-cond-move",       MASK_NO_COND_MOVE,    "Disable conditional moves" },  \
+ { "scc",               -MASK_NO_SCC,          "Enable setting gprs to the result of comparisons" },  \
+ { "no-scc",             MASK_NO_SCC,          "Disable setting gprs to the result of comparisons" },  \
+ { "cond-exec",                 -MASK_NO_COND_EXEC,    "Enable conditional execution other than moves/scc" }, \
+ { "no-cond-exec",       MASK_NO_COND_EXEC,    "Disable conditional execution other than moves/scc" }, \
+ { "vliw-branch",       -MASK_NO_VLIW_BRANCH,  "Run pass to pack branches into VLIW insns" }, \
+ { "no-vliw-branch",     MASK_NO_VLIW_BRANCH,  "Do not run pass to pack branches into VLIW insns" }, \
+ { "multi-cond-exec",   -MASK_NO_MULTI_CE,     "Disable optimizing &&/|| in conditional execution" }, \
+ { "no-multi-cond-exec",  MASK_NO_MULTI_CE,    "Enable optimizing &&/|| in conditional execution" }, \
+ { "nested-cond-exec",  -MASK_NO_NESTED_CE,    "Enable nested conditional execution optimizations" }, \
+ { "no-nested-cond-exec" ,MASK_NO_NESTED_CE,   "Disable nested conditional execution optimizations" }, \
+ { "tomcat-stats",       0,                    "Cause gas to print tomcat statistics" }, \
+ { "",                   MASK_DEFAULT,         "" }}                       \
+
+/* This macro is similar to `TARGET_SWITCHES' but defines names of command
+   options that have values.  Its definition is an initializer with a
+   subgrouping for each command option.
+
+   Each subgrouping contains a string constant, that defines the fixed part of
+   the option name, the address of a variable, and an optional description string.
+   The variable, of type `char *', is set to the text following the fixed part of
+   the option as it is specified on the command line.  The actual option name is
+   made by appending `-m' to the specified name.
+
+   Here is an example which defines `-mshort-data-NUMBER'.  If the given option
+   is `-mshort-data-512', the variable `m88k_short_data' will be set to the
+   string `"512"'.
+
+        extern char *m88k_short_data;
+        #define TARGET_OPTIONS \
+         { { "short-data-", & m88k_short_data, \
+        "Specify the size of the short data section"  } }
+
+   This declaration is optional.  */
+#define TARGET_OPTIONS                                                     \
+{                                                                          \
+  { "cpu=",            &frv_cpu_string,         "Set cpu type" },          \
+  { "branch-cost=",    &frv_branch_cost_string, "Internal debug switch" }, \
+  { "cond-exec-insns=", &frv_condexec_insns_str, "Internal debug switch" }, \
+  { "cond-exec-temps=", &frv_condexec_temps_str, "Internal debug switch" }, \
+  { "sched-lookahead=", &frv_sched_lookahead_str,"Internal debug switch" }, \
+}
+
+/* This macro is a C statement to print on `stderr' a string describing the
+   particular machine description choice.  Every machine description should
+   define `TARGET_VERSION'.  For example:
+
+        #ifdef MOTOROLA
+        #define TARGET_VERSION \
+          fprintf (stderr, " (68k, Motorola syntax)");
+        #else
+        #define TARGET_VERSION \
+          fprintf (stderr, " (68k, MIT syntax)");
+        #endif  */
+#define TARGET_VERSION fprintf (stderr, _(" (frv)"))
+
+/* Sometimes certain combinations of command options do not make sense on a
+   particular target machine.  You can define a macro `OVERRIDE_OPTIONS' to
+   take account of this.  This macro, if defined, is executed once just after
+   all the command options have been parsed.
+
+   Don't use this macro to turn on various extra optimizations for `-O'.  That
+   is what `OPTIMIZATION_OPTIONS' is for.  */
+
+#define OVERRIDE_OPTIONS frv_override_options ()
+
+/* Some machines may desire to change what optimizations are performed for
+   various optimization levels.  This macro, if defined, is executed once just
+   after the optimization level is determined and before the remainder of the
+   command options have been parsed.  Values set in this macro are used as the
+   default values for the other command line options.
+
+   LEVEL is the optimization level specified; 2 if `-O2' is specified, 1 if
+   `-O' is specified, and 0 if neither is specified.
+
+   SIZE is non-zero if `-Os' is specified, 0 otherwise.
+
+   You should not use this macro to change options that are not
+   machine-specific.  These should uniformly selected by the same optimization
+   level on all supported machines.  Use this macro to enable machbine-specific
+   optimizations.
+
+   *Do not examine `write_symbols' in this macro!* The debugging options are
+   *not supposed to alter the generated code.  */
+#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) frv_optimization_options (LEVEL, SIZE)
+
+
+/* Define this macro if debugging can be performed even without a frame
+   pointer.  If this macro is defined, GNU CC will turn on the
+   `-fomit-frame-pointer' option whenever `-O' is specified.  */
+/* Frv needs a specific frame layout that includes the frame pointer */
+
+#define CAN_DEBUG_WITHOUT_FP
+
+\f
+/* Small Data Area Support.  */
+/* Maximum size of variables that go in .sdata/.sbss.
+   The -msdata=foo switch also controls how small variables are handled.  */
+#ifndef SDATA_DEFAULT_SIZE
+#define SDATA_DEFAULT_SIZE 8
+#endif
+
+extern int g_switch_value;        /* value of the -G xx switch */
+extern int g_switch_set;          /* whether -G xx was passed.  */
+
+
+/* Storage Layout */
+
+/* Define this macro to have the value 1 if the most significant bit in a byte
+   has the lowest number; otherwise define it to have the value zero.  This
+   means that bit-field instructions count from the most significant bit.  If
+   the machine has no bit-field instructions, then this must still be defined,
+   but it doesn't matter which value it is defined to.  This macro need not be
+   a constant.
+
+   This macro does not affect the way structure fields are packed into bytes or
+   words; that is controlled by `BYTES_BIG_ENDIAN'.  */
+#define BITS_BIG_ENDIAN 1
+
+/* Define this macro to have the value 1 if the most significant byte in a word
+   has the lowest number.  This macro need not be a constant.  */
+#define BYTES_BIG_ENDIAN 1
+
+/* Define this macro to have the value 1 if, in a multiword object, the most
+   significant word has the lowest number.  This applies to both memory
+   locations and registers; GNU CC fundamentally assumes that the order of
+   words in memory is the same as the order in registers.  This macro need not
+   be a constant.  */
+#define WORDS_BIG_ENDIAN 1
+
+/* Number of storage units in a word; normally 4.  */
+#define UNITS_PER_WORD 4
+
+/* A macro to update MODE and UNSIGNEDP when an object whose type is TYPE and
+   which has the specified mode and signedness is to be stored in a register.
+   This macro is only called when TYPE is a scalar type.
+
+   On most RISC machines, which only have operations that operate on a full
+   register, define this macro to set M to `word_mode' if M is an integer mode
+   narrower than `BITS_PER_WORD'.  In most cases, only integer modes should be
+   widened because wider-precision floating-point operations are usually more
+   expensive than their narrower counterparts.
+
+   For most machines, the macro definition does not change UNSIGNEDP.  However,
+   some machines, have instructions that preferentially handle either signed or
+   unsigned quantities of certain modes.  For example, on the DEC Alpha, 32-bit
+   loads from memory and 32-bit add instructions sign-extend the result to 64
+   bits.  On such machines, set UNSIGNEDP according to which kind of extension
+   is more efficient.
+
+   Do not define this macro if it would never modify MODE.  */
+#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE)    \
+  do                                           \
+    {                                          \
+      if (GET_MODE_CLASS (MODE) == MODE_INT    \
+         && GET_MODE_SIZE (MODE) < 4)          \
+       (MODE) = SImode;                        \
+    }                                          \
+  while (0)
+
+/* Normal alignment required for function parameters on the stack, in bits.
+   All stack parameters receive at least this much alignment regardless of data
+   type.  On most machines, this is the same as the size of an integer.  */
+#define PARM_BOUNDARY 32
+
+/* Define this macro if you wish to preserve a certain alignment for the stack
+   pointer.  The definition is a C expression for the desired alignment
+   (measured in bits).
+
+   If `PUSH_ROUNDING' is not defined, the stack will always be aligned to the
+   specified boundary.  If `PUSH_ROUNDING' is defined and specifies a less
+   strict alignment than `STACK_BOUNDARY', the stack may be momentarily
+   unaligned while pushing arguments.  */
+#define STACK_BOUNDARY 64
+
+/* Alignment required for a function entry point, in bits.  */
+#define FUNCTION_BOUNDARY 128
+
+/* Biggest alignment that any data type can require on this machine,
+   in bits.  */
+#define BIGGEST_ALIGNMENT 64
+
+/* @@@ A hack, needed because libobjc wants to use ADJUST_FIELD_ALIGN for
+   some reason.  */
+#ifdef IN_TARGET_LIBS
+#define BIGGEST_FIELD_ALIGNMENT 64
+#else
+/* An expression for the alignment of a structure field FIELD if the
+   alignment computed in the usual way is COMPUTED.  GNU CC uses this
+   value instead of the value in `BIGGEST_ALIGNMENT' or
+   `BIGGEST_FIELD_ALIGNMENT', if defined, for structure fields only.  */
+#define ADJUST_FIELD_ALIGN(FIELD, COMPUTED)                            \
+  frv_adjust_field_align (FIELD, COMPUTED)
+#endif
+
+/* If defined, a C expression to compute the alignment for a static variable.
+   TYPE is the data type, and ALIGN is the alignment that the object
+   would ordinarily have.  The value of this macro is used instead of that
+   alignment to align the object.
+
+   If this macro is not defined, then ALIGN is used.
+
+   One use of this macro is to increase alignment of medium-size data to make
+   it all fit in fewer cache lines.  Another is to cause character arrays to be
+   word-aligned so that `strcpy' calls that copy constants to character arrays
+   can be done inline.  */
+#define DATA_ALIGNMENT(TYPE, ALIGN)            \
+  (TREE_CODE (TYPE) == ARRAY_TYPE              \
+   && TYPE_MODE (TREE_TYPE (TYPE)) == QImode   \
+   && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
+/* If defined, a C expression to compute the alignment given to a constant that
+   is being placed in memory.  CONSTANT is the constant and ALIGN is the
+   alignment that the object would ordinarily have.  The value of this macro is
+   used instead of that alignment to align the object.
+
+   If this macro is not defined, then ALIGN is used.
+
+   The typical use of this macro is to increase alignment for string constants
+   to be word aligned so that `strcpy' calls that copy constants can be done
+   inline.  */
+#define CONSTANT_ALIGNMENT(EXP, ALIGN)  \
+  (TREE_CODE (EXP) == STRING_CST       \
+   && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
+/* Define this macro to be the value 1 if instructions will fail to work if
+   given data not on the nominal alignment.  If instructions will merely go
+   slower in that case, define this macro as 0.  */
+#define STRICT_ALIGNMENT 1
+
+/* Define this if you wish to imitate the way many other C compilers handle
+   alignment of bitfields and the structures that contain them.
+
+   The behavior is that the type written for a bitfield (`int', `short', or
+   other integer type) imposes an alignment for the entire structure, as if the
+   structure really did contain an ordinary field of that type.  In addition,
+   the bitfield is placed within the structure so that it would fit within such
+   a field, not crossing a boundary for it.
+
+   Thus, on most machines, a bitfield whose type is written as `int' would not
+   cross a four-byte boundary, and would force four-byte alignment for the
+   whole structure.  (The alignment used may not be four bytes; it is
+   controlled by the other alignment parameters.)
+
+   If the macro is defined, its definition should be a C expression; a nonzero
+   value for the expression enables this behavior.
+
+   Note that if this macro is not defined, or its value is zero, some bitfields
+   may cross more than one alignment boundary.  The compiler can support such
+   references if there are `insv', `extv', and `extzv' insns that can directly
+   reference memory.
+
+   The other known way of making bitfields work is to define
+   `STRUCTURE_SIZE_BOUNDARY' as large as `BIGGEST_ALIGNMENT'.  Then every
+   structure can be accessed with fullwords.
+
+   Unless the machine has bitfield instructions or you define
+   `STRUCTURE_SIZE_BOUNDARY' that way, you must define
+   `PCC_BITFIELD_TYPE_MATTERS' to have a nonzero value.
+
+   If your aim is to make GNU CC use the same conventions for laying out
+   bitfields as are used by another compiler, here is how to investigate what
+   the other compiler does.  Compile and run this program:
+
+        struct foo1
+        {
+          char x;
+          char :0;
+          char y;
+        };
+
+        struct foo2
+        {
+          char x;
+          int :0;
+          char y;
+        };
+
+        main ()
+        {
+          printf ("Size of foo1 is %d\n",
+                  sizeof (struct foo1));
+          printf ("Size of foo2 is %d\n",
+                  sizeof (struct foo2));
+          exit (0);
+        }
+
+   If this prints 2 and 5, then the compiler's behavior is what you would get
+   from `PCC_BITFIELD_TYPE_MATTERS'.
+
+   Defined in svr4.h.  */
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+/* A code distinguishing the floating point format of the target machine.
+   There are three defined values:
+
+   IEEE_FLOAT_FORMAT'
+        This code indicates IEEE floating point.  It is the default;
+        there is no need to define this macro when the format is IEEE.
+
+   VAX_FLOAT_FORMAT'
+        This code indicates the peculiar format used on the Vax.
+
+   UNKNOWN_FLOAT_FORMAT'
+        This code indicates any other format.
+
+   The value of this macro is compared with `HOST_FLOAT_FORMAT'
+   to determine whether the target machine has the same format as
+   the host machine.  If any other formats are actually in use on supported
+   machines, new codes should be defined for them.
+
+   The ordering of the component words of floating point values stored in
+   memory is controlled by `FLOAT_WORDS_BIG_ENDIAN' for the target machine and
+   `HOST_FLOAT_WORDS_BIG_ENDIAN' for the host.  */
+#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT
+
+/* GNU CC supports two ways of implementing C++ vtables: traditional or with
+   so-called "thunks".  The flag `-fvtable-thunk' chooses between them.  Define
+   this macro to be a C expression for the default value of that flag.  If
+   `DEFAULT_VTABLE_THUNKS' is 0, GNU CC uses the traditional implementation by
+   default.  The "thunk" implementation is more efficient (especially if you
+   have provided an implementation of `ASM_OUTPUT_MI_THUNK', but is not binary
+   compatible with code compiled using the traditional implementation.  If you
+   are writing a new ports, define `DEFAULT_VTABLE_THUNKS' to 1.
+
+   If you do not define this macro, the default for `-fvtable-thunk' is 0.  */
+#define DEFAULT_VTABLE_THUNKS 1
+
+\f
+/* Layout of Source Language Data Types.  */
+
+#define CHAR_TYPE_SIZE         8
+#define SHORT_TYPE_SIZE       16
+#define INT_TYPE_SIZE         32
+#define LONG_TYPE_SIZE        32
+#define LONG_LONG_TYPE_SIZE   64
+#define FLOAT_TYPE_SIZE       32
+#define DOUBLE_TYPE_SIZE      64
+#define LONG_DOUBLE_TYPE_SIZE 64
+
+/* An expression whose value is 1 or 0, according to whether the type `char'
+   should be signed or unsigned by default.  The user can always override this
+   default with the options `-fsigned-char' and `-funsigned-char'.  */
+#define DEFAULT_SIGNED_CHAR 1
+
+\f
+/* General purpose registers.  */
+#define GPR_FIRST       0                       /* First gpr */
+#define GPR_LAST        (GPR_FIRST + 63)        /* Last gpr */
+#define GPR_R0          GPR_FIRST               /* R0, constant 0 */
+#define GPR_FP          (GPR_FIRST + 2)         /* Frame pointer */
+#define GPR_SP          (GPR_FIRST + 1)         /* Stack pointer */
+                                               /* small data register */
+#define SDA_BASE_REG    ((unsigned)(flag_pic ? PIC_REGNO : (GPR_FIRST+16)))
+#define PIC_REGNO       (GPR_FIRST + 17)        /* PIC register */
+
+#define FPR_FIRST       64                     /* First FP reg */
+#define FPR_LAST        127                    /* Last  FP reg */
+
+#define DEFAULT_CONDEXEC_TEMPS 4               /* reserve 4 regs by default */
+#define GPR_TEMP_NUM   frv_condexec_temps      /* # gprs to reserve for temps */
+
+/* We reserve the last CR and CCR in each category to be used as a reload
+   register to reload the CR/CCR registers.  This is a kludge.  */
+#define CC_FIRST       128                     /* First ICC/FCC reg */
+#define CC_LAST                135                     /* Last  ICC/FCC reg */
+#define ICC_FIRST      (CC_FIRST + 4)          /* First ICC reg */
+#define ICC_LAST       (CC_FIRST + 7)          /* Last  ICC reg */
+#define ICC_TEMP       (CC_FIRST + 7)          /* Temporary ICC reg */
+#define FCC_FIRST      (CC_FIRST)              /* First FCC reg */
+#define FCC_LAST       (CC_FIRST + 3)          /* Last  FCC reg */
+
+/* Amount to shift a value to locate a ICC or FCC register in the CCR
+   register and shift it to the bottom 4 bits.  */
+#define CC_SHIFT_RIGHT(REGNO) (((REGNO) - CC_FIRST) << 2)
+
+/* Mask to isolate a single ICC/FCC value.  */
+#define CC_MASK                0xf
+
+/* Masks to isolate the various bits in an ICC field.  */
+#define ICC_MASK_N     0x8     /* negative */
+#define ICC_MASK_Z     0x4     /* zero */
+#define ICC_MASK_V     0x2     /* overflow */
+#define ICC_MASK_C     0x1     /* carry */
+
+/* Mask to isolate the N/Z flags in an ICC.  */
+#define ICC_MASK_NZ (ICC_MASK_N | ICC_MASK_Z)
+
+/* Mask to isolate the Z/C flags in an ICC.  */
+#define ICC_MASK_ZC (ICC_MASK_Z | ICC_MASK_C)
+
+/* Masks to isolate the various bits in a FCC field.  */
+#define FCC_MASK_E     0x8     /* equal */
+#define FCC_MASK_L     0x4     /* less than */
+#define FCC_MASK_G     0x2     /* greater than */
+#define FCC_MASK_U     0x1     /* unordered */
+
+/* For CCR registers, the machine wants CR4..CR7 to be used for integer
+   code and CR0..CR3 to be used for floating point.  */
+#define CR_FIRST       136                     /* First CCR */
+#define CR_LAST                143                     /* Last  CCR */
+#define CR_NUM         (CR_LAST-CR_FIRST+1)    /* # of CCRs (8) */
+#define ICR_FIRST      (CR_FIRST + 4)          /* First integer CCR */
+#define ICR_LAST       (CR_FIRST + 7)          /* Last  integer CCR */
+#define ICR_TEMP       ICR_LAST                /* Temp  integer CCR */
+#define FCR_FIRST      (CR_FIRST + 0)          /* First float CCR */
+#define FCR_LAST       (CR_FIRST + 3)          /* Last  float CCR */
+
+/* Amount to shift a value to locate a CR register in the CCCR special purpose
+   register and shift it to the bottom 2 bits.  */
+#define CR_SHIFT_RIGHT(REGNO) (((REGNO) - CR_FIRST) << 1)
+
+/* Mask to isolate a single CR value.  */
+#define CR_MASK                0x3
+
+#define ACC_FIRST      144                     /* First acc register */
+#define ACC_LAST       151                     /* Last  acc register */
+
+#define ACCG_FIRST     152                     /* First accg register */
+#define ACCG_LAST      159                     /* Last  accg register */
+
+#define AP_FIRST       160                     /* fake argument pointer */
+
+#define SPR_FIRST      161
+#define SPR_LAST       162
+#define LR_REGNO       (SPR_FIRST)
+#define LCR_REGNO      (SPR_FIRST + 1)
+
+#define GPR_P(R)       IN_RANGE_P (R, GPR_FIRST, GPR_LAST)
+#define GPR_OR_AP_P(R) (GPR_P (R) || (R) == ARG_POINTER_REGNUM)
+#define FPR_P(R)       IN_RANGE_P (R, FPR_FIRST, FPR_LAST)
+#define CC_P(R)                IN_RANGE_P (R, CC_FIRST, CC_LAST)
+#define ICC_P(R)       IN_RANGE_P (R, ICC_FIRST, ICC_LAST)
+#define FCC_P(R)       IN_RANGE_P (R, FCC_FIRST, FCC_LAST)
+#define CR_P(R)                IN_RANGE_P (R, CR_FIRST, CR_LAST)
+#define ICR_P(R)       IN_RANGE_P (R, ICR_FIRST, ICR_LAST)
+#define FCR_P(R)       IN_RANGE_P (R, FCR_FIRST, FCR_LAST)
+#define ACC_P(R)       IN_RANGE_P (R, ACC_FIRST, ACC_LAST)
+#define ACCG_P(R)      IN_RANGE_P (R, ACCG_FIRST, ACCG_LAST)
+#define SPR_P(R)       IN_RANGE_P (R, SPR_FIRST, SPR_LAST)
+
+#define GPR_OR_PSEUDO_P(R)     (GPR_P (R) || (R) >= FIRST_PSEUDO_REGISTER)
+#define FPR_OR_PSEUDO_P(R)     (FPR_P (R) || (R) >= FIRST_PSEUDO_REGISTER)
+#define GPR_AP_OR_PSEUDO_P(R)  (GPR_OR_AP_P (R) || (R) >= FIRST_PSEUDO_REGISTER)
+#define CC_OR_PSEUDO_P(R)      (CC_P (R) || (R) >= FIRST_PSEUDO_REGISTER)
+#define ICC_OR_PSEUDO_P(R)     (ICC_P (R) || (R) >= FIRST_PSEUDO_REGISTER)
+#define FCC_OR_PSEUDO_P(R)     (FCC_P (R) || (R) >= FIRST_PSEUDO_REGISTER)
+#define CR_OR_PSEUDO_P(R)      (CR_P (R) || (R) >= FIRST_PSEUDO_REGISTER)
+#define ICR_OR_PSEUDO_P(R)     (ICR_P (R) || (R) >= FIRST_PSEUDO_REGISTER)
+#define FCR_OR_PSEUDO_P(R)     (FCR_P (R) || (R) >= FIRST_PSEUDO_REGISTER)
+#define ACC_OR_PSEUDO_P(R)     (ACC_P (R) || (R) >= FIRST_PSEUDO_REGISTER)
+#define ACCG_OR_PSEUDO_P(R)    (ACCG_P (R) || (R) >= FIRST_PSEUDO_REGISTER)
+
+#define MAX_STACK_IMMEDIATE_OFFSET 2047
+
+\f
+/* Register Basics.  */
+
+/* Number of hardware registers known to the compiler.  They receive numbers 0
+   through `FIRST_PSEUDO_REGISTER-1'; thus, the first pseudo register's number
+   really is assigned the number `FIRST_PSEUDO_REGISTER'.  */
+#define FIRST_PSEUDO_REGISTER (SPR_LAST + 1)
+
+/* The first/last register that can contain the arguments to a function.  */
+#define FIRST_ARG_REGNUM       (GPR_FIRST + 8)
+#define LAST_ARG_REGNUM                (FIRST_ARG_REGNUM + FRV_NUM_ARG_REGS - 1)
+
+/* Registers used by the exception handling functions.  These should be
+   registers that are not otherwised used by the calling sequence.  */
+#define FIRST_EH_REGNUM                14
+#define LAST_EH_REGNUM         15
+
+/* Scratch registers used in the prologue, epilogue and thunks.
+   OFFSET_REGNO is for loading constant addends that are too big for a
+   single instruction.  TEMP_REGNO is used for transferring SPRs to and from
+   the stack, and various other activities.  */
+#define OFFSET_REGNO           4
+#define TEMP_REGNO             5
+
+/* Registers used in the prologue.  OLD_SP_REGNO is the old stack pointer,
+   which is sometimes used to set up the frame pointer.  */
+#define OLD_SP_REGNO           6
+
+/* Registers used in the epilogue.  STACKADJ_REGNO stores the exception
+   handler's stack adjustment.  */
+#define STACKADJ_REGNO         6
+
+/* Registers used in thunks.  JMP_REGNO is used for loading the target
+   address.  */
+#define JUMP_REGNO             6
+
+#define EH_RETURN_DATA_REGNO(N)        ((N) <= (LAST_EH_REGNUM - FIRST_EH_REGNUM)? \
+                                (N) + FIRST_EH_REGNUM : INVALID_REGNUM)
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (SImode, STACKADJ_REGNO)
+#define EH_RETURN_HANDLER_RTX   RETURN_ADDR_RTX (0, frame_pointer_rtx)
+
+/* An initializer that says which registers are used for fixed purposes all
+   throughout the compiled code and are therefore not available for general
+   allocation.  These would include the stack pointer, the frame pointer
+   (except on machines where that can be used as a general register when no
+   frame pointer is needed), the program counter on machines where that is
+   considered one of the addressable registers, and any other numbered register
+   with a standard use.
+
+   This information is expressed as a sequence of numbers, separated by commas
+   and surrounded by braces.  The Nth number is 1 if register N is fixed, 0
+   otherwise.
+
+   The table initialized from this macro, and the table initialized by the
+   following one, may be overridden at run time either automatically, by the
+   actions of the macro `CONDITIONAL_REGISTER_USAGE', or by the user with the
+   command options `-ffixed-REG', `-fcall-used-REG' and `-fcall-saved-REG'.  */
+
+/* gr0  -- Hard Zero
+   gr1  -- Stack Pointer
+   gr2  -- Frame Pointer
+   gr3  -- Hidden Parameter
+   gr16 -- Small Data reserved
+   gr17 -- Pic reserved
+   gr28 -- OS reserved
+   gr29 -- OS reserved
+   gr30 -- OS reserved
+   gr31 -- OS reserved
+   cr3  -- reserved to reload FCC registers.
+   cr7  -- reserved to reload ICC registers.  */
+#define FIXED_REGISTERS                                                        \
+{      /* Integer Registers */                                         \
+       1, 1, 1, 1, 0, 0, 0, 0,         /* 000-007, gr0  - gr7  */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 008-015, gr8  - gr15 */      \
+       1, 1, 0, 0, 0, 0, 0, 0,         /* 016-023, gr16 - gr23 */      \
+       0, 0, 0, 0, 1, 1, 1, 1,         /* 024-031, gr24 - gr31 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 032-039, gr32 - gr39 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 040-040, gr48 - gr47 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 048-055, gr48 - gr55 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 056-063, gr56 - gr63 */      \
+       /* Float Registers */                                           \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 064-071, fr0  - fr7  */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 072-079, fr8  - fr15 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 080-087, fr16 - fr23 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 088-095, fr24 - fr31 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 096-103, fr32 - fr39 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 104-111, fr48 - fr47 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 112-119, fr48 - fr55 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 120-127, fr56 - fr63 */      \
+       /* Condition Code Registers */                                  \
+       0, 0, 0, 0,                     /* 128-131, fcc0 - fcc3  */     \
+       0, 0, 0, 1,                     /* 132-135, icc0 - icc3 */      \
+       /* Conditional execution Registers (CCR) */                     \
+       0, 0, 0, 0, 0, 0, 0, 1,         /* 136-143, cr0 - cr7 */        \
+       /* Accumulators */                                              \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 144-151, acc0  - acc7 */     \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 152-159, accg0 - accg7 */    \
+       /* Other registers */                                           \
+       1,                              /* 160, AP   - fake arg ptr */  \
+       0,                              /* 161, LR   - Link register*/  \
+       0,                              /* 162, LCR  - Loop count reg*/ \
+}
+
+/* Like `FIXED_REGISTERS' but has 1 for each register that is clobbered (in
+   general) by function calls as well as for fixed registers.  This macro
+   therefore identifies the registers that are not available for general
+   allocation of values that must live across function calls.
+
+   If a register has 0 in `CALL_USED_REGISTERS', the compiler automatically
+   saves it on function entry and restores it on function exit, if the register
+   is used within the function.  */
+#define CALL_USED_REGISTERS                                            \
+{      /* Integer Registers */                                         \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 000-007, gr0  - gr7  */      \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 008-015, gr8  - gr15 */      \
+       1, 1, 0, 0, 0, 0, 0, 0,         /* 016-023, gr16 - gr23 */      \
+       0, 0, 0, 0, 1, 1, 1, 1,         /* 024-031, gr24 - gr31 */      \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 032-039, gr32 - gr39 */      \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 040-040, gr48 - gr47 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 048-055, gr48 - gr55 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 056-063, gr56 - gr63 */      \
+       /* Float Registers */                                           \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 064-071, fr0  - fr7  */      \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 072-079, fr8  - fr15 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 080-087, fr16 - fr23 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 088-095, fr24 - fr31 */      \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 096-103, fr32 - fr39 */      \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 104-111, fr48 - fr47 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 112-119, fr48 - fr55 */      \
+       0, 0, 0, 0, 0, 0, 0, 0,         /* 120-127, fr56 - fr63 */      \
+       /* Condition Code Registers */                                  \
+       1, 1, 1, 1,                     /* 128-131, fcc0 - fcc3 */      \
+       1, 1, 1, 1,                     /* 132-135, icc0 - icc3  */     \
+       /* Conditional execution Registers (CCR) */                     \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 136-143, cr0 - cr7 */        \
+       /* Accumulators */                                              \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 144-151, acc0 - acc7 */      \
+       1, 1, 1, 1, 1, 1, 1, 1,         /* 152-159, accg0 - accg7 */    \
+       /* Other registers */                                           \
+       1,                              /* 160, AP  - fake arg ptr */   \
+       1,                              /* 161, LR  - Link register*/   \
+       1,                              /* 162, LCR - Loop count reg */ \
+}
+
+/* Zero or more C statements that may conditionally modify two variables
+   `fixed_regs' and `call_used_regs' (both of type `char []') after they have
+   been initialized from the two preceding macros.
+
+   This is necessary in case the fixed or call-clobbered registers depend on
+   target flags.
+
+   You need not define this macro if it has no work to do.
+
+   If the usage of an entire class of registers depends on the target flags,
+   you may indicate this to GCC by using this macro to modify `fixed_regs' and
+   `call_used_regs' to 1 for each of the registers in the classes which should
+   not be used by GCC.  Also define the macro `REG_CLASS_FROM_LETTER' to return
+   `NO_REGS' if it is called with a letter for a class that shouldn't be used.
+
+   (However, if this class is not included in `GENERAL_REGS' and all of the
+   insn patterns whose constraints permit this class are controlled by target
+   switches, then GCC will automatically avoid using these registers when the
+   target switches are opposed to them.)  */
+
+#define CONDITIONAL_REGISTER_USAGE frv_conditional_register_usage ()
+
+\f
+/* Order of allocation of registers.  */
+
+/* If defined, an initializer for a vector of integers, containing the numbers
+   of hard registers in the order in which GNU CC should prefer to use them
+   (from most preferred to least).
+
+   If this macro is not defined, registers are used lowest numbered first (all
+   else being equal).
+
+   One use of this macro is on machines where the highest numbered registers
+   must always be saved and the save-multiple-registers instruction supports
+   only sequences of consecutive registers.  On such machines, define
+   `REG_ALLOC_ORDER' to be an initializer that lists the highest numbered
+   allocatable register first.  */
+
+/* On the FRV, allocate GR16 and GR17 after other saved registers so that we
+   have a better chance of allocating 2 registers at a time and can use the
+   double word load/store instructions in the prologue.  */
+#define REG_ALLOC_ORDER                                                        \
+{                                                                      \
+  /* volatile registers */                                             \
+  GPR_FIRST  +  4, GPR_FIRST  +  5, GPR_FIRST  +  6, GPR_FIRST         +  7,   \
+  GPR_FIRST  +  8, GPR_FIRST  +  9, GPR_FIRST  + 10, GPR_FIRST         + 11,   \
+  GPR_FIRST  + 12, GPR_FIRST  + 13, GPR_FIRST  + 14, GPR_FIRST         + 15,   \
+  GPR_FIRST  + 32, GPR_FIRST  + 33, GPR_FIRST  + 34, GPR_FIRST         + 35,   \
+  GPR_FIRST  + 36, GPR_FIRST  + 37, GPR_FIRST  + 38, GPR_FIRST         + 39,   \
+  GPR_FIRST  + 40, GPR_FIRST  + 41, GPR_FIRST  + 42, GPR_FIRST         + 43,   \
+  GPR_FIRST  + 44, GPR_FIRST  + 45, GPR_FIRST  + 46, GPR_FIRST         + 47,   \
+                                                                       \
+  FPR_FIRST  +  0, FPR_FIRST  +  1, FPR_FIRST  +  2, FPR_FIRST         +  3,   \
+  FPR_FIRST  +  4, FPR_FIRST  +  5, FPR_FIRST  +  6, FPR_FIRST         +  7,   \
+  FPR_FIRST  +  8, FPR_FIRST  +  9, FPR_FIRST  + 10, FPR_FIRST         + 11,   \
+  FPR_FIRST  + 12, FPR_FIRST  + 13, FPR_FIRST  + 14, FPR_FIRST         + 15,   \
+  FPR_FIRST  + 32, FPR_FIRST  + 33, FPR_FIRST  + 34, FPR_FIRST         + 35,   \
+  FPR_FIRST  + 36, FPR_FIRST  + 37, FPR_FIRST  + 38, FPR_FIRST         + 39,   \
+  FPR_FIRST  + 40, FPR_FIRST  + 41, FPR_FIRST  + 42, FPR_FIRST         + 43,   \
+  FPR_FIRST  + 44, FPR_FIRST  + 45, FPR_FIRST  + 46, FPR_FIRST         + 47,   \
+                                                                       \
+  ICC_FIRST  +  0, ICC_FIRST  +  1, ICC_FIRST  +  2, ICC_FIRST         +  3,   \
+  FCC_FIRST  +  0, FCC_FIRST  +  1, FCC_FIRST  +  2, FCC_FIRST         +  3,   \
+  CR_FIRST   +  0, CR_FIRST   +  1, CR_FIRST   +  2, CR_FIRST          +  3,   \
+  CR_FIRST   +  4, CR_FIRST   +  5, CR_FIRST   +  6, CR_FIRST          +  7,   \
+                                                                       \
+  /* saved registers */                                                        \
+  GPR_FIRST  + 18, GPR_FIRST  + 19,                                    \
+  GPR_FIRST  + 20, GPR_FIRST  + 21, GPR_FIRST  + 22, GPR_FIRST         + 23,   \
+  GPR_FIRST  + 24, GPR_FIRST  + 25, GPR_FIRST  + 26, GPR_FIRST         + 27,   \
+  GPR_FIRST  + 48, GPR_FIRST  + 49, GPR_FIRST  + 50, GPR_FIRST         + 51,   \
+  GPR_FIRST  + 52, GPR_FIRST  + 53, GPR_FIRST  + 54, GPR_FIRST         + 55,   \
+  GPR_FIRST  + 56, GPR_FIRST  + 57, GPR_FIRST  + 58, GPR_FIRST         + 59,   \
+  GPR_FIRST  + 60, GPR_FIRST  + 61, GPR_FIRST  + 62, GPR_FIRST         + 63,   \
+  GPR_FIRST  + 16, GPR_FIRST  + 17,                                    \
+                                                                       \
+  FPR_FIRST  + 16, FPR_FIRST  + 17, FPR_FIRST  + 18, FPR_FIRST         + 19,   \
+  FPR_FIRST  + 20, FPR_FIRST  + 21, FPR_FIRST  + 22, FPR_FIRST         + 23,   \
+  FPR_FIRST  + 24, FPR_FIRST  + 25, FPR_FIRST  + 26, FPR_FIRST         + 27,   \
+  FPR_FIRST  + 28, FPR_FIRST  + 29, FPR_FIRST  + 30, FPR_FIRST         + 31,   \
+  FPR_FIRST  + 48, FPR_FIRST  + 49, FPR_FIRST  + 50, FPR_FIRST         + 51,   \
+  FPR_FIRST  + 52, FPR_FIRST  + 53, FPR_FIRST  + 54, FPR_FIRST         + 55,   \
+  FPR_FIRST  + 56, FPR_FIRST  + 57, FPR_FIRST  + 58, FPR_FIRST         + 59,   \
+  FPR_FIRST  + 60, FPR_FIRST  + 61, FPR_FIRST  + 62, FPR_FIRST         + 63,   \
+                                                                       \
+  /* special or fixed registers */                                     \
+  GPR_FIRST  +  0, GPR_FIRST  +  1, GPR_FIRST  +  2, GPR_FIRST         +  3,   \
+  GPR_FIRST  + 28, GPR_FIRST  + 29, GPR_FIRST  + 30, GPR_FIRST         + 31,   \
+  ACC_FIRST  +  0, ACC_FIRST  +  1, ACC_FIRST  +  2, ACC_FIRST         +  3,   \
+  ACC_FIRST  +  4, ACC_FIRST  +  5, ACC_FIRST  +  6, ACC_FIRST         +  7,   \
+  ACCG_FIRST +  0, ACCG_FIRST +  1, ACCG_FIRST +  2, ACCG_FIRST        +  3,   \
+  ACCG_FIRST +  4, ACCG_FIRST +  5, ACCG_FIRST +  6, ACCG_FIRST        +  7,   \
+  AP_FIRST,       LR_REGNO,       LCR_REGNO                            \
+}
+
+\f
+/* How Values Fit in Registers.  */
+
+/* A C expression for the number of consecutive hard registers, starting at
+   register number REGNO, required to hold a value of mode MODE.
+
+   On a machine where all registers are exactly one word, a suitable definition
+   of this macro is
+
+        #define HARD_REGNO_NREGS(REGNO, MODE)            \
+           ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1)  \
+            / UNITS_PER_WORD))  */
+
+/* On the FRV, make the CC modes take 3 words in the integer registers, so that
+   we can build the appropriate instructions to properly reload the values.  */
+#define HARD_REGNO_NREGS(REGNO, MODE) frv_hard_regno_nregs (REGNO, MODE)
+
+/* A C expression that is nonzero if it is permissible to store a value of mode
+   MODE in hard register number REGNO (or in several registers starting with
+   that one).  For a machine where all registers are equivalent, a suitable
+   definition is
+
+        #define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+
+   It is not necessary for this macro to check for the numbers of fixed
+   registers, because the allocation mechanism considers them to be always
+   occupied.
+
+   On some machines, double-precision values must be kept in even/odd register
+   pairs.  The way to implement that is to define this macro to reject odd
+   register numbers for such modes.
+
+   The minimum requirement for a mode to be OK in a register is that the
+   `movMODE' instruction pattern support moves between the register and any
+   other hard register for which the mode is OK; and that moving a value into
+   the register and back out not alter it.
+
+   Since the same instruction used to move `SImode' will work for all narrower
+   integer modes, it is not necessary on any machine for `HARD_REGNO_MODE_OK'
+   to distinguish between these modes, provided you define patterns `movhi',
+   etc., to take advantage of this.  This is useful because of the interaction
+   between `HARD_REGNO_MODE_OK' and `MODES_TIEABLE_P'; it is very desirable for
+   all integer modes to be tieable.
+
+   Many machines have special registers for floating point arithmetic.  Often
+   people assume that floating point machine modes are allowed only in floating
+   point registers.  This is not true.  Any registers that can hold integers
+   can safely *hold* a floating point machine mode, whether or not floating
+   arithmetic can be done on it in those registers.  Integer move instructions
+   can be used to move the values.
+
+   On some machines, though, the converse is true: fixed-point machine modes
+   may not go in floating registers.  This is true if the floating registers
+   normalize any value stored in them, because storing a non-floating value
+   there would garble it.  In this case, `HARD_REGNO_MODE_OK' should reject
+   fixed-point machine modes in floating registers.  But if the floating
+   registers do not automatically normalize, if you can store any bit pattern
+   in one and retrieve it unchanged without a trap, then any machine mode may
+   go in a floating register, so you can define this macro to say so.
+
+   The primary significance of special floating registers is rather that they
+   are the registers acceptable in floating point arithmetic instructions.
+   However, this is of no concern to `HARD_REGNO_MODE_OK'.  You handle it by
+   writing the proper constraints for those instructions.
+
+   On some machines, the floating registers are especially slow to access, so
+   that it is better to store a value in a stack frame than in such a register
+   if floating point arithmetic is not being done.  As long as the floating
+   registers are not in class `GENERAL_REGS', they will not be used unless some
+   pattern's constraint asks for one.  */
+#define HARD_REGNO_MODE_OK(REGNO, MODE) frv_hard_regno_mode_ok (REGNO, MODE)
+
+/* A C expression that is nonzero if it is desirable to choose register
+   allocation so as to avoid move instructions between a value of mode MODE1
+   and a value of mode MODE2.
+
+   If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R, MODE2)' are
+   ever different for any R, then `MODES_TIEABLE_P (MODE1, MODE2)' must be
+   zero.  */
+#define MODES_TIEABLE_P(MODE1, MODE2) (MODE1 == MODE2)
+
+/* Define this macro if the compiler should avoid copies to/from CCmode
+   registers.  You should only define this macro if support fo copying to/from
+   CCmode is incomplete.  */
+#define AVOID_CCMODE_COPIES
+
+\f
+/* Register Classes.  */
+
+/* An enumeral type that must be defined with all the register class names as
+   enumeral values.  `NO_REGS' must be first.  `ALL_REGS' must be the last
+   register class, followed by one more enumeral value, `LIM_REG_CLASSES',
+   which is not a register class but rather tells how many classes there are.
+
+   Each register class has a number, which is the value of casting the class
+   name to type `int'.  The number serves as an index in many of the tables
+   described below.  */
+enum reg_class
+{
+  NO_REGS,
+  ICC_REGS,
+  FCC_REGS,
+  CC_REGS,
+  ICR_REGS,
+  FCR_REGS,
+  CR_REGS,
+  LCR_REG,
+  LR_REG,
+  SPR_REGS,
+  QUAD_ACC_REGS,
+  EVEN_ACC_REGS,
+  ACC_REGS,
+  ACCG_REGS,
+  QUAD_FPR_REGS,
+  FEVEN_REGS,
+  FPR_REGS,
+  QUAD_REGS,
+  EVEN_REGS,
+  GPR_REGS,
+  ALL_REGS,
+  LIM_REG_CLASSES
+};
+
+#define GENERAL_REGS GPR_REGS
+
+/* The number of distinct register classes, defined as follows:
+
+        #define N_REG_CLASSES (int) LIM_REG_CLASSES  */
+#define N_REG_CLASSES ((int) LIM_REG_CLASSES)
+
+/* An initializer containing the names of the register classes as C string
+   constants.  These names are used in writing some of the debugging dumps.  */
+#define REG_CLASS_NAMES {                                              \
+   "NO_REGS",                                                          \
+   "ICC_REGS",                                                         \
+   "FCC_REGS",                                                         \
+   "CC_REGS",                                                          \
+   "ICR_REGS",                                                         \
+   "FCR_REGS",                                                         \
+   "CR_REGS",                                                          \
+   "LCR_REG",                                                          \
+   "LR_REG",                                                           \
+   "SPR_REGS",                                                         \
+   "QUAD_ACC_REGS",                                                    \
+   "EVEN_ACC_REGS",                                                    \
+   "ACC_REGS",                                                         \
+   "ACCG_REGS",                                                                \
+   "QUAD_FPR_REGS",                                                    \
+   "FEVEN_REGS",                                                       \
+   "FPR_REGS",                                                         \
+   "QUAD_REGS",                                                                \
+   "EVEN_REGS",                                                                \
+   "GPR_REGS",                                                         \
+   "ALL_REGS"                                                          \
+}
+
+/* An initializer containing the contents of the register classes, as integers
+   which are bit masks.  The Nth integer specifies the contents of class N.
+   The way the integer MASK is interpreted is that register R is in the class
+   if `MASK & (1 << R)' is 1.
+
+   When the machine has more than 32 registers, an integer does not suffice.
+   Then the integers are replaced by sub-initializers, braced groupings
+   containing several integers.  Each sub-initializer must be suitable as an
+   initializer for the type `HARD_REG_SET' which is defined in
+   `hard-reg-set.h'.  */
+#define REG_CLASS_CONTENTS                                                    \
+{  /* gr0-gr31 gr32-gr63  fr0-fr31   fr32-fr-63 cc/ccr/acc ap/spr */          \
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x0}, /* NO_REGS  */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x000000f0,0x0}, /* ICC_REGS */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x0000000f,0x0}, /* FCC_REGS */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x000000ff,0x0}, /* CC_REGS  */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x0000f000,0x0}, /* ICR_REGS */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000f00,0x0}, /* FCR_REGS */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x0000ff00,0x0}, /* CR_REGS  */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x4}, /* LCR_REGS */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x2}, /* LR_REGS  */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x6}, /* SPR_REGS */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x00ff0000,0x0}, /* QUAD_ACC */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x00ff0000,0x0}, /* EVEN_ACC */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0x00ff0000,0x0}, /* ACC_REGS */\
+  { 0x00000000,0x00000000,0x00000000,0x00000000,0xff000000,0x0}, /* ACCG_REGS*/\
+  { 0x00000000,0x00000000,0xffffffff,0xffffffff,0x00000000,0x0}, /* QUAD_FPR */\
+  { 0x00000000,0x00000000,0xffffffff,0xffffffff,0x00000000,0x0}, /* FEVEN_REG*/\
+  { 0x00000000,0x00000000,0xffffffff,0xffffffff,0x00000000,0x0}, /* FPR_REGS */\
+  { 0x0ffffffc,0xffffffff,0x00000000,0x00000000,0x00000000,0x0}, /* QUAD_REGS*/\
+  { 0xfffffffc,0xffffffff,0x00000000,0x00000000,0x00000000,0x0}, /* EVEN_REGS*/\
+  { 0xffffffff,0xffffffff,0x00000000,0x00000000,0x00000000,0x1}, /* GPR_REGS */\
+  { 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0x7}, /* ALL_REGS */\
+}
+
+/* A C expression whose value is a register class containing hard register
+   REGNO.  In general there is more than one such class; choose a class which
+   is "minimal", meaning that no smaller class also contains the register.  */
+
+extern enum reg_class regno_reg_class[];
+#define REGNO_REG_CLASS(REGNO) regno_reg_class [REGNO]
+
+/* A macro whose definition is the name of the class to which a valid base
+   register must belong.  A base register is one used in an address which is
+   the register value plus a displacement.  */
+#define BASE_REG_CLASS GPR_REGS
+
+/* A macro whose definition is the name of the class to which a valid index
+   register must belong.  An index register is one used in an address where its
+   value is either multiplied by a scale factor or added to another register
+   (as well as added to a displacement).  */
+#define INDEX_REG_CLASS GPR_REGS
+
+/* A C expression which defines the machine-dependent operand constraint
+   letters for register classes.  If CHAR is such a letter, the value should be
+   the register class corresponding to it.  Otherwise, the value should be
+   `NO_REGS'.  The register letter `r', corresponding to class `GENERAL_REGS',
+   will not be passed to this macro; you do not need to handle it.
+
+   The following letters are unavailable, due to being used as
+   constraints:
+       '0'..'9'
+       '<', '>'
+       'E', 'F', 'G', 'H'
+       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P'
+       'Q', 'R', 'S', 'T', 'U'
+       'V', 'X'
+       'g', 'i', 'm', 'n', 'o', 'p', 'r', 's' */
+
+extern enum reg_class reg_class_from_letter[];
+#define REG_CLASS_FROM_LETTER(CHAR) reg_class_from_letter [CHAR]
+
+/* A C expression which is nonzero if register number NUM is suitable for use
+   as a base register in operand addresses.  It may be either a suitable hard
+   register or a pseudo register that has been allocated such a hard register.  */
+#define REGNO_OK_FOR_BASE_P(NUM)           \
+  ((NUM) < FIRST_PSEUDO_REGISTER           \
+   ? GPR_P (NUM)                           \
+   : (reg_renumber [NUM] >= 0 && GPR_P (reg_renumber [NUM])))
+
+/* A C expression which is nonzero if register number NUM is suitable for use
+   as an index register in operand addresses.  It may be either a suitable hard
+   register or a pseudo register that has been allocated such a hard register.
+
+   The difference between an index register and a base register is that the
+   index register may be scaled.  If an address involves the sum of two
+   registers, neither one of them scaled, then either one may be labeled the
+   "base" and the other the "index"; but whichever labeling is used must fit
+   the machine's constraints of which registers may serve in each capacity.
+   The compiler will try both labelings, looking for one that is valid, and
+   will reload one or both registers only if neither labeling works.  */
+#define REGNO_OK_FOR_INDEX_P(NUM)                                       \
+  ((NUM) < FIRST_PSEUDO_REGISTER                                        \
+   ? GPR_P (NUM)                                                        \
+   : (reg_renumber [NUM] >= 0 && GPR_P (reg_renumber [NUM])))
+
+/* A C expression that places additional restrictions on the register class to
+   use when it is necessary to copy value X into a register in class CLASS.
+   The value is a register class; perhaps CLASS, or perhaps another, smaller
+   class.  On many machines, the following definition is safe:
+
+        #define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS
+
+   Sometimes returning a more restrictive class makes better code.  For
+   example, on the 68000, when X is an integer constant that is in range for a
+   `moveq' instruction, the value of this macro is always `DATA_REGS' as long
+   as CLASS includes the data registers.  Requiring a data register guarantees
+   that a `moveq' will be used.
+
+   If X is a `const_double', by returning `NO_REGS' you can force X into a
+   memory constant.  This is useful on certain machines where immediate
+   floating values cannot be loaded into certain kinds of registers.
+
+   This declaration must be present.  */
+#define PREFERRED_RELOAD_CLASS(X, CLASS) CLASS
+
+#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) \
+  frv_secondary_reload_class (CLASS, MODE, X, TRUE)
+
+#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X) \
+  frv_secondary_reload_class (CLASS, MODE, X, FALSE)
+
+/* A C expression whose value is nonzero if pseudos that have been assigned to
+   registers of class CLASS would likely be spilled because registers of CLASS
+   are needed for spill registers.
+
+   The default value of this macro returns 1 if CLASS has exactly one register
+   and zero otherwise.  On most machines, this default should be used.  Only
+   define this macro to some other expression if pseudo allocated by
+   `local-alloc.c' end up in memory because their hard registers were needed
+   for spill registers.  If this macro returns nonzero for those classes, those
+   pseudos will only be allocated by `global.c', which knows how to reallocate
+   the pseudo to another register.  If there would not be another register
+   available for reallocation, you should not change the definition of this
+   macro since the only effect of such a definition would be to slow down
+   register allocation.  */
+#define CLASS_LIKELY_SPILLED_P(CLASS) frv_class_likely_spilled_p (CLASS)
+
+/* A C expression for the maximum number of consecutive registers of
+   class CLASS needed to hold a value of mode MODE.
+
+   This is closely related to the macro `HARD_REGNO_NREGS'.  In fact, the value
+   of the macro `CLASS_MAX_NREGS (CLASS, MODE)' should be the maximum value of
+   `HARD_REGNO_NREGS (REGNO, MODE)' for all REGNO values in the class CLASS.
+
+   This macro helps control the handling of multiple-word values in
+   the reload pass.
+
+   This declaration is required.  */
+#define CLASS_MAX_NREGS(CLASS, MODE) frv_class_max_nregs (CLASS, MODE)
+
+#define ZERO_P(x) (x == CONST0_RTX (GET_MODE (x)))
+
+/* 6 bit signed immediate.  */
+#define CONST_OK_FOR_I(VALUE) IN_RANGE_P(VALUE, -32, 31)
+/* 10 bit signed immediate.  */
+#define CONST_OK_FOR_J(VALUE) IN_RANGE_P(VALUE, -512, 511)
+/* Unused */
+#define CONST_OK_FOR_K(VALUE)  0
+/* 16 bit signed immediate.  */
+#define CONST_OK_FOR_L(VALUE) IN_RANGE_P(VALUE, -32768, 32767)
+/* 16 bit unsigned immediate.  */
+#define CONST_OK_FOR_M(VALUE)  IN_RANGE_P (VALUE, 0, 65535)
+/* 12 bit signed immediate that is negative.  */
+#define CONST_OK_FOR_N(VALUE) IN_RANGE_P(VALUE, -2048, -1)
+/* Zero */
+#define CONST_OK_FOR_O(VALUE) ((VALUE) == 0)
+/* 12 bit signed immediate that is negative.  */
+#define CONST_OK_FOR_P(VALUE) IN_RANGE_P(VALUE, 1, 2047)
+
+/* A C expression that defines the machine-dependent operand constraint letters
+   (`I', `J', `K', .. 'P') that specify particular ranges of integer values.
+   If C is one of those letters, the expression should check that VALUE, an
+   integer, is in the appropriate range and return 1 if so, 0 otherwise.  If C
+   is not one of those letters, the value should be 0 regardless of VALUE.  */
+#define CONST_OK_FOR_LETTER_P(VALUE, C)                \
+  (  (C) == 'I' ? CONST_OK_FOR_I (VALUE)        \
+   : (C) == 'J' ? CONST_OK_FOR_J (VALUE)        \
+   : (C) == 'K' ? CONST_OK_FOR_K (VALUE)        \
+   : (C) == 'L' ? CONST_OK_FOR_L (VALUE)        \
+   : (C) == 'M' ? CONST_OK_FOR_M (VALUE)        \
+   : (C) == 'N' ? CONST_OK_FOR_N (VALUE)        \
+   : (C) == 'O' ? CONST_OK_FOR_O (VALUE)        \
+   : (C) == 'P' ? CONST_OK_FOR_P (VALUE)        \
+   : 0)
+
+
+/* A C expression that defines the machine-dependent operand constraint letters
+   (`G', `H') that specify particular ranges of `const_double' values.
+
+   If C is one of those letters, the expression should check that VALUE, an RTX
+   of code `const_double', is in the appropriate range and return 1 if so, 0
+   otherwise.  If C is not one of those letters, the value should be 0
+   regardless of VALUE.
+
+   `const_double' is used for all floating-point constants and for `DImode'
+   fixed-point constants.  A given letter can accept either or both kinds of
+   values.  It can use `GET_MODE' to distinguish between these kinds.  */
+
+#define CONST_DOUBLE_OK_FOR_G(VALUE)                                   \
+  ((GET_MODE (VALUE) == VOIDmode                                       \
+    && CONST_DOUBLE_LOW (VALUE) == 0                                   \
+    && CONST_DOUBLE_HIGH (VALUE) == 0)                                 \
+   || ((GET_MODE (VALUE) == SFmode                                     \
+        || GET_MODE (VALUE) == DFmode)                                 \
+       && (VALUE) == CONST0_RTX (GET_MODE (VALUE))))
+
+#define CONST_DOUBLE_OK_FOR_H(VALUE) 0
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C)                         \
+  (  (C) == 'G' ? CONST_DOUBLE_OK_FOR_G (VALUE)                                \
+   : (C) == 'H' ? CONST_DOUBLE_OK_FOR_H (VALUE)                                \
+   : 0)
+
+/* A C expression that defines the optional machine-dependent constraint
+   letters (`Q', `R', `S', `T', `U') that can be used to segregate specific
+   types of operands, usually memory references, for the target machine.
+   Normally this macro will not be defined.  If it is required for a particular
+   target machine, it should return 1 if VALUE corresponds to the operand type
+   represented by the constraint letter C.  If C is not defined as an extra
+   constraint, the value returned should be 0 regardless of VALUE.
+
+   For example, on the ROMP, load instructions cannot have their output in r0
+   if the memory reference contains a symbolic address.  Constraint letter `Q'
+   is defined as representing a memory address that does *not* contain a
+   symbolic address.  An alternative is specified with a `Q' constraint on the
+   input and `r' on the output.  The next alternative specifies `m' on the
+   input and a register class that does not include r0 on the output.  */
+
+/* Small data references */
+#define EXTRA_CONSTRAINT_FOR_Q(VALUE)                                  \
+  (small_data_symbolic_operand (VALUE, GET_MODE (VALUE)))
+
+/* Double word memory ops that take one instruction.  */
+#define EXTRA_CONSTRAINT_FOR_R(VALUE)                                  \
+  (dbl_memory_one_insn_operand (VALUE, GET_MODE (VALUE)))
+
+/* SYMBOL_REF */
+#define EXTRA_CONSTRAINT_FOR_S(VALUE) (GET_CODE (VALUE) == SYMBOL_REF)
+
+/* Double word memory ops that take two instructions.  */
+#define EXTRA_CONSTRAINT_FOR_T(VALUE)                                  \
+  (dbl_memory_two_insn_operand (VALUE, GET_MODE (VALUE)))
+
+/* Memory operand for conditional execution.  */
+#define EXTRA_CONSTRAINT_FOR_U(VALUE)                                  \
+  (condexec_memory_operand (VALUE, GET_MODE (VALUE)))
+
+#define EXTRA_CONSTRAINT(VALUE, C)                                     \
+  (  (C) == 'Q'   ? EXTRA_CONSTRAINT_FOR_Q (VALUE)                     \
+   : (C) == 'R' ? EXTRA_CONSTRAINT_FOR_R (VALUE)                       \
+   : (C) == 'S' ? EXTRA_CONSTRAINT_FOR_S (VALUE)                       \
+   : (C) == 'T' ? EXTRA_CONSTRAINT_FOR_T (VALUE)                       \
+   : (C) == 'U' ? EXTRA_CONSTRAINT_FOR_U (VALUE)                       \
+   : 0)
+
+\f
+/* Basic Stack Layout.  */
+
+/* Structure to describe information about a saved range of registers */
+
+typedef struct frv_stack_regs {
+  const char * name;           /* name of the register ranges */
+  int first;                   /* first register in the range */
+  int last;                    /* last register in the range */
+  int size_1word;              /* # of bytes to be stored via 1 word stores */
+  int size_2words;             /* # of bytes to be stored via 2 word stores */
+  unsigned char field_p;       /* true if the registers are a single SPR */
+  unsigned char dword_p;       /* true if we can do dword stores */
+  unsigned char special_p;     /* true if the regs have a fixed save loc.  */
+} frv_stack_regs_t;
+
+/* Register ranges to look into saving.  */
+#define STACK_REGS_GPR         0       /* Gprs (normally gr16..gr31, gr48..gr63) */
+#define STACK_REGS_FPR         1       /* Fprs (normally fr16..fr31, fr48..fr63) */
+#define STACK_REGS_LR          2       /* LR register */
+#define STACK_REGS_CC          3       /* CCrs (normally not saved) */
+#define STACK_REGS_LCR         5       /* lcr register */
+#define STACK_REGS_STDARG      6       /* stdarg registers */
+#define STACK_REGS_STRUCT      7       /* structure return (gr3) */
+#define STACK_REGS_FP          8       /* FP register */
+#define STACK_REGS_MAX         9       /* # of register ranges */
+
+/* Values for save_p field.  */
+#define REG_SAVE_NO_SAVE       0       /* register not saved */
+#define REG_SAVE_1WORD         1       /* save the register */
+#define REG_SAVE_2WORDS                2       /* save register and register+1 */
+
+/* Structure used to define the frv stack.  */
+
+typedef struct frv_stack {
+  int total_size;              /* total bytes allocated for stack */
+  int vars_size;               /* variable save area size */
+  int parameter_size;          /* outgoing parameter size */
+  int stdarg_size;             /* size of regs needed to be saved for stdarg */
+  int regs_size;               /* size of the saved registers */
+  int regs_size_1word;         /* # of bytes to be stored via 1 word stores */
+  int regs_size_2words;                /* # of bytes to be stored via 2 word stores */
+  int header_size;             /* size of the old FP, struct ret., LR save */
+  int pretend_size;            /* size of pretend args */
+  int vars_offset;             /* offset to save local variables from new SP*/
+  int regs_offset;             /* offset to save registers from new SP */
+                               /* register range information */
+  frv_stack_regs_t regs[STACK_REGS_MAX];
+                               /* offset to store each register */
+  int reg_offset[FIRST_PSEUDO_REGISTER];
+                               /* whether to save register (& reg+1) */
+  unsigned char save_p[FIRST_PSEUDO_REGISTER];
+} frv_stack_t;
+
+/* Define this macro if pushing a word onto the stack moves the stack pointer
+   to a smaller address.  */
+#define STACK_GROWS_DOWNWARD 1
+
+/* Define this macro if the addresses of local variable slots are at negative
+   offsets from the frame pointer.  */
+#define FRAME_GROWS_DOWNWARD
+
+/* Offset from the frame pointer to the first local variable slot to be
+   allocated.
+
+   If `FRAME_GROWS_DOWNWARD', find the next slot's offset by subtracting the
+   first slot's length from `STARTING_FRAME_OFFSET'.  Otherwise, it is found by
+   adding the length of the first slot to the value `STARTING_FRAME_OFFSET'.  */
+#define STARTING_FRAME_OFFSET 0
+
+/* Offset from the stack pointer register to the first location at which
+   outgoing arguments are placed.  If not specified, the default value of zero
+   is used.  This is the proper value for most machines.
+
+   If `ARGS_GROW_DOWNWARD', this is the offset to the location above the first
+   location at which outgoing arguments are placed.  */
+#define STACK_POINTER_OFFSET 0
+
+/* Offset from the argument pointer register to the first argument's address.
+   On some machines it may depend on the data type of the function.
+
+   If `ARGS_GROW_DOWNWARD', this is the offset to the location above the first
+   argument's address.  */
+#define FIRST_PARM_OFFSET(FUNDECL) 0
+
+/* A C expression whose value is RTL representing the address in a stack frame
+   where the pointer to the caller's frame is stored.  Assume that FRAMEADDR is
+   an RTL expression for the address of the stack frame itself.
+
+   If you don't define this macro, the default is to return the value of
+   FRAMEADDR--that is, the stack frame address is also the address of the stack
+   word that points to the previous frame.  */
+#define DYNAMIC_CHAIN_ADDRESS(FRAMEADDR) frv_dynamic_chain_address (FRAMEADDR)
+
+/* A C expression whose value is RTL representing the value of the return
+   address for the frame COUNT steps up from the current frame, after the
+   prologue.  FRAMEADDR is the frame pointer of the COUNT frame, or the frame
+   pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
+   defined.
+
+   The value of the expression must always be the correct address when COUNT is
+   zero, but may be `NULL_RTX' if there is not way to determine the return
+   address of other frames.  */
+#define RETURN_ADDR_RTX(COUNT, FRAMEADDR) frv_return_addr_rtx (COUNT, FRAMEADDR)
+
+/* This function contains machine specific function data.  */
+struct machine_function GTY(())
+{
+  /* True if we have created an rtx that relies on the stack frame.  */
+  int frame_needed;
+};
+
+#define RETURN_POINTER_REGNUM LR_REGNO
+
+/* A C expression whose value is RTL representing the location of the incoming
+   return address at the beginning of any function, before the prologue.  This
+   RTL is either a `REG', indicating that the return value is saved in `REG',
+   or a `MEM' representing a location in the stack.
+
+   You only need to define this macro if you want to support call frame
+   debugging information like that provided by DWARF 2.  */
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (SImode, RETURN_POINTER_REGNUM)
+
+\f
+/* Register That Address the Stack Frame.  */
+
+/* The register number of the stack pointer register, which must also be a
+   fixed register according to `FIXED_REGISTERS'.  On most machines, the
+   hardware determines which register this is.  */
+#define STACK_POINTER_REGNUM (GPR_FIRST + 1)
+
+/* The register number of the frame pointer register, which is used to access
+   automatic variables in the stack frame.  On some machines, the hardware
+   determines which register this is.  On other machines, you can choose any
+   register you wish for this purpose.  */
+#define FRAME_POINTER_REGNUM (GPR_FIRST + 2)
+
+/* The register number of the arg pointer register, which is used to access the
+   function's argument list.  On some machines, this is the same as the frame
+   pointer register.  On some machines, the hardware determines which register
+   this is.  On other machines, you can choose any register you wish for this
+   purpose.  If this is not the same register as the frame pointer register,
+   then you must mark it as a fixed register according to `FIXED_REGISTERS', or
+   arrange to be able to eliminate it.  */
+
+/* On frv this is a fake register that is eliminated in
+   terms of either the frame pointer or stack pointer.  */
+#define ARG_POINTER_REGNUM AP_FIRST
+
+/* Register numbers used for passing a function's static chain pointer.  If
+   register windows are used, the register number as seen by the called
+   function is `STATIC_CHAIN_INCOMING_REGNUM', while the register number as
+   seen by the calling function is `STATIC_CHAIN_REGNUM'.  If these registers
+   are the same, `STATIC_CHAIN_INCOMING_REGNUM' need not be defined.
+
+   The static chain register need not be a fixed register.
+
+   If the static chain is passed in memory, these macros should not be defined;
+   instead, the next two macros should be defined.  */
+#define STATIC_CHAIN_REGNUM (GPR_FIRST + 7)
+#define STATIC_CHAIN_INCOMING_REGNUM (GPR_FIRST + 7)
+
+\f
+/* Eliminating the Frame Pointer and the Arg Pointer.  */
+
+/* A C expression which is nonzero if a function must have and use a frame
+   pointer.  This expression is evaluated in the reload pass.  If its value is
+   nonzero the function will have a frame pointer.
+
+   The expression can in principle examine the current function and decide
+   according to the facts, but on most machines the constant 0 or the constant
+   1 suffices.  Use 0 when the machine allows code to be generated with no
+   frame pointer, and doing so saves some time or space.  Use 1 when there is
+   no possible advantage to avoiding a frame pointer.
+
+   In certain cases, the compiler does not know how to produce valid code
+   without a frame pointer.  The compiler recognizes those cases and
+   automatically gives the function a frame pointer regardless of what
+   `FRAME_POINTER_REQUIRED' says.  You don't need to worry about them.
+
+   In a function that does not require a frame pointer, the frame pointer
+   register can be allocated for ordinary usage, unless you mark it as a fixed
+   register.  See `FIXED_REGISTERS' for more information.  */
+#define FRAME_POINTER_REQUIRED frv_frame_pointer_required ()
+
+/* If defined, this macro specifies a table of register pairs used to eliminate
+   unneeded registers that point into the stack frame.  If it is not defined,
+   the only elimination attempted by the compiler is to replace references to
+   the frame pointer with references to the stack pointer.
+
+   The definition of this macro is a list of structure initializations, each of
+   which specifies an original and replacement register.
+
+   On some machines, the position of the argument pointer is not known until
+   the compilation is completed.  In such a case, a separate hard register must
+   be used for the argument pointer.  This register can be eliminated by
+   replacing it with either the frame pointer or the argument pointer,
+   depending on whether or not the frame pointer has been eliminated.
+
+   In this case, you might specify:
+        #define ELIMINABLE_REGS  \
+        {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+         {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+         {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+
+   Note that the elimination of the argument pointer with the stack pointer is
+   specified first since that is the preferred elimination.  */
+
+#define ELIMINABLE_REGS                                                        \
+{                                                                      \
+  {ARG_POINTER_REGNUM,  STACK_POINTER_REGNUM},                         \
+  {ARG_POINTER_REGNUM,  FRAME_POINTER_REGNUM},                         \
+  {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}                         \
+}
+
+/* A C expression that returns non-zero if the compiler is allowed to try to
+   replace register number FROM with register number TO.  This macro need only
+   be defined if `ELIMINABLE_REGS' is defined, and will usually be the constant
+   1, since most of the cases preventing register elimination are things that
+   the compiler already knows about.  */
+
+#define CAN_ELIMINATE(FROM, TO)                                                \
+  ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM                \
+   ? ! frame_pointer_needed                                            \
+   : 1)
+
+/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'.  It specifies the
+   initial difference between the specified pair of registers.  This macro must
+   be defined if `ELIMINABLE_REGS' is defined.  */
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)                   \
+  (OFFSET) = frv_initial_elimination_offset (FROM, TO)
+
+\f
+/* Passing Function Arguments on the Stack.  */
+
+/* If defined, the maximum amount of space required for outgoing arguments will
+   be computed and placed into the variable
+   `current_function_outgoing_args_size'.  No space will be pushed onto the
+   stack for each call; instead, the function prologue should increase the
+   stack frame size by this amount.
+
+   Defining both `PUSH_ROUNDING' and `ACCUMULATE_OUTGOING_ARGS' is not
+   proper.  */
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+/* A C expression that should indicate the number of bytes of its own arguments
+   that a function pops on returning, or 0 if the function pops no arguments
+   and the caller must therefore pop them all after the function returns.
+
+   FUNDECL is a C variable whose value is a tree node that describes the
+   function in question.  Normally it is a node of type `FUNCTION_DECL' that
+   describes the declaration of the function.  From this it is possible to
+   obtain the DECL_ATTRIBUTES of the function.
+
+   FUNTYPE is a C variable whose value is a tree node that describes the
+   function in question.  Normally it is a node of type `FUNCTION_TYPE' that
+   describes the data type of the function.  From this it is possible to obtain
+   the data types of the value and arguments (if known).
+
+   When a call to a library function is being considered, FUNTYPE will contain
+   an identifier node for the library function.  Thus, if you need to
+   distinguish among various library functions, you can do so by their names.
+   Note that "library function" in this context means a function used to
+   perform arithmetic, whose name is known specially in the compiler and was
+   not mentioned in the C code being compiled.
+
+   STACK-SIZE is the number of bytes of arguments passed on the stack.  If a
+   variable number of bytes is passed, it is zero, and argument popping will
+   always be the responsibility of the calling function.
+
+   On the Vax, all functions always pop their arguments, so the definition of
+   this macro is STACK-SIZE.  On the 68000, using the standard calling
+   convention, no functions pop their arguments, so the value of the macro is
+   always 0 in this case.  But an alternative calling convention is available
+   in which functions that take a fixed number of arguments pop them but other
+   functions (such as `printf') pop nothing (the caller pops all).  When this
+   convention is in use, FUNTYPE is examined to determine whether a function
+   takes a fixed number of arguments.  */
+#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0
+
+\f
+/* Function Arguments in Registers.  */
+
+/* Nonzero if we do not know how to pass TYPE solely in registers.
+   We cannot do so in the following cases:
+
+   - if the type has variable size
+   - if the type is marked as addressable (it is required to be constructed
+     into the stack)
+   - if the type is a structure or union.  */
+
+#define MUST_PASS_IN_STACK(MODE,TYPE)                           \
+   (((MODE) == BLKmode)                                         \
+    || ((TYPE) != 0                                             \
+         && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST        \
+             || TREE_CODE (TYPE) == RECORD_TYPE                 \
+             || TREE_CODE (TYPE) == UNION_TYPE                  \
+             || TREE_CODE (TYPE) == QUAL_UNION_TYPE             \
+             || TREE_ADDRESSABLE (TYPE))))
+
+/* The number of register assigned to holding function arguments.  */
+
+#define FRV_NUM_ARG_REGS        6
+
+/* A C expression that controls whether a function argument is passed in a
+   register, and which register.
+
+   The arguments are CUM, of type CUMULATIVE_ARGS, which summarizes (in a way
+   defined by INIT_CUMULATIVE_ARGS and FUNCTION_ARG_ADVANCE) all of the previous
+   arguments so far passed in registers; MODE, the machine mode of the argument;
+   TYPE, the data type of the argument as a tree node or 0 if that is not known
+   (which happens for C support library functions); and NAMED, which is 1 for an
+   ordinary argument and 0 for nameless arguments that correspond to `...' in the
+   called function's prototype.
+
+   The value of the expression should either be a `reg' RTX for the hard
+   register in which to pass the argument, or zero to pass the argument on the
+   stack.
+
+   For machines like the Vax and 68000, where normally all arguments are
+   pushed, zero suffices as a definition.
+
+   The usual way to make the ANSI library `stdarg.h' work on a machine where
+   some arguments are usually passed in registers, is to cause nameless
+   arguments to be passed on the stack instead.  This is done by making
+   `FUNCTION_ARG' return 0 whenever NAMED is 0.
+
+   You may use the macro `MUST_PASS_IN_STACK (MODE, TYPE)' in the definition of
+   this macro to determine if this argument is of a type that must be passed in
+   the stack.  If `REG_PARM_STACK_SPACE' is not defined and `FUNCTION_ARG'
+   returns non-zero for such an argument, the compiler will abort.  If
+   `REG_PARM_STACK_SPACE' is defined, the argument will be computed in the
+   stack and then loaded into a register.  */
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED)                    \
+  frv_function_arg (&CUM, MODE, TYPE, NAMED, FALSE)
+
+/* Define this macro if the target machine has "register windows", so that the
+   register in which a function sees an arguments is not necessarily the same
+   as the one in which the caller passed the argument.
+
+   For such machines, `FUNCTION_ARG' computes the register in which the caller
+   passes the value, and `FUNCTION_INCOMING_ARG' should be defined in a similar
+   fashion to tell the function being called where the arguments will arrive.
+
+   If `FUNCTION_INCOMING_ARG' is not defined, `FUNCTION_ARG' serves both
+   purposes.  */
+
+#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED)                  \
+  frv_function_arg (&CUM, MODE, TYPE, NAMED, TRUE)
+
+/* A C expression for the number of words, at the beginning of an argument,
+   must be put in registers.  The value must be zero for arguments that are
+   passed entirely in registers or that are entirely pushed on the stack.
+
+   On some machines, certain arguments must be passed partially in registers
+   and partially in memory.  On these machines, typically the first N words of
+   arguments are passed in registers, and the rest on the stack.  If a
+   multi-word argument (a `double' or a structure) crosses that boundary, its
+   first few words must be passed in registers and the rest must be pushed.
+   This macro tells the compiler when this occurs, and how many of the words
+   should go in registers.
+
+   `FUNCTION_ARG' for these arguments should return the first register to be
+   used by the caller for this argument; likewise `FUNCTION_INCOMING_ARG', for
+   the called function.  */
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED)             \
+  frv_function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)
+
+/* extern int frv_function_arg_partial_nregs PARAMS ((CUMULATIVE_ARGS, int, Tree, int));  */
+
+/* A C expression that indicates when an argument must be passed by reference.
+   If nonzero for an argument, a copy of that argument is made in memory and a
+   pointer to the argument is passed instead of the argument itself.  The
+   pointer is passed in whatever way is appropriate for passing a pointer to
+   that type.
+
+   On machines where `REG_PARM_STACK_SPACE' is not defined, a suitable
+   definition of this macro might be
+        #define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED)  \
+          MUST_PASS_IN_STACK (MODE, TYPE)  */
+#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED)         \
+  frv_function_arg_pass_by_reference (&CUM, MODE, TYPE, NAMED)
+
+/* If defined, a C expression that indicates when it is the called function's
+   responsibility to make a copy of arguments passed by invisible reference.
+   Normally, the caller makes a copy and passes the address of the copy to the
+   routine being called.  When FUNCTION_ARG_CALLEE_COPIES is defined and is
+   nonzero, the caller does not make a copy.  Instead, it passes a pointer to
+   the "live" value.  The called function must not modify this value.  If it
+   can be determined that the value won't be modified, it need not make a copy;
+   otherwise a copy must be made.  */
+#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED)             \
+  frv_function_arg_callee_copies (&CUM, MODE, TYPE, NAMED)
+
+/* If defined, a C expression that indicates when it is more desirable to keep
+   an argument passed by invisible reference as a reference, rather than
+   copying it to a pseudo register.  */
+#define FUNCTION_ARG_KEEP_AS_REFERENCE(CUM, MODE, TYPE, NAMED)         \
+  frv_function_arg_keep_as_reference (&CUM, MODE, TYPE, NAMED)
+
+/* A C type for declaring a variable that is used as the first argument of
+   `FUNCTION_ARG' and other related values.  For some target machines, the type
+   `int' suffices and can hold the number of bytes of argument so far.
+
+   There is no need to record in `CUMULATIVE_ARGS' anything about the arguments
+   that have been passed on the stack.  The compiler has other variables to
+   keep track of that.  For target machines on which all arguments are passed
+   on the stack, there is no need to store anything in `CUMULATIVE_ARGS';
+   however, the data structure must exist and should not be empty, so use
+   `int'.  */
+#define CUMULATIVE_ARGS int
+
+/* A C statement (sans semicolon) for initializing the variable CUM for the
+   state at the beginning of the argument list.  The variable has type
+   `CUMULATIVE_ARGS'.  The value of FNTYPE is the tree node for the data type
+   of the function which will receive the args, or 0 if the args are to a
+   compiler support library function.  The value of INDIRECT is nonzero when
+   processing an indirect call, for example a call through a function pointer.
+   The value of INDIRECT is zero for a call to an explicitly named function, a
+   library function call, or when `INIT_CUMULATIVE_ARGS' is used to find
+   arguments for the function being compiled.
+
+   When processing a call to a compiler support library function, LIBNAME
+   identifies which one.  It is a `symbol_ref' rtx which contains the name of
+   the function, as a string.  LIBNAME is 0 when an ordinary C function call is
+   being processed.  Thus, each time this macro is called, either LIBNAME or
+   FNTYPE is nonzero, but never both of them at once.  */
+
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \
+  frv_init_cumulative_args (&CUM, FNTYPE, LIBNAME, INDIRECT, FALSE)
+
+/* Like `INIT_CUMULATIVE_ARGS' but overrides it for the purposes of finding the
+   arguments for the function being compiled.  If this macro is undefined,
+   `INIT_CUMULATIVE_ARGS' is used instead.
+
+   The value passed for LIBNAME is always 0, since library routines with
+   special calling conventions are never compiled with GNU CC.  The argument
+   LIBNAME exists for symmetry with `INIT_CUMULATIVE_ARGS'.  */
+
+#define INIT_CUMULATIVE_INCOMING_ARGS(CUM, FNTYPE, LIBNAME) \
+  frv_init_cumulative_args (&CUM, FNTYPE, LIBNAME, FALSE, TRUE)
+
+/* A C statement (sans semicolon) to update the summarizer variable CUM to
+   advance past an argument in the argument list.  The values MODE, TYPE and
+   NAMED describe that argument.  Once this is done, the variable CUM is
+   suitable for analyzing the *following* argument with `FUNCTION_ARG', etc.
+
+   This macro need not do anything if the argument in question was passed on
+   the stack.  The compiler knows how to track the amount of stack space used
+   for arguments without any special help.  */
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)                   \
+  frv_function_arg_advance (&CUM, MODE, TYPE, NAMED)
+
+/* If defined, a C expression that gives the alignment boundary, in bits, of an
+   argument with the specified mode and type.  If it is not defined,
+   `PARM_BOUNDARY' is used for all arguments.  */
+
+#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \
+  frv_function_arg_boundary (MODE, TYPE)
+
+/* A C expression that is nonzero if REGNO is the number of a hard register in
+   which function arguments are sometimes passed.  This does *not* include
+   implicit arguments such as the static chain and the structure-value address.
+   On many machines, no registers can be used for this purpose since all
+   function arguments are pushed on the stack.  */
+#define FUNCTION_ARG_REGNO_P(REGNO) \
+  ((REGNO) >= FIRST_ARG_REGNUM && ((REGNO) <= LAST_ARG_REGNUM))
+
+\f
+/* How Scalar Function Values are Returned.  */
+
+/* The number of the hard register that is used to return a scalar value from a
+   function call.  */
+#define RETURN_VALUE_REGNUM    (GPR_FIRST + 8)
+
+/* A C expression to create an RTX representing the place where a function
+   returns a value of data type VALTYPE.  VALTYPE is a tree node representing a
+   data type.  Write `TYPE_MODE (VALTYPE)' to get the machine mode used to
+   represent that type.  On many machines, only the mode is relevant.
+   (Actually, on most machines, scalar values are returned in the same place
+   regardless of mode).
+
+   If `PROMOTE_FUNCTION_RETURN' is defined, you must apply the same promotion
+   rules specified in `PROMOTE_MODE' if VALTYPE is a scalar type.
+
+   If the precise function being called is known, FUNC is a tree node
+   (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer.  This makes it
+   possible to use a different value-returning convention for specific
+   functions when all their calls are known.
+
+   `FUNCTION_VALUE' is not used for return vales with aggregate data types,
+   because these are returned in another way.  See `STRUCT_VALUE_REGNUM' and
+   related macros, below.  */
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
+  gen_rtx (REG, TYPE_MODE (VALTYPE), RETURN_VALUE_REGNUM)
+
+/* A C expression to create an RTX representing the place where a library
+   function returns a value of mode MODE.
+
+   Note that "library function" in this context means a compiler support
+   routine, used to perform arithmetic, whose name is known specially by the
+   compiler and was not mentioned in the C code being compiled.
+
+   The definition of `LIBRARY_VALUE' need not be concerned aggregate data
+   types, because none of the library functions returns such types.  */
+#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, RETURN_VALUE_REGNUM)
+
+/* A C expression that is nonzero if REGNO is the number of a hard register in
+   which the values of called function may come back.
+
+   A register whose use for returning values is limited to serving as the
+   second of a pair (for a value of type `double', say) need not be recognized
+   by this macro.  So for most machines, this definition suffices:
+
+        #define FUNCTION_VALUE_REGNO_P(N) ((N) == RETURN)
+
+   If the machine has register windows, so that the caller and the called
+   function use different registers for the return value, this macro should
+   recognize only the caller's register numbers.  */
+#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == RETURN_VALUE_REGNUM)
+
+\f
+/* How Large Values are Returned.  */
+
+/* If the structure value address is passed in a register, then
+   `STRUCT_VALUE_REGNUM' should be the number of that register.  */
+#define STRUCT_VALUE_REGNUM (GPR_FIRST + 3)
+
+\f
+/* Function Entry and Exit.  */
+
+/* Define this macro as a C expression that is nonzero if the return
+   instruction or the function epilogue ignores the value of the stack pointer;
+   in other words, if it is safe to delete an instruction to adjust the stack
+   pointer before a return from the function.
+
+   Note that this macro's value is relevant only for functions for which frame
+   pointers are maintained.  It is never safe to delete a final stack
+   adjustment in a function that has no frame pointer, and the compiler knows
+   this regardless of `EXIT_IGNORE_STACK'.  */
+#define EXIT_IGNORE_STACK 1
+
+/* A C compound statement that outputs the assembler code for a thunk function,
+   used to implement C++ virtual function calls with multiple inheritance.  The
+   thunk acts as a wrapper around a virtual function, adjusting the implicit
+   object parameter before handing control off to the real function.
+
+   First, emit code to add the integer DELTA to the location that contains the
+   incoming first argument.  Assume that this argument contains a pointer, and
+   is the one used to pass the `this' pointer in C++.  This is the incoming
+   argument *before* the function prologue, e.g. `%o0' on a sparc.  The
+   addition must preserve the values of all other incoming arguments.
+
+   After the addition, emit code to jump to FUNCTION, which is a
+   `FUNCTION_DECL'.  This is a direct pure jump, not a call, and does not touch
+   the return address.  Hence returning from FUNCTION will return to whoever
+   called the current `thunk'.
+
+   The effect must be as if FUNCTION had been called directly with the adjusted
+   first argument.  This macro is responsible for emitting all of the code for
+   a thunk function; `FUNCTION_PROLOGUE' and `FUNCTION_EPILOGUE' are not
+   invoked.
+
+   The THUNK_FNDECL is redundant.  (DELTA and FUNCTION have already been
+   extracted from it.)  It might possibly be useful on some targets, but
+   probably not.
+
+   If you do not define this macro, the target-independent code in the C++
+   frontend will generate a less efficient heavyweight thunk that calls
+   FUNCTION instead of jumping to it.  The generic approach does not support
+   varargs.  */
+#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
+frv_asm_output_mi_thunk (FILE, THUNK_FNDECL, (long)DELTA, FUNCTION)
+
+\f
+/* Generating Code for Profiling.  */
+
+/* A C statement or compound statement to output to FILE some assembler code to
+   call the profiling subroutine `mcount'.  Before calling, the assembler code
+   must load the address of a counter variable into a register where `mcount'
+   expects to find the address.  The name of this variable is `LP' followed by
+   the number LABELNO, so you would generate the name using `LP%d' in a
+   `fprintf'.
+
+   The details of how the address should be passed to `mcount' are determined
+   by your operating system environment, not by GNU CC.  To figure them out,
+   compile a small program for profiling using the system's installed C
+   compiler and look at the assembler code that results.
+
+   This declaration must be present, but it can be an abort if profiling is
+   not implemented.  */
+
+#define FUNCTION_PROFILER(FILE, LABELNO) abort ()
+
+\f
+/* Implementing the Varargs Macros.  */
+
+/* If defined, is a C expression that produces the machine-specific code for a
+   call to `__builtin_saveregs'.  This code will be moved to the very beginning
+   of the function, before any parameter access are made.  The return value of
+   this function should be an RTX that contains the value to use as the return
+   of `__builtin_saveregs'.
+
+   If this macro is not defined, the compiler will output an ordinary call to
+   the library function `__builtin_saveregs'.  */
+
+#define EXPAND_BUILTIN_SAVEREGS() frv_expand_builtin_saveregs ()
+
+/* This macro offers an alternative to using `__builtin_saveregs' and defining
+   the macro `EXPAND_BUILTIN_SAVEREGS'.  Use it to store the anonymous register
+   arguments into the stack so that all the arguments appear to have been
+   passed consecutively on the stack.  Once this is done, you can use the
+   standard implementation of varargs that works for machines that pass all
+   their arguments on the stack.
+
+   The argument ARGS_SO_FAR is the `CUMULATIVE_ARGS' data structure, containing
+   the values that obtain after processing of the named arguments.  The
+   arguments MODE and TYPE describe the last named argument--its machine mode
+   and its data type as a tree node.
+
+   The macro implementation should do two things: first, push onto the stack
+   all the argument registers *not* used for the named arguments, and second,
+   store the size of the data thus pushed into the `int'-valued variable whose
+   name is supplied as the argument PRETEND_ARGS_SIZE.  The value that you
+   store here will serve as additional offset for setting up the stack frame.
+
+   Because you must generate code to push the anonymous arguments at compile
+   time without knowing their data types, `SETUP_INCOMING_VARARGS' is only
+   useful on machines that have just a single category of argument register and
+   use it uniformly for all data types.
+
+   If the argument SECOND_TIME is nonzero, it means that the arguments of the
+   function are being analyzed for the second time.  This happens for an inline
+   function, which is not actually compiled until the end of the source file.
+   The macro `SETUP_INCOMING_VARARGS' should not generate any instructions in
+   this case.  */
+#define SETUP_INCOMING_VARARGS(ARGS_SO_FAR, MODE, TYPE, PRETEND_ARGS_SIZE, SECOND_TIME) \
+  frv_setup_incoming_varargs (& ARGS_SO_FAR, (int) MODE, TYPE,         \
+                             & PRETEND_ARGS_SIZE, SECOND_TIME)
+
+/* Implement the stdarg/varargs va_start macro.  STDARG_P is non-zero if this
+   is stdarg.h instead of varargs.h.  VALIST is the tree of the va_list
+   variable to initialize.  NEXTARG is the machine independent notion of the
+   'next' argument after the variable arguments.  If not defined, a standard
+   implementation will be defined that works for arguments passed on the stack.  */
+
+#define EXPAND_BUILTIN_VA_START(VALIST, NEXTARG)               \
+  (frv_expand_builtin_va_start(VALIST, NEXTARG))
+
+/* Implement the stdarg/varargs va_arg macro.  VALIST is the variable of type
+   va_list as a tree, TYPE is the type passed to va_arg.  */
+
+#define EXPAND_BUILTIN_VA_ARG(VALIST, TYPE)                            \
+  (frv_expand_builtin_va_arg (VALIST, TYPE))
+
+\f
+/* Trampolines for Nested Functions.  */
+
+/* A C expression for the size in bytes of the trampoline, as an integer.  */
+#define TRAMPOLINE_SIZE frv_trampoline_size ()
+
+/* Alignment required for trampolines, in bits.
+
+   If you don't define this macro, the value of `BIGGEST_ALIGNMENT' is used for
+   aligning trampolines.  */
+#define TRAMPOLINE_ALIGNMENT 32
+
+/* A C statement to initialize the variable parts of a trampoline.  ADDR is an
+   RTX for the address of the trampoline; FNADDR is an RTX for the address of
+   the nested function; STATIC_CHAIN is an RTX for the static chain value that
+   should be passed to the function when it is called.  */
+#define INITIALIZE_TRAMPOLINE(ADDR, FNADDR, STATIC_CHAIN) \
+  frv_initialize_trampoline (ADDR, FNADDR, STATIC_CHAIN)
+
+/* Define this macro if trampolines need a special subroutine to do their work.
+   The macro should expand to a series of `asm' statements which will be
+   compiled with GNU CC.  They go in a library function named
+   `__transfer_from_trampoline'.
+
+   If you need to avoid executing the ordinary prologue code of a compiled C
+   function when you jump to the subroutine, you can do so by placing a special
+   label of your own in the assembler code.  Use one `asm' statement to
+   generate an assembler label, and another to make the label global.  Then
+   trampolines can use that label to jump directly to your special assembler
+   code.  */
+
+#ifdef __FRV_UNDERSCORE__
+#define TRAMPOLINE_TEMPLATE_NAME "___trampoline_template"
+#else
+#define TRAMPOLINE_TEMPLATE_NAME "__trampoline_template"
+#endif
+
+#define TRANSFER_FROM_TRAMPOLINE                                       \
+extern int _write (int, const void *, unsigned);                       \
+                                                                       \
+void                                                                   \
+__trampoline_setup (addr, size, fnaddr, sc)                            \
+     short * addr;                                                     \
+     int size;                                                         \
+     int fnaddr;                                                       \
+     int sc;                                                           \
+{                                                                      \
+  extern short __trampoline_template[];                                        \
+  short * to = addr;                                                   \
+  short * from = &__trampoline_template[0];                            \
+  int i;                                                               \
+                                                                       \
+  if (size < 20)                                                       \
+    {                                                                  \
+      _write (2, "__trampoline_setup bad size\n",                      \
+             sizeof ("__trampoline_setup bad size\n") - 1);            \
+      exit (-1);                                                       \
+    }                                                                  \
+                                                                       \
+  to[0] = from[0];                                                     \
+  to[1] = (short)(fnaddr);                                             \
+  to[2] = from[2];                                                     \
+  to[3] = (short)(sc);                                                 \
+  to[4] = from[4];                                                     \
+  to[5] = (short)(fnaddr >> 16);                                       \
+  to[6] = from[6];                                                     \
+  to[7] = (short)(sc >> 16);                                           \
+  to[8] = from[8];                                                     \
+  to[9] = from[9];                                                     \
+                                                                       \
+  for (i = 0; i < 20; i++)                                             \
+    __asm__ volatile ("dcf @(%0,%1)\n\tici @(%0,%1)" :: "r" (to), "r" (i)); \
+}                                                                      \
+                                                                       \
+__asm__("\n"                                                           \
+       "\t.globl " TRAMPOLINE_TEMPLATE_NAME "\n"                       \
+       "\t.text\n"                                                     \
+       TRAMPOLINE_TEMPLATE_NAME ":\n"                                  \
+       "\tsetlos #0, gr6\n"    /* jump register */                     \
+       "\tsetlos #0, gr7\n"    /* static chain */                      \
+       "\tsethi #0, gr6\n"                                             \
+       "\tsethi #0, gr7\n"                                             \
+       "\tjmpl @(gr0,gr6)\n");
+
+\f
+/* Implicit Calls to Library Routines.  */
+
+/* A C string constant giving the name of the function to call for the
+   remainder in division of one signed full-word by another.  If you do not
+   define this macro, the default name is used, which is `__modsi3', a function
+   defined in `libgcc.a'.  */
+#define MODSI3_LIBCALL "__modi"
+
+/* A C string constant giving the name of the function to call for the
+   remainder in division of one unsigned full-word by another.  If you do not
+   define this macro, the default name is used, which is `__umodsi3', a
+   function defined in `libgcc.a'.  */
+#define UMODSI3_LIBCALL "__umodi"
+
+/* A C string constant giving the name of the function to call for
+   multiplication of one signed double-word by another.  If you do not define
+   this macro, the default name is used, which is `__muldi3', a function
+   defined in `libgcc.a'.  */
+#define MULDI3_LIBCALL "__mulll"
+
+/* A C string constant giving the name of the function to call for division of
+   one signed double-word by another.  If you do not define this macro, the
+   default name is used, which is `__divdi3', a function defined in `libgcc.a'.  */
+#define DIVDI3_LIBCALL "__divll"
+
+/* A C string constant giving the name of the function to call for division of
+   one unsigned full-word by another.  If you do not define this macro, the
+   default name is used, which is `__udivdi3', a function defined in
+   `libgcc.a'.  */
+#define UDIVDI3_LIBCALL "__udivll"
+
+/* A C string constant giving the name of the function to call for the
+   remainder in division of one signed double-word by another.  If you do not
+   define this macro, the default name is used, which is `__moddi3', a function
+   defined in `libgcc.a'.  */
+#define MODDI3_LIBCALL "__modll"
+
+/* A C string constant giving the name of the function to call for the
+   remainder in division of one unsigned full-word by another.  If you do not
+   define this macro, the default name is used, which is `__umoddi3', a
+   function defined in `libgcc.a'.  */
+#define UMODDI3_LIBCALL "__umodll"
+
+/* Define this macro as a C statement that declares additional library routines
+   renames existing ones. `init_optabs' calls this macro after initializing all
+   the normal library routines.  */
+#define INIT_TARGET_OPTABS                                     \
+  do                                                           \
+    {                                                          \
+      add_optab->handlers [(int) DImode].libfunc               \
+       = init_one_libfunc ("__addll");                         \
+      sub_optab->handlers [(int) DImode].libfunc               \
+       = init_one_libfunc ("__subll");                         \
+      and_optab->handlers [(int) DImode].libfunc               \
+       = init_one_libfunc ("__andll");                         \
+      ior_optab->handlers [(int) DImode].libfunc               \
+       = init_one_libfunc ("__orll");                          \
+      xor_optab->handlers [(int) DImode].libfunc               \
+       = init_one_libfunc ("__xorll");                         \
+      one_cmpl_optab->handlers [(int) DImode].libfunc          \
+       = init_one_libfunc ("__notll");                         \
+      add_optab->handlers [(int) SFmode].libfunc               \
+       = init_one_libfunc ("__addf");                          \
+      sub_optab->handlers [(int) SFmode].libfunc               \
+       = init_one_libfunc ("__subf");                          \
+      smul_optab->handlers [(int) SFmode].libfunc              \
+       = init_one_libfunc ("__mulf");                          \
+      sdiv_optab->handlers [(int) SFmode].libfunc              \
+       = init_one_libfunc ("__divf");                          \
+      add_optab->handlers [(int) DFmode].libfunc               \
+       = init_one_libfunc ("__addd");                          \
+      sub_optab->handlers [(int) DFmode].libfunc               \
+       = init_one_libfunc ("__subd");                          \
+      smul_optab->handlers [(int) DFmode].libfunc              \
+       = init_one_libfunc ("__muld");                          \
+      sdiv_optab->handlers [(int) DFmode].libfunc              \
+       = init_one_libfunc ("__divd");                          \
+      fixsfsi_libfunc = init_one_libfunc ("__ftoi");           \
+      fixunssfsi_libfunc = init_one_libfunc ("__ftoui");       \
+      fixsfdi_libfunc = init_one_libfunc ("__ftoll");          \
+      fixunssfdi_libfunc = init_one_libfunc ("__ftoull");      \
+      fixdfsi_libfunc = init_one_libfunc ("__dtoi");           \
+      fixunsdfsi_libfunc = init_one_libfunc ("__dtoui");       \
+      fixdfdi_libfunc = init_one_libfunc ("__dtoll");          \
+      fixunsdfdi_libfunc = init_one_libfunc ("__dtoull");      \
+      floatsisf_libfunc = init_one_libfunc ("__itof");         \
+      floatdisf_libfunc = init_one_libfunc ("__lltof");                \
+      floatsidf_libfunc = init_one_libfunc ("__itod");         \
+      floatdidf_libfunc = init_one_libfunc ("__lltod");                \
+      extendsfdf2_libfunc = init_one_libfunc ("__ftod");       \
+      truncdfsf2_libfunc = init_one_libfunc ("__dtof");                \
+    }                                                          \
+  while (0)
+
+\f
+/* Addressing Modes.  */
+
+/* A C expression that is 1 if the RTX X is a constant which is a valid
+   address.  On most machines, this can be defined as `CONSTANT_P (X)', but a
+   few machines are more restrictive in which constant addresses are supported.
+
+   `CONSTANT_P' accepts integer-values expressions whose values are not
+   explicitly known, such as `symbol_ref', `label_ref', and `high' expressions
+   and `const' arithmetic expressions, in addition to `const_int' and
+   `const_double' expressions.  */
+#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X)
+
+/* A number, the maximum number of registers that can appear in a valid memory
+   address.  Note that it is up to you to specify a value equal to the maximum
+   number that `GO_IF_LEGITIMATE_ADDRESS' would ever accept.  */
+#define MAX_REGS_PER_ADDRESS 2
+
+/* A C compound statement with a conditional `goto LABEL;' executed if X (an
+   RTX) is a legitimate memory address on the target machine for a memory
+   operand of mode MODE.
+
+   It usually pays to define several simpler macros to serve as subroutines for
+   this one.  Otherwise it may be too complicated to understand.
+
+   This macro must exist in two variants: a strict variant and a non-strict
+   one.  The strict variant is used in the reload pass.  It must be defined so
+   that any pseudo-register that has not been allocated a hard register is
+   considered a memory reference.  In contexts where some kind of register is
+   required, a pseudo-register with no hard register must be rejected.
+
+   The non-strict variant is used in other passes.  It must be defined to
+   accept all pseudo-registers in every context where some kind of register is
+   required.
+
+   Compiler source files that want to use the strict variant of this macro
+   define the macro `REG_OK_STRICT'.  You should use an `#ifdef REG_OK_STRICT'
+   conditional to define the strict variant in that case and the non-strict
+   variant otherwise.
+
+   Subroutines to check for acceptable registers for various purposes (one for
+   base registers, one for index registers, and so on) are typically among the
+   subroutines used to define `GO_IF_LEGITIMATE_ADDRESS'.  Then only these
+   subroutine macros need have two variants; the higher levels of macros may be
+   the same whether strict or not.
+
+   Normally, constant addresses which are the sum of a `symbol_ref' and an
+   integer are stored inside a `const' RTX to mark them as constant.
+   Therefore, there is no need to recognize such sums specifically as
+   legitimate addresses.  Normally you would simply recognize any `const' as
+   legitimate.
+
+   Usually `PRINT_OPERAND_ADDRESS' is not prepared to handle constant sums that
+   are not marked with `const'.  It assumes that a naked `plus' indicates
+   indexing.  If so, then you *must* reject such naked constant sums as
+   illegitimate addresses, so that none of them will be given to
+   `PRINT_OPERAND_ADDRESS'.
+
+   On some machines, whether a symbolic address is legitimate depends on the
+   section that the address refers to.  On these machines, define the macro
+   `ENCODE_SECTION_INFO' to store the information into the `symbol_ref', and
+   then check for it here.  When you see a `const', you will have to look
+   inside it to find the `symbol_ref' in order to determine the section.
+
+   The best way to modify the name string is by adding text to the beginning,
+   with suitable punctuation to prevent any ambiguity.  Allocate the new name
+   in `saveable_obstack'.  You will have to modify `ASM_OUTPUT_LABELREF' to
+   remove and decode the added text and output the name accordingly, and define
+   `STRIP_NAME_ENCODING' to access the original name string.
+
+   You can check the information stored here into the `symbol_ref' in the
+   definitions of the macros `GO_IF_LEGITIMATE_ADDRESS' and
+   `PRINT_OPERAND_ADDRESS'.  */
+
+#ifdef REG_OK_STRICT
+#define REG_OK_STRICT_P 1
+#else
+#define REG_OK_STRICT_P 0
+#endif
+
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL)                       \
+  do                                                                   \
+    {                                                                  \
+      if (frv_legitimate_address_p (MODE, X, REG_OK_STRICT_P, FALSE))  \
+       goto LABEL;                                                     \
+    }                                                                  \
+  while (0)
+
+/* A C expression that is nonzero if X (assumed to be a `reg' RTX) is valid for
+   use as a base register.  For hard registers, it should always accept those
+   which the hardware permits and reject the others.  Whether the macro accepts
+   or rejects pseudo registers must be controlled by `REG_OK_STRICT' as
+   described above.  This usually requires two variant definitions, of which
+   `REG_OK_STRICT' controls the one actually used.  */
+#ifdef REG_OK_STRICT
+#define REG_OK_FOR_BASE_P(X) GPR_P (REGNO (X))
+#else
+#define REG_OK_FOR_BASE_P(X) GPR_AP_OR_PSEUDO_P (REGNO (X))
+#endif
+
+/* A C expression that is nonzero if X (assumed to be a `reg' RTX) is valid for
+   use as an index register.
+
+   The difference between an index register and a base register is that the
+   index register may be scaled.  If an address involves the sum of two
+   registers, neither one of them scaled, then either one may be labeled the
+   "base" and the other the "index"; but whichever labeling is used must fit
+   the machine's constraints of which registers may serve in each capacity.
+   The compiler will try both labelings, looking for one that is valid, and
+   will reload one or both registers only if neither labeling works.  */
+#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
+
+/* A C compound statement that attempts to replace X with a valid memory
+   address for an operand of mode MODE.  WIN will be a C statement label
+   elsewhere in the code; the macro definition may use
+
+        GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN);
+
+   to avoid further processing if the address has become legitimate.
+
+   X will always be the result of a call to `break_out_memory_refs', and OLDX
+   will be the operand that was given to that function to produce X.
+
+   The code generated by this macro should not alter the substructure of X.  If
+   it transforms X into a more legitimate form, it should assign X (which will
+   always be a C variable) a new value.
+
+   It is not necessary for this macro to come up with a legitimate address.
+   The compiler has standard ways of doing so in all cases.  In fact, it is
+   safe for this macro to do nothing.  But often a machine-dependent strategy
+   can generate better code.  */
+
+/* On the FRV, we use it to convert small data and pic references into using
+   the appropriate pointer in the address.  */
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN)                 \
+  do                                                           \
+    {                                                          \
+      rtx newx = frv_legitimize_address (X, OLDX, MODE);       \
+                                                               \
+      if (newx)                                                        \
+       {                                                       \
+         (X) = newx;                                           \
+         goto WIN;                                             \
+       }                                                       \
+    }                                                          \
+  while (0)
+
+/* A C statement or compound statement with a conditional `goto LABEL;'
+   executed if memory address X (an RTX) can have different meanings depending
+   on the machine mode of the memory reference it is used for or if the address
+   is valid for some modes but not others.
+
+   Autoincrement and autodecrement addresses typically have mode-dependent
+   effects because the amount of the increment or decrement is the size of the
+   operand being addressed.  Some machines have other mode-dependent addresses.
+   Many RISC machines have no mode-dependent addresses.
+
+   You may assume that ADDR is a valid address for the machine.  */
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)
+
+/* A C expression that is nonzero if X is a legitimate constant for an
+   immediate operand on the target machine.  You can assume that X satisfies
+   `CONSTANT_P', so you need not check this.  In fact, `1' is a suitable
+   definition for this macro on machines where anything `CONSTANT_P' is valid.  */
+#define LEGITIMATE_CONSTANT_P(X) frv_legitimate_constant_p (X)
+
+/* The load-and-update commands allow pre-modification in addresses.
+   The index has to be in a register.  */
+#define HAVE_PRE_MODIFY_REG 1
+
+\f
+/* Returns a mode from class `MODE_CC' to be used when comparison operation
+   code OP is applied to rtx X and Y.  For example, on the Sparc,
+   `SELECT_CC_MODE' is defined as (see *note Jump Patterns::.  for a
+   description of the reason for this definition)
+
+        #define SELECT_CC_MODE(OP,X,Y) \
+          (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT          \
+           ? ((OP == EQ || OP == NE) ? CCFPmode : CCFPEmode)    \
+           : ((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS    \
+               || GET_CODE (X) == NEG) \
+              ? CC_NOOVmode : CCmode))
+
+   You need not define this macro if `EXTRA_CC_MODES' is not defined.  */
+#define SELECT_CC_MODE(OP, X, Y)                                       \
+  (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT                         \
+   ? CC_FPmode                                                         \
+   : (((OP) == LEU || (OP) == GTU || (OP) == LTU || (OP) == GEU)       \
+      ? CC_UNSmode                                                     \
+      : CCmode))
+
+/* A C expression whose value is one if it is always safe to reverse a
+   comparison whose mode is MODE.  If `SELECT_CC_MODE' can ever return MODE for
+   a floating-point inequality comparison, then `REVERSIBLE_CC_MODE (MODE)'
+   must be zero.
+
+   You need not define this macro if it would always returns zero or if the
+   floating-point format is anything other than `IEEE_FLOAT_FORMAT'.  For
+   example, here is the definition used on the Sparc, where floating-point
+   inequality comparisons are always given `CCFPEmode':
+
+        #define REVERSIBLE_CC_MODE(MODE)  ((MODE) != CCFPEmode)  */
+
+/* On frv, don't consider floating point comparisons to be reversible.  In
+   theory, fp equality comparisons can be reversible */
+#define REVERSIBLE_CC_MODE(MODE) ((MODE) == CCmode || (MODE) == CC_UNSmode)
+
+/* Frv CCR_MODE's are not reversible.  */
+#define REVERSE_CONDEXEC_PREDICATES_P(x,y)      0
+
+\f
+/* Describing Relative Costs of Operations.  */
+
+/* A part of a C `switch' statement that describes the relative costs of
+   constant RTL expressions.  It must contain `case' labels for expression
+   codes `const_int', `const', `symbol_ref', `label_ref' and `const_double'.
+   Each case must ultimately reach a `return' statement to return the relative
+   cost of the use of that kind of constant value in an expression.  The cost
+   may depend on the precise value of the constant, which is available for
+   examination in X, and the rtx code of the expression in which it is
+   contained, found in OUTER_CODE.
+
+   CODE is the expression code--redundant, since it can be obtained with
+   `GET_CODE (X)'.  */
+#define CONST_COSTS(X, CODE, OUTER_CODE)                               \
+  case CONST:                                                          \
+  case LABEL_REF:                                                      \
+  case SYMBOL_REF:                                                     \
+  case CONST_DOUBLE:                                                   \
+    return COSTS_N_INSNS (2);                                          \
+                                                                       \
+  case CONST_INT:                                                      \
+    /* Make 12 bit integers really cheap */                            \
+    return IN_RANGE_P (INTVAL (X), -2048, 2047) ? 0 : COSTS_N_INSNS (2); \
+
+/* Like `CONST_COSTS' but applies to nonconstant RTL expressions.  This can be
+   used, for example, to indicate how costly a multiply instruction is.  In
+   writing this macro, you can use the construct `COSTS_N_INSNS (N)' to specify
+   a cost equal to N fast instructions.  OUTER_CODE is the code of the
+   expression in which X is contained.
+
+   This macro is optional; do not define it if the default cost assumptions are
+   adequate for the target machine.  */
+#define RTX_COSTS(X, CODE, OUTER_CODE)                                 \
+  case PLUS:                                                           \
+  case MINUS:                                                          \
+  case AND:                                                            \
+  case IOR:                                                            \
+  case XOR:                                                            \
+  case ASHIFT:                                                         \
+  case ASHIFTRT:                                                       \
+  case LSHIFTRT:                                                       \
+  case NOT:                                                            \
+  case NEG:                                                            \
+  case COMPARE:                                                                \
+    if (GET_MODE (X) == SImode)                                                \
+      return COSTS_N_INSNS (1);                                                \
+    else if (GET_MODE (X) == DImode)                                   \
+      return COSTS_N_INSNS (2);                                                \
+    else                                                               \
+      return COSTS_N_INSNS (3);        /* guess */                             \
+                                                                       \
+  case MULT:                                                           \
+    if (GET_MODE (X) == SImode)                                                \
+      return COSTS_N_INSNS (2);                                                \
+    else                                                               \
+      return COSTS_N_INSNS (6);        /* guess */                             \
+                                                                       \
+  case DIV:                                                            \
+  case UDIV:                                                           \
+    return COSTS_N_INSNS (18);
+
+/* A C expression for the cost of moving data from a register in class FROM to
+   one in class TO.  The classes are expressed using the enumeration values
+   such as `GENERAL_REGS'.  A value of 4 is the default; other values are
+   interpreted relative to that.
+
+   It is not required that the cost always equal 2 when FROM is the same as TO;
+   on some machines it is expensive to move between registers if they are not
+   general registers.
+
+   If reload sees an insn consisting of a single `set' between two hard
+   registers, and if `REGISTER_MOVE_COST' applied to their classes returns a
+   value of 2, reload does not check to ensure that the constraints of the insn
+   are met.  Setting a cost of other than 2 will allow reload to verify that
+   the constraints are met.  You should do this if the `movM' pattern's
+   constraints do not allow such copying.  */
+#define REGISTER_MOVE_COST(MODE, FROM, TO) frv_register_move_cost (FROM, TO)
+
+/* A C expression for the cost of moving data of mode M between a register and
+   memory.  A value of 2 is the default; this cost is relative to those in
+   `REGISTER_MOVE_COST'.
+
+   If moving between registers and memory is more expensive than between two
+   registers, you should define this macro to express the relative cost.  */
+#define MEMORY_MOVE_COST(M,C,I) 4
+
+/* A C expression for the cost of a branch instruction.  A value of 1 is the
+   default; other values are interpreted relative to that.  */
+
+/* Here are additional macros which do not specify precise relative costs, but
+   only that certain actions are more expensive than GNU CC would ordinarily
+   expect.  */
+
+/* We used to default the branch cost to 2, but I changed it to 1, to avoid
+   generating SCC instructions and or/and-ing them together, and then doing the
+   branch on the result, which collectively generate much worse code.  */
+#ifndef DEFAULT_BRANCH_COST
+#define DEFAULT_BRANCH_COST 1
+#endif
+
+#define BRANCH_COST frv_branch_cost_int
+
+/* Define this macro as a C expression which is nonzero if accessing less than
+   a word of memory (i.e. a `char' or a `short') is no faster than accessing a
+   word of memory, i.e., if such access require more than one instruction or if
+   there is no difference in cost between byte and (aligned) word loads.
+
+   When this macro is not defined, the compiler will access a field by finding
+   the smallest containing object; when it is defined, a fullword load will be
+   used if alignment permits.  Unless bytes accesses are faster than word
+   accesses, using word accesses is preferable since it may eliminate
+   subsequent memory access if subsequent accesses occur to other fields in the
+   same word of the structure, but to different bytes.  */
+#define SLOW_BYTE_ACCESS 1
+
+/* Define this macro if zero-extension (of a `char' or `short' to an `int') can
+   be done faster if the destination is a register that is known to be zero.
+
+   If you define this macro, you must have instruction patterns that recognize
+   RTL structures like this:
+
+        (set (strict_low_part (subreg:QI (reg:SI ...) 0)) ...)
+
+   and likewise for `HImode'.  */
+#define SLOW_ZERO_EXTEND 0
+
+/* Define this macro if it is as good or better to call a constant function
+   address than to call an address kept in a register.  */
+#define NO_FUNCTION_CSE
+
+/* Define this macro if it is as good or better for a function to call itself
+   with an explicit address than to call an address kept in a register.  */
+#define NO_RECURSIVE_FUNCTION_CSE
+
+\f
+/* Dividing the output into sections.  */
+
+/* A C expression whose value is a string containing the assembler operation
+   that should precede instructions and read-only data.  Normally `".text"' is
+   right.  */
+#define TEXT_SECTION_ASM_OP "\t.text"
+
+/* A C expression whose value is a string containing the assembler operation to
+   identify the following data as writable initialized data.  Normally
+   `".data"' is right.  */
+#define DATA_SECTION_ASM_OP "\t.data"
+
+/* If defined, a C expression whose value is a string containing the
+   assembler operation to identify the following data as
+   uninitialized global data.  If not defined, and neither
+   `ASM_OUTPUT_BSS' nor `ASM_OUTPUT_ALIGNED_BSS' are defined,
+   uninitialized global data will be output in the data section if
+   `-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be
+   used.  */
+#define BSS_SECTION_ASM_OP "\t.section .bss,\"aw\""
+
+/* Short Data Support */
+#define SDATA_SECTION_ASM_OP   "\t.section .sdata,\"aw\""
+#define SBSS_SECTION_ASM_OP    "\t.section .sbss,\"aw\""
+
+/* On svr4, we *do* have support for the .init and .fini sections, and we
+   can put stuff in there to be executed before and after `main'.  We let
+   crtstuff.c and other files know this by defining the following symbols.
+   The definitions say how to change sections to the .init and .fini
+   sections.  This is the same for all known svr4 assemblers.
+
+   The standard System V.4 macros will work, but they look ugly in the
+   assembly output, so redefine them.  */
+
+#undef INIT_SECTION_ASM_OP
+#undef FINI_SECTION_ASM_OP
+#define INIT_SECTION_ASM_OP    "\t.section .init,\"ax\""
+#define FINI_SECTION_ASM_OP    "\t.section .fini,\"ax\""
+
+/* A C expression whose value is a string containing the assembler operation to
+   switch to the fixup section that records all initialized pointers in a -fpic
+   program so they can be changed program startup time if the program is loaded
+   at a different address than linked for.  */
+#define FIXUP_SECTION_ASM_OP   "\t.section .rofixup,\"a\""
+
+/* A list of names for sections other than the standard two, which are
+   `in_text' and `in_data'.  You need not define this macro
+   on a system with no other sections (that GCC needs to use).  */
+#undef  EXTRA_SECTIONS
+#define EXTRA_SECTIONS in_sdata, in_sbss, in_const, in_fixup
+
+/* One or more functions to be defined in "varasm.c".  These
+   functions should do jobs analogous to those of `text_section' and
+   `data_section', for your additional sections.  Do not define this
+   macro if you do not define `EXTRA_SECTIONS'.  */
+#undef  EXTRA_SECTION_FUNCTIONS
+#define EXTRA_SECTION_FUNCTIONS                                         \
+SDATA_SECTION_FUNCTION                                                  \
+SBSS_SECTION_FUNCTION                                                  \
+FIXUP_SECTION_FUNCTION
+
+
+#define SDATA_SECTION_FUNCTION                                         \
+void                                                                   \
+sdata_section ()                                                       \
+{                                                                      \
+  if (in_section != in_sdata)                                          \
+    {                                                                  \
+      fprintf (asm_out_file, "%s\n", SDATA_SECTION_ASM_OP);            \
+      in_section = in_sdata;                                           \
+    }                                                                  \
+}                                                                      \
+
+#define SBSS_SECTION_FUNCTION                                          \
+void                                                                   \
+sbss_section ()                                                                \
+{                                                                      \
+  if (in_section != in_sbss)                                           \
+    {                                                                  \
+      fprintf (asm_out_file, "%s\n", SBSS_SECTION_ASM_OP);             \
+      in_section = in_sbss;                                            \
+    }                                                                  \
+}                                                                      \
+
+#define FIXUP_SECTION_FUNCTION                                         \
+void                                                                   \
+fixup_section ()                                                       \
+{                                                                      \
+  if (in_section != in_fixup)                                          \
+    {                                                                  \
+      fprintf (asm_out_file, "%s\n", FIXUP_SECTION_ASM_OP);            \
+      in_section = in_fixup;                                           \
+    }                                                                  \
+}                                                                      \
+
+/* A C statement or statements to switch to the appropriate section for output
+   of EXP.  You can assume that EXP is either a `VAR_DECL' node or a constant
+   of some sort.  RELOC indicates whether the initial value of EXP requires
+   link-time relocations.  Select the section by calling `text_section' or one
+   of the alternatives for other sections.
+
+   Do not define this macro if you put all read-only variables and constants in
+   the read-only data section (usually the text section).
+
+   Defined in svr4.h.  */
+#undef SELECT_SECTION
+#define SELECT_SECTION(EXP, RELOC, ALIGN) frv_select_section ((EXP), (RELOC))
+
+/* A C statement or statements to switch to the appropriate section for output
+   of RTX in mode MODE.  You can assume that RTX is some kind of constant in
+   RTL.  The argument MODE is redundant except in the case of a `const_int'
+   rtx.  Select the section by calling `text_section' or one of the
+   alternatives for other sections.
+
+   Do not define this macro if you put all constants in the read-only data
+   section.
+
+   Defined in svr4.h.  */
+#undef SELECT_RTX_SECTION
+#define SELECT_RTX_SECTION(MODE, RTX, ALIGN) frv_select_rtx_section (MODE, RTX)
+
+#define SDATA_FLAG_CHAR '@'
+
+#define SDATA_NAME_P(NAME) (*(NAME) == SDATA_FLAG_CHAR)
+
+#define ENCODE_SECTION_INFO(DECL, FIRST)       \
+  do                                           \
+    {                                          \
+      if (FIRST)                               \
+        frv_encode_section_info (DECL);                \
+    }                                          \
+  while (0)
+
+/* Decode SYM_NAME and store the real name part in VAR, sans
+   the characters that encode section info.  Define this macro if
+   ENCODE_SECTION_INFO alters the symbol's name string.  */
+
+#define STRIP_NAME_ENCODING(VAR, SYMBOL_NAME)                  \
+  do                                                           \
+    {                                                          \
+      const char * _name = (SYMBOL_NAME);                      \
+                                                               \
+      while (* _name == '*' || * _name == SDATA_FLAG_CHAR)     \
+       _name ++;                                               \
+      (VAR) = _name;                                           \
+    }                                                          \
+  while (0)
+
+\f
+/* Position Independent Code.  */
+
+/* A C expression that is nonzero if X is a legitimate immediate operand on the
+   target machine when generating position independent code.  You can assume
+   that X satisfies `CONSTANT_P', so you need not check this.  You can also
+   assume FLAG_PIC is true, so you need not check it either.  You need not
+   define this macro if all constants (including `SYMBOL_REF') can be immediate
+   operands when generating position independent code.  */
+#define LEGITIMATE_PIC_OPERAND_P(X)                                    \
+  (   GET_CODE (X) == CONST_INT                                                \
+   || GET_CODE (X) == CONST_DOUBLE                                     \
+   || (GET_CODE (X) == HIGH && GET_CODE (XEXP (X, 0)) == CONST_INT)    \
+   || GET_CODE (X) == CONSTANT_P_RTX)
+
+\f
+/* The Overall Framework of an Assembler File.  */
+
+/* A C string constant describing how to begin a comment in the target
+   assembler language.  The compiler assumes that the comment will end at the
+   end of the line.  */
+#define ASM_COMMENT_START ";"
+
+/* A C string constant for text to be output before each `asm' statement or
+   group of consecutive ones.  Normally this is `"#APP"', which is a comment
+   that has no effect on most assemblers but tells the GNU assembler that it
+   must check the lines that follow for all valid assembler constructs.  */
+#define ASM_APP_ON "#APP\n"
+
+/* A C string constant for text to be output after each `asm' statement or
+   group of consecutive ones.  Normally this is `"#NO_APP"', which tells the
+   GNU assembler to resume making the time-saving assumptions that are valid
+   for ordinary compiler output.  */
+#define ASM_APP_OFF "#NO_APP\n"
+
+\f
+/* Output of Data.  */
+
+/* This is how to output a label to dwarf/dwarf2.  */
+#define ASM_OUTPUT_DWARF_ADDR(STREAM, LABEL)                           \
+do {                                                                   \
+  fprintf (STREAM, "\t.picptr\t");                                     \
+  assemble_name (STREAM, LABEL);                                       \
+} while (0)
+
+/* Whether to emit the gas specific dwarf2 line number support.  */
+#define DWARF2_ASM_LINE_DEBUG_INFO (TARGET_DEBUG_LOC)
+\f
+/* Output of Uninitialized Variables.  */
+
+/* A C statement (sans semicolon) to output to the stdio stream STREAM the
+   assembler definition of a local-common-label named NAME whose size is SIZE
+   bytes.  The variable ROUNDED is the size rounded up to whatever alignment
+   the caller wants.
+
+   Use the expression `assemble_name (STREAM, NAME)' to output the name itself;
+   before and after that, output the additional assembler syntax for defining
+   the name, and a newline.
+
+   This macro controls how the assembler definitions of uninitialized static
+   variables are output.  */
+#undef ASM_OUTPUT_LOCAL
+
+/* Like `ASM_OUTPUT_LOCAL' except takes the required alignment as a separate,
+   explicit argument.  If you define this macro, it is used in place of
+   `ASM_OUTPUT_LOCAL', and gives you more flexibility in handling the required
+   alignment of the variable.  The alignment is specified as the number of
+   bits.
+
+   Defined in svr4.h.  */
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+
+/* This is for final.c, because it is used by ASM_DECLARE_OBJECT_NAME.  */
+extern int size_directive_output;
+
+/* Like `ASM_OUTPUT_ALIGNED_LOCAL' except that it takes an additional
+   parameter - the DECL of variable to be output, if there is one.
+   This macro can be called with DECL == NULL_TREE.  If you define
+   this macro, it is used in place of `ASM_OUTPUT_LOCAL' and
+   `ASM_OUTPUT_ALIGNED_LOCAL', and gives you more flexibility in
+   handling the destination of the variable.  */
+#undef ASM_OUTPUT_ALIGNED_DECL_LOCAL
+#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(STREAM, DECL, NAME, SIZE, ALIGN) \
+do {                                                                           \
+  if (SDATA_NAME_P (NAME))                                                     \
+    sbss_section ();                                                   \
+  else                                                                         \
+     bss_section ();                                                   \
+  ASM_OUTPUT_ALIGN (STREAM, floor_log2 ((ALIGN) / BITS_PER_UNIT));             \
+  ASM_DECLARE_OBJECT_NAME (STREAM, NAME, DECL);                                \
+  ASM_OUTPUT_SKIP (STREAM, (SIZE) ? (SIZE) : 1);                               \
+} while (0)
+
+\f
+/* Output and Generation of Labels.  */
+
+/* A C statement (sans semicolon) to output to the stdio stream STREAM the
+   assembler definition of a label named NAME.  Use the expression
+   `assemble_name (STREAM, NAME)' to output the name itself; before and after
+   that, output the additional assembler syntax for defining the name, and a
+   newline.  */
+#define ASM_OUTPUT_LABEL(STREAM, NAME)                                 \
+do {                                                                   \
+  assemble_name (STREAM, NAME);                                                \
+  fputs (":\n", STREAM);                                               \
+} while (0)
+
+/* A C statement (sans semicolon) to output to the stdio stream STREAM some
+   commands that will make the label NAME global; that is, available for
+   reference from other files.  Use the expression `assemble_name (STREAM,
+   NAME)' to output the name itself; before and after that, output the
+   additional assembler syntax for making that name global, and a newline.  */
+#define ASM_GLOBALIZE_LABEL(STREAM, NAME)                              \
+do {                                                                   \
+  fputs ("\t.globl ", STREAM);                                         \
+  assemble_name (STREAM, NAME);                                                \
+  fputs ("\n", STREAM);                                                        \
+} while (0)
+
+/* A C statement (sans semicolon) to output to the stdio stream STREAM a
+   reference in assembler syntax to a label named NAME.  This should add `_' to
+   the front of the name, if that is customary on your operating system, as it
+   is in most Berkeley Unix systems.  This macro is used in `assemble_name'.  */
+#undef ASM_OUTPUT_LABELREF
+#define ASM_OUTPUT_LABELREF(STREAM, NAME)                              \
+do {                                                                   \
+  const char *_name = (NAME);                                          \
+  while (*_name == '*' || *_name == SDATA_FLAG_CHAR)                   \
+    _name++;                                                           \
+  asm_fprintf (STREAM, "%U%s", _name);                                 \
+} while (0)
+
+/* A C statement to store into the string STRING a label whose name is made
+   from the string PREFIX and the number NUM.
+
+   This string, when output subsequently by `assemble_name', should produce the
+   output that `ASM_OUTPUT_INTERNAL_LABEL' would produce with the same PREFIX
+   and NUM.
+
+   If the string begins with `*', then `assemble_name' will output the rest of
+   the string unchanged.  It is often convenient for
+   `ASM_GENERATE_INTERNAL_LABEL' to use `*' in this way.  If the string doesn't
+   start with `*', then `ASM_OUTPUT_LABELREF' gets to output the string, and
+   may change it.  (Of course, `ASM_OUTPUT_LABELREF' is also part of your
+   machine description, so you should know what it does on your machine.)
+
+   Defined in svr4.h.  */
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM)                        \
+do {                                                                   \
+  sprintf (LABEL, "*.%s%ld", PREFIX, (long)NUM);                       \
+} while (0)
+
+/* A C expression to assign to OUTVAR (which is a variable of type `char *') a
+   newly allocated string made from the string NAME and the number NUMBER, with
+   some suitable punctuation added.  Use `alloca' to get space for the string.
+
+   The string will be used as an argument to `ASM_OUTPUT_LABELREF' to produce
+   an assembler label for an internal static variable whose name is NAME.
+   Therefore, the string must be such as to result in valid assembler code.
+   The argument NUMBER is different each time this macro is executed; it
+   prevents conflicts between similarly-named internal static variables in
+   different scopes.
+
+   Ideally this string should not be a valid C identifier, to prevent any
+   conflict with the user's own symbols.  Most assemblers allow periods or
+   percent signs in assembler symbols; putting at least one of these between
+   the name and the number will suffice.  */
+#define ASM_FORMAT_PRIVATE_NAME(OUTVAR, NAME, NUMBER)                  \
+do {                                                                   \
+  (OUTVAR) = (char *) alloca (strlen ((NAME)) + 12);                   \
+  sprintf ((OUTVAR), "%s.%ld", (NAME), (long)(NUMBER));                        \
+} while (0)
+
+\f
+/* Macros Controlling Initialization Routines.  */
+
+/* If defined, a C string constant for the assembler operation to identify the
+   following data as initialization code.  If not defined, GNU CC will assume
+   such a section does not exist.  When you are using special sections for
+   initialization and termination functions, this macro also controls how
+   `crtstuff.c' and `libgcc2.c' arrange to run the initialization functions.
+
+   Defined in svr4.h.  */
+#undef INIT_SECTION_ASM_OP
+
+/* If defined, `main' will call `__main' despite the presence of
+   `INIT_SECTION_ASM_OP'.  This macro should be defined for systems where the
+   init section is not actually run automatically, but is still useful for
+   collecting the lists of constructors and destructors.  */
+#define INVOKE__main
+
+/* Output appropriate code tp call a static constructor.  */
+#undef  ASM_OUTPUT_CONSTRUCTOR
+#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME)                            \
+do {                                                                   \
+  ctors_section ();                                                    \
+  fprintf (STREAM, "\t.picptr\t");                                     \
+  assemble_name (STREAM, NAME);                                                \
+  fprintf (STREAM, "\n");                                                      \
+} while (0)
+
+/* Output appropriate code tp call a static destructor.  */
+#undef  ASM_OUTPUT_DESTRUCTOR
+#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME)                             \
+do {                                                                   \
+  dtors_section ();                                                    \
+  fprintf (STREAM, "\t.picptr\t");                                     \
+  assemble_name (STREAM, NAME);                                                \
+  fprintf (STREAM, "\n");                                                      \
+} while (0)
+
+\f
+/* Output of Assembler Instructions.  */
+
+/* A C initializer containing the assembler's names for the machine registers,
+   each one as a C string constant.  This is what translates register numbers
+   in the compiler into assembler language.  */
+#define REGISTER_NAMES                                                 \
+{                                                                      \
+ "gr0",  "sp",   "fp",   "gr3",  "gr4",  "gr5",  "gr6",  "gr7",                \
+  "gr8",  "gr9",  "gr10", "gr11", "gr12", "gr13", "gr14", "gr15",      \
+  "gr16", "gr17", "gr18", "gr19", "gr20", "gr21", "gr22", "gr23",      \
+  "gr24", "gr25", "gr26", "gr27", "gr28", "gr29", "gr30", "gr31",      \
+  "gr32", "gr33", "gr34", "gr35", "gr36", "gr37", "gr38", "gr39",      \
+  "gr40", "gr41", "gr42", "gr43", "gr44", "gr45", "gr46", "gr47",      \
+  "gr48", "gr49", "gr50", "gr51", "gr52", "gr53", "gr54", "gr55",      \
+  "gr56", "gr57", "gr58", "gr59", "gr60", "gr61", "gr62", "gr63",      \
+                                                                       \
+  "fr0",  "fr1",  "fr2",  "fr3",  "fr4",  "fr5",  "fr6",  "fr7",       \
+  "fr8",  "fr9",  "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",      \
+  "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23",      \
+  "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31",      \
+  "fr32", "fr33", "fr34", "fr35", "fr36", "fr37", "fr38", "fr39",      \
+  "fr40", "fr41", "fr42", "fr43", "fr44", "fr45", "fr46", "fr47",      \
+  "fr48", "fr49", "fr50", "fr51", "fr52", "fr53", "fr54", "fr55",      \
+  "fr56", "fr57", "fr58", "fr59", "fr60", "fr61", "fr62", "fr63",      \
+                                                                       \
+  "fcc0", "fcc1", "fcc2", "fcc3", "icc0", "icc1", "icc2", "icc3",      \
+  "cc0",  "cc1",  "cc2",  "cc3",  "cc4",  "cc5",  "cc6",  "cc7",       \
+  "acc0", "acc1", "acc2", "acc3", "acc4", "acc5", "acc6", "acc7",      \
+  "accg0","accg1","accg2","accg3","accg4","accg5","accg6","accg7",     \
+  "ap",   "lr",   "lcr"                                                        \
+}
+
+/* Define this macro if you are using an unusual assembler that
+   requires different names for the machine instructions.
+
+   The definition is a C statement or statements which output an
+   assembler instruction opcode to the stdio stream STREAM.  The
+   macro-operand PTR is a variable of type `char *' which points to
+   the opcode name in its "internal" form--the form that is written
+   in the machine description.  The definition should output the
+   opcode name to STREAM, performing any translation you desire, and
+   increment the variable PTR to point at the end of the opcode so
+   that it will not be output twice.
+
+   In fact, your macro definition may process less than the entire
+   opcode name, or more than the opcode name; but if you want to
+   process text that includes `%'-sequences to substitute operands,
+   you must take care of the substitution yourself.  Just be sure to
+   increment PTR over whatever text should not be output normally.
+
+   If you need to look at the operand values, they can be found as the
+   elements of `recog_operand'.
+
+   If the macro definition does nothing, the instruction is output in
+   the usual way.  */
+
+#define ASM_OUTPUT_OPCODE(STREAM, PTR)\
+   (PTR) = frv_asm_output_opcode (STREAM, PTR)
+
+/* If defined, a C statement to be executed just prior to the output
+   of assembler code for INSN, to modify the extracted operands so
+   they will be output differently.
+
+   Here the argument OPVEC is the vector containing the operands
+   extracted from INSN, and NOPERANDS is the number of elements of
+   the vector which contain meaningful data for this insn.  The
+   contents of this vector are what will be used to convert the insn
+   template into assembler code, so you can change the assembler
+   output by changing the contents of the vector.
+
+   This macro is useful when various assembler syntaxes share a single
+   file of instruction patterns; by defining this macro differently,
+   you can cause a large class of instructions to be output
+   differently (such as with rearranged operands).  Naturally,
+   variations in assembler syntax affecting individual insn patterns
+   ought to be handled by writing conditional output routines in
+   those patterns.
+
+   If this macro is not defined, it is equivalent to a null statement.  */
+
+#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS)\
+  frv_final_prescan_insn (INSN, OPVEC, NOPERANDS)
+
+
+/* A C compound statement to output to stdio stream STREAM the assembler syntax
+   for an instruction operand X.  X is an RTL expression.
+
+   CODE is a value that can be used to specify one of several ways of printing
+   the operand.  It is used when identical operands must be printed differently
+   depending on the context.  CODE comes from the `%' specification that was
+   used to request printing of the operand.  If the specification was just
+   `%DIGIT' then CODE is 0; if the specification was `%LTR DIGIT' then CODE is
+   the ASCII code for LTR.
+
+   If X is a register, this macro should print the register's name.  The names
+   can be found in an array `reg_names' whose type is `char *[]'.  `reg_names'
+   is initialized from `REGISTER_NAMES'.
+
+   When the machine description has a specification `%PUNCT' (a `%' followed by
+   a punctuation character), this macro is called with a null pointer for X and
+   the punctuation character for CODE.  */
+#define PRINT_OPERAND(STREAM, X, CODE) frv_print_operand (STREAM, X, CODE)
+
+/* A C expression which evaluates to true if CODE is a valid punctuation
+   character for use in the `PRINT_OPERAND' macro.  If
+   `PRINT_OPERAND_PUNCT_VALID_P' is not defined, it means that no punctuation
+   characters (except for the standard one, `%') are used in this way.  */
+/* . == gr0
+   # == hint operand -- always zero for now
+   @ == small data base register (gr16)
+   ~ == pic register (gr17)
+   * == temporary integer CCR register (cr3)
+   & == temporary integer ICC register (icc3)  */
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE)                              \
+((CODE) == '.' || (CODE) == '#' || (CODE) == SDATA_FLAG_CHAR || (CODE) == '~'  \
+ || (CODE) == '*' || (CODE) == '&')
+
+/* A C compound statement to output to stdio stream STREAM the assembler syntax
+   for an instruction operand that is a memory reference whose address is X.  X
+   is an RTL expression.
+
+   On some machines, the syntax for a symbolic address depends on the section
+   that the address refers to.  On these machines, define the macro
+   `ENCODE_SECTION_INFO' to store the information into the `symbol_ref', and
+   then check for it here.
+
+   This declaration must be present.  */
+#define PRINT_OPERAND_ADDRESS(STREAM, X) frv_print_operand_address (STREAM, X)
+
+/* If defined, C string expressions to be used for the `%R', `%L', `%U', and
+   `%I' options of `asm_fprintf' (see `final.c').  These are useful when a
+   single `md' file must support multiple assembler formats.  In that case, the
+   various `tm.h' files can define these macros differently.
+
+   USER_LABEL_PREFIX is defined in svr4.h.  */
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
+#define REGISTER_PREFIX ""
+#define LOCAL_LABEL_PREFIX "."
+#define IMMEDIATE_PREFIX "#"
+
+\f
+/* Output of dispatch tables.  */
+
+/* This macro should be provided on machines where the addresses in a dispatch
+   table are relative to the table's own address.
+
+   The definition should be a C statement to output to the stdio stream STREAM
+   an assembler pseudo-instruction to generate a difference between two labels.
+   VALUE and REL are the numbers of two internal labels.  The definitions of
+   these labels are output using `ASM_OUTPUT_INTERNAL_LABEL', and they must be
+   printed in the same way here.  For example,
+
+        fprintf (STREAM, "\t.word L%d-L%d\n", VALUE, REL)  */
+#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL) \
+fprintf (STREAM, "\t.word .L%d-.L%d\n", VALUE, REL)
+
+/* This macro should be provided on machines where the addresses in a dispatch
+   table are absolute.
+
+   The definition should be a C statement to output to the stdio stream STREAM
+   an assembler pseudo-instruction to generate a reference to a label.  VALUE
+   is the number of an internal label whose definition is output using
+   `ASM_OUTPUT_INTERNAL_LABEL'.  For example,
+
+        fprintf (STREAM, "\t.word L%d\n", VALUE)  */
+#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
+fprintf (STREAM, "\t.word .L%d\n", VALUE)
+
+/* Define this if the label before a jump-table needs to be output specially.
+   The first three arguments are the same as for `ASM_OUTPUT_INTERNAL_LABEL';
+   the fourth argument is the jump-table which follows (a `jump_insn'
+   containing an `addr_vec' or `addr_diff_vec').
+
+   This feature is used on system V to output a `swbeg' statement for the
+   table.
+
+   If this macro is not defined, these labels are output with
+   `ASM_OUTPUT_INTERNAL_LABEL'.
+
+   Defined in svr4.h.  */
+/* When generating embedded PIC or mips16 code we want to put the jump
+   table in the .text section.  In all other cases, we want to put the
+   jump table in the .rdata section.  Unfortunately, we can't use
+   JUMP_TABLES_IN_TEXT_SECTION, because it is not conditional.
+   Instead, we use ASM_OUTPUT_CASE_LABEL to switch back to the .text
+   section if appropriate.  */
+
+#undef  ASM_OUTPUT_CASE_LABEL
+#define ASM_OUTPUT_CASE_LABEL(STREAM, PREFIX, NUM, TABLE)               \
+do {                                                                    \
+  if (flag_pic)                                                         \
+    function_section (current_function_decl);                           \
+  ASM_OUTPUT_INTERNAL_LABEL (STREAM, PREFIX, NUM);                      \
+} while (0)
+
+/* Define this to determine whether case statement labels are relative to
+   the start of the case statement or not.  */
+
+#define CASE_VECTOR_PC_RELATIVE (flag_pic)
+
+\f
+/* Assembler Commands for Exception Regions.  */
+
+/* Define this macro to 0 if your target supports DWARF 2 frame unwind
+   information, but it does not yet work with exception handling.  Otherwise,
+   if your target supports this information (if it defines
+   `INCOMING_RETURN_ADDR_RTX' and either `UNALIGNED_INT_ASM_OP' or
+   `OBJECT_FORMAT_ELF'), GCC will provide a default definition of 1.
+
+   If this macro is defined to 1, the DWARF 2 unwinder will be the default
+   exception handling mechanism; otherwise, setjmp/longjmp will be used by
+   default.
+
+   If this macro is defined to anything, the DWARF 2 unwinder will be used
+   instead of inline unwinders and __unwind_function in the non-setjmp case.  */
+#define DWARF2_UNWIND_INFO 1
+
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (LR_REGNO)
+\f
+/* Assembler Commands for Alignment.  */
+
+/* A C statement to output to the stdio stream STREAM an assembler instruction
+   to advance the location counter by NBYTES bytes.  Those bytes should be zero
+   when loaded.  NBYTES will be a C expression of type `int'.
+
+   Defined in svr4.h.  */
+#undef  ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \
+  fprintf (STREAM, "\t.zero\t%u\n", (NBYTES))
+
+/* A C statement to output to the stdio stream STREAM an assembler command to
+   advance the location counter to a multiple of 2 to the POWER bytes.  POWER
+   will be a C expression of type `int'.  */
+#define ASM_OUTPUT_ALIGN(STREAM, POWER) \
+  fprintf ((STREAM), "\t.p2align %d\n", (POWER))
+
+\f
+/* Macros Affecting all Debug Formats.  */
+
+/* A C expression that returns the DBX register number for the compiler
+   register number REGNO.  In simple cases, the value of this expression may be
+   REGNO itself.  But sometimes there are some registers that the compiler
+   knows about and DBX does not, or vice versa.  In such cases, some register
+   may need to have one number in the compiler and another for DBX.
+
+   If two registers have consecutive numbers inside GNU CC, and they can be
+   used as a pair to hold a multiword value, then they *must* have consecutive
+   numbers after renumbering with `DBX_REGISTER_NUMBER'.  Otherwise, debuggers
+   will be unable to access such a pair, because they expect register pairs to
+   be consecutive in their own numbering scheme.
+
+   If you find yourself defining `DBX_REGISTER_NUMBER' in way that does not
+   preserve register pairs, then what you must do instead is redefine the
+   actual register numbering scheme.
+
+   This declaration is required.  */
+#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+
+/* A C expression that returns the type of debugging output GNU CC produces
+   when the user specifies `-g' or `-ggdb'.  Define this if you have arranged
+   for GNU CC to support more than one format of debugging output.  Currently,
+   the allowable values are `DBX_DEBUG', `SDB_DEBUG', `DWARF_DEBUG',
+   `DWARF2_DEBUG', and `XCOFF_DEBUG'.
+
+   The value of this macro only affects the default debugging output; the user
+   can always get a specific type of output by using `-gstabs', `-gcoff',
+   `-gdwarf-1', `-gdwarf-2', or `-gxcoff'.
+
+   Defined in svr4.h.  */
+#undef  PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+/* This version of UNIQUE_SECTION overrides the one in elfos.h.  We
+   need to check whether DECL is destined for the .sdata section.  */
+
+#undef  UNIQUE_SECTION
+#define UNIQUE_SECTION(DECL,RELOC) frv_unique_section (DECL, RELOC)
+\f
+/* Miscellaneous Parameters.  */
+
+/* Define this if you have defined special-purpose predicates in the file
+   `MACHINE.c'.  This macro is called within an initializer of an array of
+   structures.  The first field in the structure is the name of a predicate and
+   the second field is an array of rtl codes.  For each predicate, list all rtl
+   codes that can be in expressions matched by the predicate.  The list should
+   have a trailing comma.  Here is an example of two entries in the list for a
+   typical RISC machine:
+
+        #define PREDICATE_CODES \
+          {"gen_reg_rtx_operand", {SUBREG, REG}},  \
+          {"reg_or_short_cint_operand", {SUBREG, REG, CONST_INT}},
+
+   Defining this macro does not affect the generated code (however, incorrect
+   definitions that omit an rtl code that may be matched by the predicate can
+   cause the compiler to malfunction).  Instead, it allows the table built by
+   `genrecog' to be more compact and efficient, thus speeding up the compiler.
+   The most important predicates to include in the list specified by this macro
+   are thoses used in the most insn patterns.  */
+#define PREDICATE_CODES                                                        \
+  { "integer_register_operand",                { REG, SUBREG }},               \
+  { "frv_load_operand",                        { REG, SUBREG, MEM }},          \
+  { "gpr_no_subreg_operand",           { REG }},                       \
+  { "gpr_or_fpr_operand",              { REG, SUBREG }},               \
+  { "gpr_or_int12_operand",            { REG, SUBREG, CONST_INT }},    \
+  { "gpr_fpr_or_int12_operand",                { REG, SUBREG, CONST_INT }},    \
+  { "gpr_or_int10_operand",            { REG, SUBREG, CONST_INT }},    \
+  { "gpr_or_int_operand",              { REG, SUBREG, CONST_INT }},    \
+  { "move_source_operand",             { REG, SUBREG, CONST_INT, MEM,  \
+                                         CONST_DOUBLE, CONST,          \
+                                         SYMBOL_REF, LABEL_REF }},     \
+  { "move_destination_operand",                { REG, SUBREG, MEM }},          \
+  { "condexec_source_operand",         { REG, SUBREG, CONST_INT, MEM,  \
+                                         CONST_DOUBLE }},              \
+  { "condexec_dest_operand",           { REG, SUBREG, MEM }},          \
+  { "reg_or_0_operand",                        { REG, SUBREG, CONST_INT }},    \
+  { "lr_operand",                      { REG }},                       \
+  { "gpr_or_memory_operand",           { REG, SUBREG, MEM }},          \
+  { "fpr_or_memory_operand",           { REG, SUBREG, MEM }},          \
+  { "int12_operand",                   { CONST_INT }},                 \
+  { "int_2word_operand",               { CONST_INT, CONST_DOUBLE,      \
+                                         SYMBOL_REF, LABEL_REF, CONST }}, \
+  { "pic_register_operand",            { REG }},                       \
+  { "pic_symbolic_operand",            { SYMBOL_REF, LABEL_REF, CONST }}, \
+  { "small_data_register_operand",     { REG }},                       \
+  { "small_data_symbolic_operand",     { SYMBOL_REF, CONST }},         \
+  { "icc_operand",                     { REG }},                       \
+  { "fcc_operand",                     { REG }},                       \
+  { "cc_operand",                      { REG }},                       \
+  { "icr_operand",                     { REG }},                       \
+  { "fcr_operand",                     { REG }},                       \
+  { "cr_operand",                      { REG }},                       \
+  { "fpr_operand",                     { REG, SUBREG }},               \
+  { "even_reg_operand",                        { REG, SUBREG }},               \
+  { "odd_reg_operand",                 { REG, SUBREG }},               \
+  { "even_gpr_operand",                        { REG, SUBREG }},               \
+  { "odd_gpr_operand",                 { REG, SUBREG }},               \
+  { "quad_fpr_operand",                        { REG, SUBREG }},               \
+  { "even_fpr_operand",                        { REG, SUBREG }},               \
+  { "odd_fpr_operand",                 { REG, SUBREG }},               \
+  { "dbl_memory_one_insn_operand",     { MEM }},                       \
+  { "dbl_memory_two_insn_operand",     { MEM }},                       \
+  { "call_operand",                    { REG, SUBREG, PLUS, CONST_INT, \
+                                         SYMBOL_REF, LABEL_REF, CONST }}, \
+  { "upper_int16_operand",             { CONST_INT }},                 \
+  { "uint16_operand",                  { CONST_INT }},                 \
+  { "relational_operator",             { EQ, NE, LE, LT, GE, GT,       \
+                                         LEU, LTU, GEU, GTU }},        \
+  { "signed_relational_operator",      { EQ, NE, LE, LT, GE, GT }},    \
+  { "unsigned_relational_operator",    { LEU, LTU, GEU, GTU }},        \
+  { "float_relational_operator",       { EQ, NE, LE, LT, GE, GT }},    \
+  { "ccr_eqne_operator",               { EQ, NE }},                    \
+  { "minmax_operator",                 { SMIN, SMAX, UMIN, UMAX }},    \
+  { "condexec_si_binary_operator",     { PLUS, MINUS, AND, IOR, XOR,   \
+                                         ASHIFT, ASHIFTRT, LSHIFTRT }}, \
+  { "condexec_si_divide_operator",     { DIV, UDIV }},                 \
+  { "condexec_si_unary_operator",      { NOT, NEG }},                  \
+  { "condexec_sf_binary_operator",     { PLUS, MINUS, MULT, DIV }},    \
+  { "condexec_sf_unary_operator",      { ABS, NEG, SQRT }},            \
+  { "intop_compare_operator",          { PLUS, MINUS, AND, IOR, XOR,   \
+                                         ASHIFT, ASHIFTRT, LSHIFTRT }}, \
+  { "condexec_intop_cmp_operator",     { PLUS, MINUS, AND, IOR, XOR,   \
+                                         ASHIFT, ASHIFTRT, LSHIFTRT }}, \
+  { "fpr_or_int6_operand",             { REG, SUBREG, CONST_INT }},    \
+  { "int6_operand",                    { CONST_INT }},                 \
+  { "int5_operand",                    { CONST_INT }},                 \
+  { "uint5_operand",                   { CONST_INT }},                 \
+  { "uint4_operand",                   { CONST_INT }},                 \
+  { "uint1_operand",                   { CONST_INT }},                 \
+  { "acc_operand",                     { REG, SUBREG }},               \
+  { "even_acc_operand",                        { REG, SUBREG }},               \
+  { "quad_acc_operand",                        { REG, SUBREG }},               \
+  { "accg_operand",                    { REG, SUBREG }},
+
+/* An alias for a machine mode name.  This is the machine mode that elements of
+   a jump-table should have.  */
+#define CASE_VECTOR_MODE SImode
+
+/* Define this macro if operations between registers with integral mode smaller
+   than a word are always performed on the entire register.  Most RISC machines
+   have this property and most CISC machines do not.  */
+#define WORD_REGISTER_OPERATIONS
+
+/* Define this macro to be a C expression indicating when insns that read
+   memory in MODE, an integral mode narrower than a word, set the bits outside
+   of MODE to be either the sign-extension or the zero-extension of the data
+   read.  Return `SIGN_EXTEND' for values of MODE for which the insn
+   sign-extends, `ZERO_EXTEND' for which it zero-extends, and `NIL' for other
+   modes.
+
+   This macro is not called with MODE non-integral or with a width greater than
+   or equal to `BITS_PER_WORD', so you may return any value in this case.  Do
+   not define this macro if it would always return `NIL'.  On machines where
+   this macro is defined, you will normally define it as the constant
+   `SIGN_EXTEND' or `ZERO_EXTEND'.  */
+#define LOAD_EXTEND_OP(MODE) SIGN_EXTEND
+
+/* Define if loading short immediate values into registers sign extends.  */
+#define SHORT_IMMEDIATES_SIGN_EXTEND
+
+/* An alias for a tree code that is the easiest kind of division to compile
+   code for in the general case.  It may be `TRUNC_DIV_EXPR', `FLOOR_DIV_EXPR',
+   `CEIL_DIV_EXPR' or `ROUND_DIV_EXPR'.  These four division operators differ
+   in how they round the result to an integer.  `EASY_DIV_EXPR' is used when it
+   is permissible to use any of those kinds of division and the choice should
+   be made on the basis of efficiency.  */
+#define EASY_DIV_EXPR TRUNC_DIV_EXPR
+
+/* The maximum number of bytes that a single instruction can move quickly from
+   memory to memory.  */
+#define MOVE_MAX 8
+
+/* A C expression which is nonzero if on this machine it is safe to "convert"
+   an integer of INPREC bits to one of OUTPREC bits (where OUTPREC is smaller
+   than INPREC) by merely operating on it as if it had only OUTPREC bits.
+
+   On many machines, this expression can be 1.
+
+   When `TRULY_NOOP_TRUNCATION' returns 1 for a pair of sizes for modes for
+   which `MODES_TIEABLE_P' is 0, suboptimal code can result.  If this is the
+   case, making `TRULY_NOOP_TRUNCATION' return 0 in such cases may improve
+   things.  */
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+/* An alias for the machine mode for pointers.  On most machines, define this
+   to be the integer mode corresponding to the width of a hardware pointer;
+   `SImode' on 32-bit machine or `DImode' on 64-bit machines.  On some machines
+   you must define this to be one of the partial integer modes, such as
+   `PSImode'.
+
+   The width of `Pmode' must be at least as large as the value of
+   `POINTER_SIZE'.  If it is not equal, you must define the macro
+   `POINTERS_EXTEND_UNSIGNED' to specify how pointers are extended to `Pmode'.  */
+#define Pmode SImode
+
+/* An alias for the machine mode used for memory references to functions being
+   called, in `call' RTL expressions.  On most machines this should be
+   `QImode'.  */
+#define FUNCTION_MODE QImode
+
+/* Define this macro to handle System V style pragmas: #pragma pack and
+   #pragma weak.  Note, #pragma weak will only be supported if SUPPORT_WEAK is
+   defined.
+
+   Defined in svr4.h.  */
+#define HANDLE_SYSV_PRAGMA
+
+/* A C expression for the maximum number of instructions to execute via
+   conditional execution instructions instead of a branch.  A value of
+   BRANCH_COST+1 is the default if the machine does not use
+   cc0, and 1 if it does use cc0.  */
+#define MAX_CONDITIONAL_EXECUTE frv_condexec_insns
+
+/* Default value of MAX_CONDITIONAL_EXECUTE if no -mcond-exec-insns= */
+#define DEFAULT_CONDEXEC_INSNS 8
+
+/* A C expression to modify the code described by the conditional if
+   information CE_INFO, possibly updating the tests in TRUE_EXPR, and
+   FALSE_EXPR for converting if-then and if-then-else code to conditional
+   instructions.  Set either TRUE_EXPR or FALSE_EXPR to a null pointer if the
+   tests cannot be converted.  */
+#define IFCVT_MODIFY_TESTS(CE_INFO, TRUE_EXPR, FALSE_EXPR)             \
+frv_ifcvt_modify_tests (CE_INFO, &TRUE_EXPR, &FALSE_EXPR)
+
+/* A C expression to modify the code described by the conditional if
+   information CE_INFO, for the basic block BB, possibly updating the tests in
+   TRUE_EXPR, and FALSE_EXPR for converting the && and || parts of if-then or
+   if-then-else code to conditional instructions.  OLD_TRUE and OLD_FALSE are
+   the previous tests.  Set either TRUE_EXPR or FALSE_EXPR to a null pointer if
+   the tests cannot be converted.  */
+#define IFCVT_MODIFY_MULTIPLE_TESTS(CE_INFO, BB, TRUE_EXPR, FALSE_EXPR) \
+frv_ifcvt_modify_multiple_tests (CE_INFO, BB, &TRUE_EXPR, &FALSE_EXPR)
+
+/* A C expression to modify the code described by the conditional if
+   information CE_INFO with the new PATTERN in INSN.  If PATTERN is a null
+   pointer after the IFCVT_MODIFY_INSN macro executes, it is assumed that that
+   insn cannot be converted to be executed conditionally.  */
+#define IFCVT_MODIFY_INSN(CE_INFO, PATTERN, INSN) \
+(PATTERN) = frv_ifcvt_modify_insn (CE_INFO, PATTERN, INSN)
+
+/* A C expression to perform any final machine dependent modifications in
+   converting code to conditional execution in the code described by the
+   conditional if information CE_INFO.  */
+#define IFCVT_MODIFY_FINAL(CE_INFO) frv_ifcvt_modify_final (CE_INFO)
+
+/* A C expression to cancel any machine dependent modifications in converting
+   code to conditional execution in the code described by the conditional if
+   information CE_INFO.  */
+#define IFCVT_MODIFY_CANCEL(CE_INFO) frv_ifcvt_modify_cancel (CE_INFO)
+
+/* Initialize the extra fields provided by IFCVT_EXTRA_FIELDS.  */
+#define IFCVT_INIT_EXTRA_FIELDS(CE_INFO) frv_ifcvt_init_extra_fields (CE_INFO)
+
+/* Indicate how many instructions can be issued at the same time.  */
+#define ISSUE_RATE                                                     \
+(! TARGET_PACK ? 1                                                     \
+ : (frv_cpu_type == FRV_CPU_GENERIC                                    \
+    || frv_cpu_type == FRV_CPU_FR500                                   \
+    || frv_cpu_type == FRV_CPU_TOMCAT) ? 4                             \
+ : frv_cpu_type == FRV_CPU_FR400 ? 2 : 1)
+
+/* Set and clear whether this insn begins a VLIW insn.  */
+#define CLEAR_VLIW_START(INSN) PUT_MODE (INSN, VOIDmode)
+#define SET_VLIW_START(INSN) PUT_MODE (INSN, TImode)
+
+/* The definition of the following macro results in that the 2nd jump
+   optimization (after the 2nd insn scheduling) is minimal.  It is
+   necessary to define when start cycle marks of insns (TImode is used
+   for this) is used for VLIW insn packing.  Some jump optimizations
+   make such marks invalid.  These marks are corrected for some
+   (minimal) optimizations.  ??? Probably the macro is temporary.
+   Final solution could making the 2nd jump optimizations before the
+   2nd instruction scheduling or corrections of the marks for all jump
+   optimizations.  Although some jump optimizations are actually
+   deoptimizations for VLIW (super-scalar) processors.  */
+
+#define MINIMAL_SECOND_JUMP_OPTIMIZATION
+
+/* Return true if parallel operations are expected to be emitted via the
+   packing flag.  */
+#define PACKING_FLAG_USED_P() \
+(optimize && flag_schedule_insns_after_reload && ISSUE_RATE > 1)
+
+/* If the following macro is defined and non zero and deterministic
+   finite state automata are used for pipeline hazard recognition, the
+   code making resource-constrained software pipelining is on.  */
+#define RCSP_SOFTWARE_PIPELINING 1
+
+/* If the following macro is defined and non zero and deterministic
+   finite state automata are used for pipeline hazard recognition, we
+   will try to exchange insns in queue ready to improve the schedule.
+   The more macro value, the more tries will be made.  */
+#define FIRST_CYCLE_MULTIPASS_SCHEDULING 1
+
+/* The following macro is used only when value of
+   FIRST_CYCLE_MULTIPASS_SCHEDULING is nonzero.  The more macro value,
+   the more tries will be made to choose better schedule.  If the
+   macro value is zero or negative there will be no multi-pass
+   scheduling.  */
+#define FIRST_CYCLE_MULTIPASS_SCHEDULING_LOOKAHEAD frv_sched_lookahead
+
+/* Return true if a function is ok to be called as a sibcall.  */
+#define FUNCTION_OK_FOR_SIBCALL(DECL) 0
+
+enum frv_builtins
+{
+  FRV_BUILTIN_MAND,
+  FRV_BUILTIN_MOR,
+  FRV_BUILTIN_MXOR,
+  FRV_BUILTIN_MNOT,
+  FRV_BUILTIN_MAVEH,
+  FRV_BUILTIN_MSATHS,
+  FRV_BUILTIN_MSATHU,
+  FRV_BUILTIN_MADDHSS,
+  FRV_BUILTIN_MADDHUS,
+  FRV_BUILTIN_MSUBHSS,
+  FRV_BUILTIN_MSUBHUS,
+  FRV_BUILTIN_MPACKH,
+  FRV_BUILTIN_MQADDHSS,
+  FRV_BUILTIN_MQADDHUS,
+  FRV_BUILTIN_MQSUBHSS,
+  FRV_BUILTIN_MQSUBHUS,
+  FRV_BUILTIN_MUNPACKH,
+  FRV_BUILTIN_MDPACKH,
+  FRV_BUILTIN_MBTOH,
+  FRV_BUILTIN_MHTOB,
+  FRV_BUILTIN_MCOP1,
+  FRV_BUILTIN_MCOP2,
+  FRV_BUILTIN_MROTLI,
+  FRV_BUILTIN_MROTRI,
+  FRV_BUILTIN_MWCUT,
+  FRV_BUILTIN_MSLLHI,
+  FRV_BUILTIN_MSRLHI,
+  FRV_BUILTIN_MSRAHI,
+  FRV_BUILTIN_MEXPDHW,
+  FRV_BUILTIN_MEXPDHD,
+  FRV_BUILTIN_MMULHS,
+  FRV_BUILTIN_MMULHU,
+  FRV_BUILTIN_MMULXHS,
+  FRV_BUILTIN_MMULXHU,
+  FRV_BUILTIN_MMACHS,
+  FRV_BUILTIN_MMACHU,
+  FRV_BUILTIN_MMRDHS,
+  FRV_BUILTIN_MMRDHU,
+  FRV_BUILTIN_MQMULHS,
+  FRV_BUILTIN_MQMULHU,
+  FRV_BUILTIN_MQMULXHU,
+  FRV_BUILTIN_MQMULXHS,
+  FRV_BUILTIN_MQMACHS,
+  FRV_BUILTIN_MQMACHU,
+  FRV_BUILTIN_MCPXRS,
+  FRV_BUILTIN_MCPXRU,
+  FRV_BUILTIN_MCPXIS,
+  FRV_BUILTIN_MCPXIU,
+  FRV_BUILTIN_MQCPXRS,
+  FRV_BUILTIN_MQCPXRU,
+  FRV_BUILTIN_MQCPXIS,
+  FRV_BUILTIN_MQCPXIU,
+  FRV_BUILTIN_MCUT,
+  FRV_BUILTIN_MCUTSS,
+  FRV_BUILTIN_MWTACC,
+  FRV_BUILTIN_MWTACCG,
+  FRV_BUILTIN_MRDACC,
+  FRV_BUILTIN_MRDACCG,
+  FRV_BUILTIN_MTRAP,
+  FRV_BUILTIN_MCLRACC,
+  FRV_BUILTIN_MCLRACCA,
+  FRV_BUILTIN_MDUNPACKH,
+  FRV_BUILTIN_MBTOHE,
+  FRV_BUILTIN_MQXMACHS,
+  FRV_BUILTIN_MQXMACXHS,
+  FRV_BUILTIN_MQMACXHS,
+  FRV_BUILTIN_MADDACCS,
+  FRV_BUILTIN_MSUBACCS,
+  FRV_BUILTIN_MASACCS,
+  FRV_BUILTIN_MDADDACCS,
+  FRV_BUILTIN_MDSUBACCS,
+  FRV_BUILTIN_MDASACCS,
+  FRV_BUILTIN_MABSHS,
+  FRV_BUILTIN_MDROTLI,
+  FRV_BUILTIN_MCPLHI,
+  FRV_BUILTIN_MCPLI,
+  FRV_BUILTIN_MDCUTSSI,
+  FRV_BUILTIN_MQSATHS,
+  FRV_BUILTIN_MHSETLOS,
+  FRV_BUILTIN_MHSETLOH,
+  FRV_BUILTIN_MHSETHIS,
+  FRV_BUILTIN_MHSETHIH,
+  FRV_BUILTIN_MHDSETS,
+  FRV_BUILTIN_MHDSETH
+};
+
+#define MD_INIT_BUILTINS do { \
+    frv_init_builtins (); \
+  } while (0)
+
+#define MD_EXPAND_BUILTIN(EXP, TARGET, SUBTARGET, MODE, IGNORE) \
+    frv_expand_builtin ((EXP), (TARGET), (SUBTARGET), (MODE), (IGNORE))
+
+/* Enable prototypes on the call rtl functions.  */
+#define MD_CALL_PROTOTYPES 1
+
+extern GTY(()) rtx frv_compare_op0;                    /* operand save for */
+extern GTY(()) rtx frv_compare_op1;                    /* comparison generation */
+
+#endif /* __FRV_H__ */
diff --git a/gcc/config/frv/frv.md b/gcc/config/frv/frv.md
new file mode 100644 (file)
index 0000000..f166804
--- /dev/null
@@ -0,0 +1,7441 @@
+;; Frv Machine Description
+;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+;; Contributed by Red Hat, Inc.
+
+;; This file is part of GNU CC.
+
+;; GNU CC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU CC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU CC; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Unspec's used
+;; ::
+;; ::::::::::::::::::::
+
+(define_constants
+  [(UNSPEC_BLOCKAGE            0)
+   (UNSPEC_CC_TO_GPR           1)
+   (UNSPEC_GPR_TO_CC           2)
+   (UNSPEC_PIC_PROLOGUE                3)
+   (UNSPEC_CR_LOGIC            4)
+   (UNSPEC_STACK_ADJUST                5)
+   (UNSPEC_EH_RETURN_EPILOGUE  6)])
+
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Constraints
+;; ::
+;; ::::::::::::::::::::
+
+;; Standard Constraints
+;;
+;; `m' A memory operand is allowed, with any kind of address that the
+;;     machine supports in general.
+;;
+;; `o' A memory operand is allowed, but only if the address is
+;;     "offsettable".  This means that adding a small integer (actually, the
+;;     width in bytes of the operand, as determined by its machine mode) may be
+;;     added to the address and the result is also a valid memory address.
+;;
+;; `V' A memory operand that is not offsettable.  In other words,
+;;     anything that would fit the `m' constraint but not the `o' constraint.
+;;
+;; `<' A memory operand with autodecrement addressing (either
+;;     predecrement or postdecrement) is allowed.
+;;
+;; `>' A memory operand with autoincrement addressing (either
+;;     preincrement or postincrement) is allowed.
+;;
+;; `r' A register operand is allowed provided that it is in a general
+;;     register.
+;;
+;; `d', `a', `f', ...
+;;     Other letters can be defined in machine-dependent fashion to stand for
+;;     particular classes of registers.  `d', `a' and `f' are defined on the
+;;     68000/68020 to stand for data, address and floating point registers.
+;;
+;; `i' An immediate integer operand (one with constant value) is allowed.
+;;     This includes symbolic constants whose values will be known only at
+;;     assembly time.
+;;
+;; `n' An immediate integer operand with a known numeric value is allowed.
+;;     Many systems cannot support assembly-time constants for operands less
+;;     than a word wide.  Constraints for these operands should use `n' rather
+;;     than `i'.
+;;
+;; 'I' First machine-dependent integer constant (6 bit signed ints).
+;; 'J' Second machine-dependent integer constant (10 bit signed ints).
+;; 'K' Third machine-dependent integer constant (-2048).
+;; 'L' Fourth machine-dependent integer constant (16 bit signed ints).
+;; 'M' Fifth machine-dependent integer constant (16 bit unsigned ints).
+;; 'N' Sixth machine-dependent integer constant (-2047..-1).
+;; 'O' Seventh machine-dependent integer constant (zero).
+;; 'P' Eighth machine-dependent integer constant (1..2047).
+;;
+;;     Other letters in the range `I' through `P' may be defined in a
+;;     machine-dependent fashion to permit immediate integer operands with
+;;     explicit integer values in specified ranges.  For example, on the 68000,
+;;     `I' is defined to stand for the range of values 1 to 8.  This is the
+;;     range permitted as a shift count in the shift instructions.
+;;
+;; `E' An immediate floating operand (expression code `const_double') is
+;;     allowed, but only if the target floating point format is the same as
+;;     that of the host machine (on which the compiler is running).
+;;
+;; `F' An immediate floating operand (expression code `const_double') is
+;;     allowed.
+;;
+;; 'G' First machine-dependent const_double.
+;; 'H' Second machine-dependent const_double.
+;;
+;; `s' An immediate integer operand whose value is not an explicit
+;;     integer is allowed.
+;;
+;;     This might appear strange; if an insn allows a constant operand with a
+;;     value not known at compile time, it certainly must allow any known
+;;     value.  So why use `s' instead of `i'?  Sometimes it allows better code
+;;     to be generated.
+;;
+;;     For example, on the 68000 in a fullword instruction it is possible to
+;;     use an immediate operand; but if the immediate value is between -128 and
+;;     127, better code results from loading the value into a register and
+;;     using the register.  This is because the load into the register can be
+;;     done with a `moveq' instruction.  We arrange for this to happen by
+;;     defining the letter `K' to mean "any integer outside the range -128 to
+;;     127", and then specifying `Ks' in the operand constraints.
+;;
+;; `g' Any register, memory or immediate integer operand is allowed,
+;;     except for registers that are not general registers.
+;;
+;; `X' Any operand whatsoever is allowed, even if it does not satisfy
+;;     `general_operand'.  This is normally used in the constraint of a
+;;     `match_scratch' when certain alternatives will not actually require a
+;;     scratch register.
+;;
+;; `0' Match operand 0.
+;; `1' Match operand 1.
+;; `2' Match operand 2.
+;; `3' Match operand 3.
+;; `4' Match operand 4.
+;; `5' Match operand 5.
+;; `6' Match operand 6.
+;; `7' Match operand 7.
+;; `8' Match operand 8.
+;; `9' Match operand 9.
+;;
+;;     An operand that matches the specified operand number is allowed.  If a
+;;     digit is used together with letters within the same alternative, the
+;;     digit should come last.
+;;
+;;     This is called a "matching constraint" and what it really means is that
+;;     the assembler has only a single operand that fills two roles considered
+;;     separate in the RTL insn.  For example, an add insn has two input
+;;     operands and one output operand in the RTL, but on most CISC machines an
+;;     add instruction really has only two operands, one of them an
+;;     input-output operand:
+;;
+;;          addl #35,r12
+;;
+;;     Matching constraints are used in these circumstances.  More precisely,
+;;     the two operands that match must include one input-only operand and one
+;;     output-only operand.  Moreover, the digit must be a smaller number than
+;;     the number of the operand that uses it in the constraint.
+;;
+;;     For operands to match in a particular case usually means that they are
+;;     identical-looking RTL expressions.  But in a few special cases specific
+;;     kinds of dissimilarity are allowed.  For example, `*x' as an input
+;;     operand will match `*x++' as an output operand.  For proper results in
+;;     such cases, the output template should always use the output-operand's
+;;     number when printing the operand.
+;;
+;; `p' An operand that is a valid memory address is allowed.  This is for
+;;     "load address" and "push address" instructions.
+;;
+;;     `p' in the constraint must be accompanied by `address_operand' as the
+;;     predicate in the `match_operand'.  This predicate interprets the mode
+;;     specified in the `match_operand' as the mode of the memory reference for
+;;     which the address would be valid.
+;;
+;; `Q` First non constant, non register machine-dependent insns
+;; `R` Second non constant, non register machine-dependent insns
+;; `S` Third non constant, non register machine-dependent insns
+;; `T` Fourth non constant, non register machine-dependent insns
+;; `U` Fifth non constant, non register machine-dependent insns
+;;
+;;     Letters in the range `Q' through `U' may be defined in a
+;;     machine-dependent fashion to stand for arbitrary operand types.  The
+;;     machine description macro `EXTRA_CONSTRAINT' is passed the operand as
+;;     its first argument and the constraint letter as its second operand.
+;;
+;;     A typical use for this would be to distinguish certain types of memory
+;;     references that affect other insn operands.
+;;
+;;     Do not define these constraint letters to accept register references
+;;     (`reg'); the reload pass does not expect this and would not handle it
+;;     properly.
+
+;; Multiple Alternative Constraints
+;; `?' Disparage slightly the alternative that the `?' appears in, as a
+;;     choice when no alternative applies exactly.  The compiler regards this
+;;     alternative as one unit more costly for each `?' that appears in it.
+;;
+;; `!' Disparage severely the alternative that the `!' appears in.  This
+;;     alternative can still be used if it fits without reloading, but if
+;;     reloading is needed, some other alternative will be used.
+
+;; Constraint modifiers
+;; `=' Means that this operand is write-only for this instruction: the
+;;     previous value is discarded and replaced by output data.
+;;
+;; `+' Means that this operand is both read and written by the
+;;     instruction.
+;;
+;;     When the compiler fixes up the operands to satisfy the constraints, it
+;;     needs to know which operands are inputs to the instruction and which are
+;;     outputs from it.  `=' identifies an output; `+' identifies an operand
+;;     that is both input and output; all other operands are assumed to be
+;;     input only.
+;;
+;; `&' Means (in a particular alternative) that this operand is written
+;;     before the instruction is finished using the input operands.  Therefore,
+;;     this operand may not lie in a register that is used as an input operand
+;;     or as part of any memory address.
+;;
+;;     `&' applies only to the alternative in which it is written.  In
+;;     constraints with multiple alternatives, sometimes one alternative
+;;     requires `&' while others do not.
+;;
+;;     `&' does not obviate the need to write `='.
+;;
+;; `%' Declares the instruction to be commutative for this operand and the
+;;     following operand.  This means that the compiler may interchange the two
+;;     operands if that is the cheapest way to make all operands fit the
+;;     constraints.  This is often used in patterns for addition instructions
+;;     that really have only two operands: the result must go in one of the
+;;     arguments.
+;;
+;; `#' Says that all following characters, up to the next comma, are to be
+;;     ignored as a constraint.  They are significant only for choosing
+;;     register preferences.
+;;
+;; `*' Says that the following character should be ignored when choosing
+;;     register preferences.  `*' has no effect on the meaning of the
+;;     constraint as a constraint, and no effect on reloading.
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Attributes
+;; ::
+;; ::::::::::::::::::::
+
+;; The `define_attr' expression is used to define each attribute required by
+;; the target machine.  It looks like:
+;;
+;; (define_attr NAME LIST-OF-VALUES DEFAULT)
+
+;; NAME is a string specifying the name of the attribute being defined.
+
+;; LIST-OF-VALUES is either a string that specifies a comma-separated list of
+;; values that can be assigned to the attribute, or a null string to indicate
+;; that the attribute takes numeric values.
+
+;; DEFAULT is an attribute expression that gives the value of this attribute
+;; for insns that match patterns whose definition does not include an explicit
+;; value for this attribute.
+
+;; For each defined attribute, a number of definitions are written to the
+;; `insn-attr.h' file.  For cases where an explicit set of values is specified
+;; for an attribute, the following are defined:
+
+;; * A `#define' is written for the symbol `HAVE_ATTR_NAME'.
+;;
+;; * An enumeral class is defined for `attr_NAME' with elements of the
+;;   form `UPPER-NAME_UPPER-VALUE' where the attribute name and value are first
+;;   converted to upper case.
+;;
+;; * A function `get_attr_NAME' is defined that is passed an insn and
+;;   returns the attribute value for that insn.
+
+;; For example, if the following is present in the `md' file:
+;;
+;; (define_attr "type" "branch,fp,load,store,arith" ...)
+;;
+;; the following lines will be written to the file `insn-attr.h'.
+;;
+;; #define HAVE_ATTR_type
+;; enum attr_type {TYPE_BRANCH, TYPE_FP, TYPE_LOAD, TYPE_STORE, TYPE_ARITH};
+;; extern enum attr_type get_attr_type ();
+
+;; If the attribute takes numeric values, no `enum' type will be defined and
+;; the function to obtain the attribute's value will return `int'.
+
+(define_attr "length" "" (const_int 4))
+
+;; Processor type -- this attribute must exactly match the processor_type
+;; enumeration in frv-protos.h.
+
+(define_attr "cpu" "generic,fr500,fr400,fr300,simple,tomcat"
+  (const (symbol_ref "frv_cpu_type")))
+
+;; Attribute is "yes" for branches and jumps that span too great a distance
+;; to be implemented in the most natural way.  Such instructions will use
+;; a call instruction in some way.
+
+(define_attr "far_jump" "yes,no" (const_string "no"))
+
+;; Instruction type
+
+;; The table below summarises the types of media instruction and their
+;; scheduling classification.  Headings are:
+
+;; Type:       the name of the define_attr type
+;; Conditions: "yes" if conditional variants are available
+;; FR500:      Fujitsu's categorisation for the FR500
+;; FR400:      Fujitsu's categorisation for the FR400 (but see below).
+
+;; On the FR400, media instructions are divided into 2 broad categories.
+;; Category 1 instructions can execute in either the M0 or M1 unit and can
+;; execute in parallel with other category 1 instructions.  Category 2
+;; instructions must use the M0 unit, and therefore cannot run in parallel
+;; with other media instructions.
+
+;; The FR400 documentation also divides media instructions into one of seven
+;; categories (m1 to m7).  m1 to m4 contain both Category 1 and Category 2
+;; instructions, so we use a combination of the categories here.
+
+;; Type                Conditional     FR500   FR400
+;; ----                ----------      -----   -----
+;; mlogic      yes             m1      m1:1
+;; mrdacc      no              m2      m4:1
+;; mwtacc      no              m3      m5:1
+;; maveh       no              m1      m1:1
+;; msath       no              m1      m1:1
+;; maddh       yes             m1      m1:1
+;; mqaddh      yes             m1      m1:2
+;; mpackh      no              m2      m3:1
+;; munpackh    no              m2      m3:2
+;; mdpackh     no              m5      m3:2
+;; mbhconv     yes             m2      m3:2
+;; mrot                no              m2      m3:1
+;; mshift      no              m2      m3:1
+;; mexpdhw     yes             m2      m3:1
+;; mexpdhd     yes             m2      m3:2
+;; mwcut       no              m2      m3:2
+;; mmulh       yes             m4      m2:1
+;; mmulxh      no              m4      m2:1
+;; mmach       yes             m4      m2:1
+;; mmrdh       no              m4      m2:1
+;; mqmulh      yes             m4      m2:2
+;; mqmulxh     no              m4      m2:2
+;; mqmach      yes             m4      m2:2
+;; mcpx                yes             m4      m2:1
+;; mqcpx       yes             m4      m2:2
+;; mcut                no              m2      m4:1
+;; mclracc     no              m3      m4:1
+;; mclracca    no              m6      m4:2
+;; mdunpackh   no              m2      n/a
+;; mbhconve    no              m2      n/a
+;; maddacc     no              n/a     m2:1
+;; mdaddacc    no              n/a     m2:2
+;; mabsh       no              n/a     m1:1
+;; mdrot       no              n/a     m3:2
+;; mcpl                no              n/a     m3:2
+;; mdcut       no              n/a     m4:2
+;; mqsath      no              n/a     m1:2
+;; mset                no              n/a     m1:1
+
+(define_attr "type"
+  "int,sethi,setlo,mul,div,gload,gstore,fload,fstore,movfg,movgf,branch,jump,jumpl,call,spr,trap,fsconv,fsadd,fsmul,fmas,fsdiv,sqrt_single,fdconv,fdadd,fdmul,fddiv,sqrt_double,mlogic,maveh,msath,maddh,mqaddh,mpackh,munpackh,mdpackh,mbhconv,mrot,mshift,mexpdhw,mexpdhd,mwcut,mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach,mcpx,mqcpx,mcut,mclracc,mclracca,mdunpackh,mbhconve,mrdacc,mwtacc,maddacc,mdaddacc,mabsh,mdrot,mcpl,mdcut,mqsath,mset,m7,ccr,multi,unknown"
+  (const_string "unknown"))
+
+\f
+
+/* This is description of pipeline hazards based on DFA.  The
+   following constructions can be used for this:
+
+   o define_cpu_unit string [string]) describes a cpu functional unit
+     (separated by comma).
+
+     1st operand: Names of cpu function units.
+     2nd operand: Name of automaton (see comments for
+     DEFINE_AUTOMATON).
+
+     All define_reservations and define_cpu_units should have unique
+     names which can not be "nothing".
+
+   o (exclusion_set string string) means that each CPU function unit
+     in the first string can not be reserved simultaneously with each
+     unit whose name is in the second string and vise versa.  CPU
+     units in the string are separated by commas. For example, it is
+     useful for description CPU with fully pipelined floating point
+     functional unit which can execute simultaneously only single
+     floating point insns or only double floating point insns.
+
+   o (presence_set string string) means that each CPU function unit in
+     the first string can not be reserved unless at least one of units
+     whose names are in the second string is reserved.  This is an
+     asymmetric relation.  CPU units in the string are separated by
+     commas.  For example, it is useful for description that slot1 is
+     reserved after slot0 reservation for a VLIW processor.
+
+   o (absence_set string string) means that each CPU function unit in
+     the first string can not be reserved only if each unit whose name
+     is in the second string is not reserved.  This is an asymmetric
+     relation (actually exclusion set is analogous to this one but it
+     is symmetric).  CPU units in the string are separated by commas.
+     For example, it is useful for description that slot0 can not be
+     reserved after slot1 or slot2 reservation for a VLIW processor.
+
+   o (define_bypass number out_insn_names in_insn_names) names bypass with
+     given latency (the first number) from insns given by the first
+     string (see define_insn_reservation) into insns given by the
+     second string.  Insn names in the strings are separated by
+     commas.
+
+   o (define_automaton string) describes names of an automaton
+     generated and used for pipeline hazards recognition.  The names
+     are separated by comma.  Actually it is possibly to generate the
+     single automaton but unfortunately it can be very large.  If we
+     use more one automata, the summary size of the automata usually
+     is less than the single one.  The automaton name is used in
+     define_cpu_unit.  All automata should have unique names.
+
+   o (define_reservation string string) names reservation (the first
+     string) of cpu functional units (the 2nd string).  Sometimes unit
+     reservations for different insns contain common parts.  In such
+     case, you describe common part and use one its name (the 1st
+     parameter) in regular expression in define_insn_reservation.  All
+     define_reservations, define results and define_cpu_units should
+     have unique names which can not be "nothing".
+
+   o (define_insn_reservation name default_latency condition regexpr)
+     describes reservation of cpu functional units (the 3nd operand)
+     for instruction which is selected by the condition (the 2nd
+     parameter).  The first parameter is used for output of debugging
+     information.  The reservations are described by a regular
+     expression according the following syntax:
+
+       regexp = regexp "," oneof
+              | oneof
+
+       oneof = oneof "|" allof
+             | allof
+
+       allof = allof "+" repeat
+             | repeat
+
+       repeat = element "*" number
+              | element
+
+       element = cpu_function_name
+               | reservation_name
+               | result_name
+               | "nothing"
+               | "(" regexp ")"
+
+       1. "," is used for describing start of the next cycle in
+          reservation.
+
+       2. "|" is used for describing the reservation described by the
+          first regular expression *or* the reservation described by
+          the second regular expression *or* etc.
+
+       3. "+" is used for describing the reservation described by the
+          first regular expression *and* the reservation described by
+          the second regular expression *and* etc.
+
+       4. "*" is used for convinience and simply means sequence in
+          which the regular expression are repeated NUMBER times with
+          cycle advancing (see ",").
+
+       5. cpu function unit name which means reservation.
+
+       6. reservation name -- see define_reservation.
+
+       7. string "nothing" means no units reservation.
+
+*/
+
+(define_automaton "nodiv, idiv, div")
+
+;; An FR500 packet can contain a single control instruction or a sequence
+;; of up to four operations matching the regular expression:
+
+;;     (I FM? I? FM? | FM? FM?) B? B?
+
+;; where I denotes an integer operation, FM a floating-point or media
+;; operation, and B a branch operation.  There are two units for each type
+;; of instruction: I0 and I1, FM0 and FM1, and B0 and B1.  Units are
+;; allocated left-to-right: the first integer instruction uses I0, the
+;; second uses I1, and so on.
+
+;; The FR400 is similar to the FR500 except that it allows only 2 operations
+;; per packet and has only one branch unit.  We can use the FR500 conflict
+;; description for the FR400, but need to define different cpu_units
+;; later.
+
+;; Slot/unit combinations available on the FR400 and above:
+(define_cpu_unit "sl0_i0, sl0_fm0, sl0_b0, sl0_c" "nodiv")
+(define_cpu_unit "sl1_fm0, sl1_i1, sl1_fm1, sl1_b0" "nodiv")
+
+;; These are available on the FR500 and above:
+(define_cpu_unit "sl1_b1" "nodiv")
+(define_cpu_unit "sl2_i1, sl2_fm1, sl2_b0, sl2_b1" "nodiv")
+(define_cpu_unit "sl3_fm1, sl3_b0, sl3_b1"  "nodiv")
+
+;; The following describes conlicts by slots
+;; slot0
+(exclusion_set "sl0_i0"  "sl0_fm0,sl0_b0,sl0_c")
+(exclusion_set "sl0_fm0" "sl0_b0,sl0_c")
+(exclusion_set "sl0_b0"  "sl0_c")
+
+;; slot1
+(exclusion_set "sl1_fm0" "sl1_i1,sl1_fm1,sl1_b0,sl1_b1")
+(exclusion_set "sl1_i1"  "sl1_fm1,sl1_b0,sl1_b1")
+(exclusion_set "sl1_fm1" "sl1_b0,sl1_b1")
+(exclusion_set "sl1_b0"  "sl1_b1")
+
+;; slot2
+(exclusion_set "sl2_i1"  "sl2_fm1,sl2_b0,sl2_b1")
+(exclusion_set "sl2_fm1" "sl2_b0,sl2_b1")
+(exclusion_set "sl2_b0"  "sl2_b1")
+
+;; slot3
+(exclusion_set "sl3_fm1" "sl3_b0,sl3_b1")
+(exclusion_set "sl3_b0"  "sl3_b1")
+
+;; The following describes conlicts by units
+;; fm0
+(exclusion_set "sl0_fm0" "sl1_fm0")
+
+;; b0
+(exclusion_set "sl0_b0"  "sl1_b0,sl2_b0,sl3_b0")
+(exclusion_set "sl1_b0"  "sl2_b0,sl3_b0")
+(exclusion_set "sl2_b0"  "sl3_b0")
+
+;; i1
+(exclusion_set "sl1_i1"  "sl2_i1")
+
+;; fm1
+(exclusion_set "sl1_fm1" "sl2_fm1,sl3_fm1")
+(exclusion_set "sl2_fm1" "sl3_fm1")
+
+;; b1
+(exclusion_set "sl1_b1"  "sl2_b1,sl3_b1")
+(exclusion_set "sl2_b1"  "sl3_b1")
+
+;; The following describes remaining combinations of conflicts
+;; slot0
+(exclusion_set "sl0_i0"  "sl1_fm1,sl1_b1")
+(exclusion_set "sl0_fm0" "sl1_i1,sl1_b1,sl2_i1,sl2_fm1,sl3_fm1,sl3_b0")
+(exclusion_set "sl0_b0"  "sl1_fm0,sl1_i1,sl1_fm1,sl2_i1,sl2_fm1,sl2_b1,\
+                          sl3_fm1,sl3_b1")
+(exclusion_set "sl0_c"   "sl1_fm0,sl1_i1,sl1_fm1,sl1_b0,sl1_b1,sl2_i1,sl2_fm1,\
+                          sl2_b0,sl2_b1,sl3_fm1,sl3_b0,sl3_b1")
+
+
+;; slot1
+(exclusion_set "sl1_fm0" "sl2_b1")
+(exclusion_set "sl1_i1"  "sl2_fm1,sl2_b1,sl3_fm1,sl3_b0")
+(exclusion_set "sl1_fm1" "sl2_i1,sl2_b1,sl3_b0")
+(exclusion_set "sl1_b0"  "sl2_i1,sl2_fm1,sl3_fm1,sl3_b1")
+(exclusion_set "sl1_b1"  "sl2_i1,sl2_fm1,sl2_b0,sl3_fm1,sl3_b0")
+
+;; slot2
+(exclusion_set "sl2_i1"  "sl3_b1")
+(exclusion_set "sl2_fm1" "sl3_b1")
+(exclusion_set "sl2_b0"  "sl3_fm1")
+(exclusion_set "sl2_b1"  "sl3_fm1,sl3_b0")
+
+;; slot3
+(exclusion_set "sl1_fm0" "sl2_i1,sl2_fm1,sl2_b0,sl2_b1,sl3_fm1,sl3_b0,sl3_b1")
+(exclusion_set "sl3_fm1" "sl2_i1,sl2_fm1,sl2_b0,sl2_b1,sl3_b0,sl3_b1")
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Generic/FR500 scheduler description
+;; ::
+;; ::::::::::::::::::::
+
+;; Define reservation in order to describe only in terms of units.
+
+(define_reservation "i0" "sl0_i0")
+(define_reservation "f0" "sl0_fm0|sl1_fm0")
+(define_reservation "m0" "f0")
+(define_reservation "b0" "sl0_b0|sl1_b0|sl2_b0|sl3_b0")
+(define_reservation "c"  "sl0_c")
+(define_reservation "i1" "sl1_i1|sl2_i1")
+(define_reservation "f1" "sl1_fm1|sl2_fm1|sl3_fm1")
+(define_reservation "m1" "f1")
+(define_reservation "b1" "sl1_b1|sl2_b1|sl3_b1")
+
+;; Integer insns
+;; It is not possibly to issue load & store in one VLIW insn.
+(define_cpu_unit "idiv1" "idiv")
+(define_cpu_unit "idiv2" "idiv")
+(define_cpu_unit "l0"    "nodiv")
+(define_cpu_unit "l1"    "nodiv")
+(define_cpu_unit "s0"    "nodiv")
+
+(exclusion_set "l1,l0" "s0")
+
+;; We set the default_latency of sethi to be 0 to allow sethi and setlo to be
+;; combined in the same VLIW instruction as allowed by the architecture.  This
+;; assumes the only use of sethi is always followed by a setlo of the same
+;; register.
+(define_insn_reservation "i1_sethi" 0
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "sethi"))
+  "i0|i1")
+
+(define_insn_reservation "i1_setlo" 1
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "setlo"))
+  "i0|i1")
+
+(define_insn_reservation "i1_int" 1
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "int"))
+  "i0|i1")
+
+(define_insn_reservation "i1_mul" 3
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "mul"))
+  "i0|i1")
+
+(define_insn_reservation "i1_div" 19
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "div"))
+  "(i0|i1),(idiv1*18|idiv2*18)")
+
+(define_insn_reservation "i2_gload" 4
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "gload"))
+  "(i0|i1)+(l0|l1)")
+
+(define_insn_reservation "i2_fload" 4
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "fload"))
+  "(i0|i1)+(l0|l1)")
+
+(define_insn_reservation "i3_gstore" 0
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "gstore"))
+  "i0+s0")
+
+(define_insn_reservation "i3_fstore" 0
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "fstore"))
+  "i0+s0")
+
+(define_insn_reservation "i4_move_gf" 3
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "movgf"))
+  "i0")
+
+(define_insn_reservation "i4_move_fg" 3 
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "movfg"))
+  "i0")
+
+(define_insn_reservation "i5" 0
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "jumpl"))
+  "i0")
+
+;; Clear/commit is not generated now:
+(define_insn_reservation "i6" 0 (const_int 0) "i0|i1")
+
+;;
+;; Branch-instructions
+;;
+(define_insn_reservation "b1/b3" 0
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "jump,branch,ccr"))
+  "b0|b1")
+
+;; The following insn is not generated now.
+
+(define_insn_reservation "b2" 0 (const_int 0) "b0")
+
+(define_insn_reservation "b4" 0
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "call"))
+  "b0")
+
+;; The following insns are not generated now.
+(define_insn_reservation "b5" 0 (const_int 0) "b0|b1")
+(define_insn_reservation "b6" 0 (const_int 0) "b0|b1")
+
+;; Control insns
+(define_insn_reservation "trap" 0
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "trap"))
+  "c")
+
+(define_insn_reservation "control" 0
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "spr"))
+  "c")
+
+;; Floating point insns
+(define_cpu_unit "add0" "nodiv")
+(define_cpu_unit "add1" "nodiv")
+(define_cpu_unit "mul0" "nodiv")
+(define_cpu_unit "mul1" "nodiv")
+(define_cpu_unit "div1" "div")
+(define_cpu_unit "div2" "div")
+(define_cpu_unit "root" "div")
+
+(define_bypass 4 "f1" "m1,m2,m3,m4,m5,m6,m7")
+(define_insn_reservation "f1" 3
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "fsconv,fdconv"))
+  "(f0|f1)")
+
+(define_bypass 4 "f2" "m1,m2,m3,m4,m5,m6,m7")
+(define_insn_reservation "f2" 3
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "fsadd,fdadd"))
+  "(f0|f1)+(add0|add1)")
+
+(define_bypass 4 "f3" "m1,m2,m3,m4,m5,m6,m7")
+(define_insn_reservation "f3" 3
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "fsmul,fdmul"))
+  "(f0|f1)+(mul0|mul1)")
+
+(define_bypass 11 "f4_div" "m1,m2,m3,m4,m5,m6,m7")
+(define_insn_reservation "f4_div" 10
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "fsdiv,fddiv"))
+  "(f0|f1),(div1*9|div2*9)")
+
+(define_bypass 16 "f4_root" "m1,m2,m3,m4,m5,m6,m7")
+(define_insn_reservation "f4_root" 15
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "sqrt_single,sqrt_double"))
+  "(f0|f1)+root*15")
+
+(define_bypass 4 "f5" "m1,m2,m3,m4,m5,m6,m7")
+(define_insn_reservation "f5" 3
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "fmas"))
+  "(f0|f1)+(add0|add1)+(mul0|mul1)")
+
+;; The following insns are not generated by gcc now:
+(define_insn_reservation "f6" 0 (const_int 0) "(f0|f1)+add0+add1")
+(define_insn_reservation "f7" 0 (const_int 0) "(f0|f1)+mul0+mul1")
+
+;; Media insns.  Now they are all not generated now.
+(define_cpu_unit "m1_0" "nodiv")
+(define_cpu_unit "m1_1" "nodiv")
+(define_cpu_unit "m2_0" "nodiv")
+(define_cpu_unit "m2_1" "nodiv")
+(define_cpu_unit "m3_0" "nodiv")
+(define_cpu_unit "m3_1" "nodiv")
+(define_cpu_unit "m4_0" "nodiv")
+(define_cpu_unit "m4_1" "nodiv")
+(define_cpu_unit "m5"   "nodiv")
+(define_cpu_unit "m6"   "nodiv")
+(define_cpu_unit "m7"   "nodiv")
+
+(exclusion_set "m5,m6,m7" "m2_0,m2_1,m3_0,m3_1")
+(exclusion_set "m5"       "m6,m7")
+(exclusion_set "m6"       "m4_0,m4_1,m7")
+(exclusion_set "m7"       "m1_0,m1_1,add0,add1,mul0,mul1")
+
+(define_bypass 2 "m1" "m1,m2,m3,m4,m5,m6,m7")
+(define_bypass 4 "m1" "f1,f2,f3,f4_div,f4_root,f5,f6,f7")
+(define_insn_reservation "m1" 3
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "mlogic,maveh,msath,maddh,mqaddh"))
+  "(m0|m1)+(m1_0|m1_1)")
+
+(define_bypass 2 "m2" "m1,m2,m3,m4,m5,m6,m7")
+(define_bypass 4 "m2" "f1,f2,f3,f4_div,f4_root,f5,f6,f7")
+(define_insn_reservation "m2" 3
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "mrdacc,mpackh,munpackh,mbhconv,mrot,mshift,mexpdhw,mexpdhd,mwcut,mcut,mdunpackh,mbhconve"))
+  "(m0|m1)+(m2_0|m2_1)")
+
+(define_bypass 1 "m3" "m4")
+(define_insn_reservation "m3" 2
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "mclracc,mwtacc"))
+  "(m0|m1)+(m3_0|m3_1)")
+
+(define_bypass 1 "m4" "m4")
+(define_insn_reservation "m4" 2
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach,mcpx,mqcpx"))
+  "(m0|m1)+(m4_0|m4_1)")
+
+(define_bypass 2 "m5" "m1,m2,m3,m4,m5,m6,m7")
+(define_bypass 4 "m5" "f1,f2,f3,f4_div,f4_root,f5,f6,f7")
+(define_insn_reservation "m5" 3
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "mdpackh"))
+  "(m0|m1)+m5")
+
+(define_bypass 1 "m6" "m4")
+(define_insn_reservation "m6" 2
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "mclracca"))
+  "(m0|m1)+m6")
+
+(define_bypass 2 "m7" "m1,m2,m3,m4,m5,m6,m7")
+(define_bypass 4 "m7" "f1,f2,f3,f4_div,f4_root,f5,f6,f7")
+
+(define_insn_reservation "m7" 3
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "m7"))
+  "(m0|m1)+m7")
+
+;; Unknown & multi insns starts on new cycle and the next insn starts
+;; on new cycle.  To describe this we consider as a control insn.
+(define_insn_reservation "unknown" 1
+  (and (eq_attr "cpu" "generic,fr500,tomcat")
+       (eq_attr "type" "unknown,multi"))
+  "c")
+
+;; ::::::::::::::::::::
+;; ::
+;; :: FR400 scheduler description
+;; ::
+;; ::::::::::::::::::::
+
+;; Category 2 media instructions use both media units, but can be packed
+;; with non-media instructions.  Use fr400_m1unit to claim the M1 unit
+;; without claiming a slot.
+
+(define_cpu_unit "fr400_m1unit" "nodiv")
+
+(define_reservation "fr400_i0"      "sl0_i0")
+(define_reservation "fr400_i1"      "sl1_i1")
+(define_reservation "fr400_m0"      "sl0_fm0|sl1_fm0")
+(define_reservation "fr400_m1"      "sl1_fm1")
+(define_reservation "fr400_meither" "fr400_m0|(fr400_m1+fr400_m1unit)")
+(define_reservation "fr400_mboth"   "fr400_m0+fr400_m1unit")
+(define_reservation "fr400_b"       "sl0_b0|sl1_b0")
+(define_reservation "fr400_c"       "sl0_c")
+
+;; Name                Class   Units   Latency
+;; ====                =====   =====   =======
+;; int         I1      I0/I1   1
+;; sethi       I1      I0/I1   0       -- does not interfere with setlo
+;; setlo       I1      I0/I1   1
+;; mul         I1      I0      3  (*)
+;; div         I1      I0      20 (*)
+;; gload       I2      I0      4  (*)
+;; fload       I2      I0      4       -- only 3 if read by a media insn
+;; gstore      I3      I0      0       -- provides no result
+;; fstore      I3      I0      0       -- provides no result
+;; movfg       I4      I0      3  (*)
+;; movgf       I4      I0      3  (*)
+;; jumpl       I5      I0      0       -- provides no result
+;;
+;; (*) The results of these instructions can be read one cycle earlier
+;; than indicated.  The penalty given is for instructions with write-after-
+;; write dependencies.
+
+;; The FR400 can only do loads and stores in I0, so we there's no danger
+;; of memory unit collision in the same packet.  There's only one divide
+;; unit too.
+
+(define_insn_reservation "fr400_i1_int" 1
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "int"))
+  "fr400_i0|fr400_i1")
+
+(define_insn_reservation "fr400_i1_sethi" 0
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "sethi"))
+  "fr400_i0|fr400_i1")
+
+(define_insn_reservation "fr400_i1_setlo" 1
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "setlo"))
+  "fr400_i0|fr400_i1")
+
+(define_insn_reservation "fr400_i1_mul" 3
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "mul"))
+  "fr400_i0")
+
+(define_insn_reservation "fr400_i1_div" 20
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "div"))
+  "fr400_i0+idiv1*19")
+
+(define_insn_reservation "fr400_i2_gload" 4
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "gload"))
+  "fr400_i0")
+
+(define_insn_reservation "fr400_i2_fload" 4
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "fload"))
+  "fr400_i0")
+
+(define_insn_reservation "fr400_i3_gstore" 0
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "gstore"))
+  "fr400_i0")
+
+(define_insn_reservation "fr400_i3_fstore" 0
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "fstore"))
+  "fr400_i0")
+
+(define_insn_reservation "fr400_i4_movfg" 3
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "movfg"))
+  "fr400_i0")
+
+(define_insn_reservation "fr400_i4_movgf" 3
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "movgf"))
+  "fr400_i0")
+
+(define_insn_reservation "fr400_i5_jumpl" 0
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "jumpl"))
+  "fr400_i0")
+
+;; The bypass between FPR loads and media instructions, described above.
+
+(define_bypass 3
+  "fr400_i2_fload"
+  "fr400_m1_1,fr400_m1_2,\
+   fr400_m2_1,fr400_m2_2,\
+   fr400_m3_1,fr400_m3_2,\
+   fr400_m4_1,fr400_m4_2,\
+   fr400_m5")
+
+;; The branch instructions all use the B unit and produce no result.
+
+(define_insn_reservation "fr400_b" 0
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "jump,branch,ccr,call"))
+  "fr400_b")
+
+;; Control instructions use the C unit, which excludes all the others.
+
+(define_insn_reservation "fr400_c" 0
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "spr,trap"))
+  "fr400_c")
+
+;; Unknown instructions use the C unit, since it requires single-operation
+;; packets.
+
+(define_insn_reservation "fr400_unknown" 1
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "unknown,multi"))
+  "fr400_c")
+
+;; FP->FP moves are marked as "fsconv" instructions in the define_insns
+;; below, but are implemented on the FR400 using "mlogic" instructions.
+;; It's easier to class "fsconv" as a "m1:1" instruction than provide
+;; separate define_insns for the FR400.
+
+;; M1 instructions store their results in FPRs.  Any instruction can read
+;; the result in the following cycle, so no penalty occurs.
+
+(define_insn_reservation "fr400_m1_1" 1
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "fsconv,mlogic,maveh,msath,maddh,mabsh,mset"))
+  "fr400_meither")
+
+(define_insn_reservation "fr400_m1_2" 1
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "mqaddh,mqsath"))
+  "fr400_mboth")
+
+;; M2 instructions store their results in accumulators, which are read
+;; by M2 or M4 media commands.  M2 instructions can read the results in
+;; the following cycle, but M4 instructions must wait a cycle more.
+
+(define_bypass 1
+  "fr400_m2_1,fr400_m2_2"
+  "fr400_m2_1,fr400_m2_2")
+
+(define_insn_reservation "fr400_m2_1" 2
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mcpx,maddacc"))
+  "fr400_meither")
+
+(define_insn_reservation "fr400_m2_2" 2
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "mqmulh,mqmulxh,mqmach,mqcpx,mdaddacc"))
+  "fr400_mboth")
+
+;; For our purposes, there seems to be little real difference between
+;; M1 and M3 instructions.  Keep them separate anyway in case the distinction
+;; is needed later.
+
+(define_insn_reservation "fr400_m3_1" 1
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "mpackh,mrot,mshift,mexpdhw"))
+  "fr400_meither")
+
+(define_insn_reservation "fr400_m3_2" 1
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "munpackh,mdpackh,mbhconv,mexpdhd,mwcut,mdrot,mcpl"))
+  "fr400_mboth")
+
+;; M4 instructions write to accumulators or FPRs.  MOVFG and STF
+;; instructions can read an FPR result in the following cycle, but
+;; M-unit instructions must wait a cycle more for either kind of result.
+
+(define_bypass 1
+  "fr400_m4_1,fr400_m4_2"
+  "fr400_i3_fstore,fr400_i4_movfg")
+
+(define_insn_reservation "fr400_m4_1" 2
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "mrdacc,mcut,mclracc"))
+  "fr400_meither")
+
+(define_insn_reservation "fr400_m4_2" 2
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "mclracca,mdcut"))
+  "fr400_mboth")
+
+;; M5 instructions always incur a 1-cycle penalty.
+
+(define_insn_reservation "fr400_m5" 2
+  (and (eq_attr "cpu" "fr400")
+       (eq_attr "type" "mwtacc"))
+  "fr400_mboth")
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Simple/FR300 scheduler description
+;; ::
+;; ::::::::::::::::::::
+
+;; Fr300 or simple processor.  To describe it as 1 insn issue
+;; processor, we use control unit.
+
+(define_insn_reservation "fr300_lat1" 1
+  (and (eq_attr "cpu" "fr300,simple")
+       (eq_attr "type" "!gload,fload,movfg,movgf"))
+  "c")
+
+(define_insn_reservation "fr300_lat2" 2
+  (and (eq_attr "cpu" "fr300,simple")
+       (eq_attr "type" "gload,fload,movfg,movgf"))
+  "c")
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Delay Slots
+;; ::
+;; ::::::::::::::::::::
+
+;; The insn attribute mechanism can be used to specify the requirements for
+;; delay slots, if any, on a target machine.  An instruction is said to require
+;; a "delay slot" if some instructions that are physically after the
+;; instruction are executed as if they were located before it.  Classic
+;; examples are branch and call instructions, which often execute the following
+;; instruction before the branch or call is performed.
+
+;; On some machines, conditional branch instructions can optionally "annul"
+;; instructions in the delay slot.  This means that the instruction will not be
+;; executed for certain branch outcomes.  Both instructions that annul if the
+;; branch is true and instructions that annul if the branch is false are
+;; supported.
+
+;; Delay slot scheduling differs from instruction scheduling in that
+;; determining whether an instruction needs a delay slot is dependent only
+;; on the type of instruction being generated, not on data flow between the
+;; instructions.  See the next section for a discussion of data-dependent
+;; instruction scheduling.
+
+;; The requirement of an insn needing one or more delay slots is indicated via
+;; the `define_delay' expression.  It has the following form:
+;;
+;; (define_delay TEST
+;;   [DELAY-1 ANNUL-TRUE-1 ANNUL-FALSE-1
+;;    DELAY-2 ANNUL-TRUE-2 ANNUL-FALSE-2
+;;    ...])
+
+;; TEST is an attribute test that indicates whether this `define_delay' applies
+;; to a particular insn.  If so, the number of required delay slots is
+;; determined by the length of the vector specified as the second argument.  An
+;; insn placed in delay slot N must satisfy attribute test DELAY-N.
+;; ANNUL-TRUE-N is an attribute test that specifies which insns may be annulled
+;; if the branch is true.  Similarly, ANNUL-FALSE-N specifies which insns in
+;; the delay slot may be annulled if the branch is false.  If annulling is not
+;; supported for that delay slot, `(nil)' should be coded.
+
+;; For example, in the common case where branch and call insns require a single
+;; delay slot, which may contain any insn other than a branch or call, the
+;; following would be placed in the `md' file:
+
+;; (define_delay (eq_attr "type" "branch,call")
+;;              [(eq_attr "type" "!branch,call") (nil) (nil)])
+
+;; Multiple `define_delay' expressions may be specified.  In this case, each
+;; such expression specifies different delay slot requirements and there must
+;; be no insn for which tests in two `define_delay' expressions are both true.
+
+;; For example, if we have a machine that requires one delay slot for branches
+;; but two for calls, no delay slot can contain a branch or call insn, and any
+;; valid insn in the delay slot for the branch can be annulled if the branch is
+;; true, we might represent this as follows:
+
+;; (define_delay (eq_attr "type" "branch")
+;;   [(eq_attr "type" "!branch,call")
+;;    (eq_attr "type" "!branch,call")
+;;    (nil)])
+;;
+;; (define_delay (eq_attr "type" "call")
+;;   [(eq_attr "type" "!branch,call") (nil) (nil)
+;;    (eq_attr "type" "!branch,call") (nil) (nil)])
+
+;; Note - it is the backend's responsibility to fill any unfilled delay slots
+;; at assembler generation time.  This is usually done by adding a special print
+;; operand to the delayed insrtuction, and then in the PRINT_OPERAND function
+;; calling dbr_sequence_length() to determine how many delay slots were filled.
+;; For example:
+;;
+;; --------------<machine>.md-----------------
+;; (define_insn "call"
+;;  [(call (match_operand 0 "memory_operand" "m")
+;;         (match_operand 1 "" ""))]
+;;   ""
+;;   "call_delayed %0,%1,%2%#"
+;;  [(set_attr "length" "4")
+;;   (set_attr "type" "call")])
+;;
+;; -------------<machine>.h-------------------
+;; #define PRINT_OPERAND_PUNCT_VALID_P(CODE) (CODE == '#')
+;;
+;;  ------------<machine>.c------------------
+;; void
+;; machine_print_operand (file, x, code)
+;;     FILE * file;
+;;     rtx    x;
+;;     int    code;
+;; {
+;;   switch (code)
+;;   {
+;;   case '#':
+;;     if (dbr_sequence_length () == 0)
+;;       fputs ("\n\tnop", file);
+;;     return;
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Notes on Patterns
+;; ::
+;; ::::::::::::::::::::
+
+;; If you need to construct a sequence of assembler instructions in order
+;; to implement a pattern be sure to escape any backslashes and double quotes
+;; that you use, eg:
+;;
+;; (define_insn "an example"
+;;   [(some rtl)]
+;;   ""
+;;   "*
+;;    { static char buffer [100];
+;;      sprintf (buffer, \"insn \\t %d\", REGNO (operands[1]));
+;;      return buffer;
+;;    }"
+;; )
+;;
+;; Also if there is more than one instruction, they can be separated by \\;
+;; which is a space saving synonym for \\n\\t:
+;;
+;; (define_insn "another example"
+;;   [(some rtl)]
+;;   ""
+;;   "*
+;;    { static char buffer [100];
+;;      sprintf (buffer, \"insn1 \\t %d\\;insn2 \\t %%1\",
+;;        REGNO (operands[1]));
+;;      return buffer;
+;;    }"
+;; )
+;;
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Moves
+;; ::
+;; ::::::::::::::::::::
+
+;; Wrap moves in define_expand to prevent memory->memory moves from being
+;; generated at the RTL level, which generates better code for most machines
+;; which can't do mem->mem moves.
+
+;; If operand 0 is a `subreg' with mode M of a register whose own mode is wider
+;; than M, the effect of this instruction is to store the specified value in
+;; the part of the register that corresponds to mode M.  The effect on the rest
+;; of the register is undefined.
+
+;; This class of patterns is special in several ways.  First of all, each of
+;; these names *must* be defined, because there is no other way to copy a datum
+;; from one place to another.
+
+;; Second, these patterns are not used solely in the RTL generation pass.  Even
+;; the reload pass can generate move insns to copy values from stack slots into
+;; temporary registers.  When it does so, one of the operands is a hard
+;; register and the other is an operand that can need to be reloaded into a
+;; register.
+
+;; Therefore, when given such a pair of operands, the pattern must
+;; generate RTL which needs no reloading and needs no temporary
+;; registers--no registers other than the operands.  For example, if
+;; you support the pattern with a `define_expand', then in such a
+;; case the `define_expand' mustn't call `force_reg' or any other such
+;; function which might generate new pseudo registers.
+
+;; This requirement exists even for subword modes on a RISC machine
+;; where fetching those modes from memory normally requires several
+;; insns and some temporary registers.  Look in `spur.md' to see how
+;; the requirement can be satisfied.
+
+;; During reload a memory reference with an invalid address may be passed as an
+;; operand.  Such an address will be replaced with a valid address later in the
+;; reload pass.  In this case, nothing may be done with the address except to
+;; use it as it stands.  If it is copied, it will not be replaced with a valid
+;; address.  No attempt should be made to make such an address into a valid
+;; address and no routine (such as `change_address') that will do so may be
+;; called.  Note that `general_operand' will fail when applied to such an
+;; address.
+;;
+;; The global variable `reload_in_progress' (which must be explicitly declared
+;; if required) can be used to determine whether such special handling is
+;; required.
+;;
+;; The variety of operands that have reloads depends on the rest of
+;; the machine description, but typically on a RISC machine these can
+;; only be pseudo registers that did not get hard registers, while on
+;; other machines explicit memory references will get optional
+;; reloads.
+;;
+;; If a scratch register is required to move an object to or from memory, it
+;; can be allocated using `gen_reg_rtx' prior to reload.  But this is
+;; impossible during and after reload.  If there are cases needing scratch
+;; registers after reload, you must define `SECONDARY_INPUT_RELOAD_CLASS' and
+;; perhaps also `SECONDARY_OUTPUT_RELOAD_CLASS' to detect them, and provide
+;; patterns `reload_inM' or `reload_outM' to handle them.
+
+;; The constraints on a `moveM' must permit moving any hard register to any
+;; other hard register provided that `HARD_REGNO_MODE_OK' permits mode M in
+;; both registers and `REGISTER_MOVE_COST' applied to their classes returns a
+;; value of 2.
+
+;; It is obligatory to support floating point `moveM' instructions
+;; into and out of any registers that can hold fixed point values,
+;; because unions and structures (which have modes `SImode' or
+;; `DImode') can be in those registers and they may have floating
+;; point members.
+
+;; There may also be a need to support fixed point `moveM' instructions in and
+;; out of floating point registers.  Unfortunately, I have forgotten why this
+;; was so, and I don't know whether it is still true.  If `HARD_REGNO_MODE_OK'
+;; rejects fixed point values in floating point registers, then the constraints
+;; of the fixed point `moveM' instructions must be designed to avoid ever
+;; trying to reload into a floating point register.
+
+(define_expand "movqi"
+  [(set (match_operand:QI 0 "general_operand" "")
+       (match_operand:QI 1 "general_operand" ""))]
+  ""
+  "
+{
+  if (!reload_in_progress
+      && !reload_completed
+      && !register_operand (operands[0], QImode)
+      && !reg_or_0_operand (operands[1], QImode))
+    operands[1] = copy_to_mode_reg (QImode, operands[1]);
+}")
+
+(define_insn "*movqi_load"
+  [(set (match_operand:QI 0 "register_operand" "=d,f")
+       (match_operand:QI 1 "frv_load_operand" "m,m"))]
+  ""
+  "* return output_move_single (operands, insn);"
+  [(set_attr "length" "4")
+   (set_attr "type" "gload,fload")])
+
+(define_insn "*movqi_internal"
+  [(set (match_operand:QI 0 "move_destination_operand" "=d,d,m,m,?f,?f,?d,?m,f")
+       (match_operand:QI 1 "move_source_operand"       "L,d,d,O, d, f, f, f,GO"))]
+  "register_operand(operands[0], QImode) || reg_or_0_operand (operands[1], QImode)"
+  "* return output_move_single (operands, insn);"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,int,gstore,gstore,movgf,fsconv,movfg,fstore,movgf")])
+
+(define_expand "movhi"
+  [(set (match_operand:HI 0 "general_operand" "")
+       (match_operand:HI 1 "general_operand" ""))]
+  ""
+  "
+{
+  if (!reload_in_progress
+      && !reload_completed
+      && !register_operand (operands[0], HImode)
+      && !reg_or_0_operand (operands[1], HImode))
+    operands[1] = copy_to_mode_reg (HImode, operands[1]);
+}")
+
+(define_insn "*movhi_load"
+  [(set (match_operand:HI 0 "register_operand" "=d,f")
+       (match_operand:HI 1 "frv_load_operand" "m,m"))]
+  ""
+  "* return output_move_single (operands, insn);"
+  [(set_attr "length" "4")
+   (set_attr "type" "gload,fload")])
+
+(define_insn "*movhi_internal"
+  [(set (match_operand:HI 0 "move_destination_operand" "=d,d,d,m,m,?f,?f,?d,?m,f")
+       (match_operand:HI 1 "move_source_operand"       "L,i,d,d,O, d, f, f, f,GO"))]
+  "register_operand(operands[0], HImode) || reg_or_0_operand (operands[1], HImode)"
+  "* return output_move_single (operands, insn);"
+  [(set_attr "length" "4,8,4,4,4,4,4,4,4,4")
+   (set_attr "type" "int,multi,int,gstore,gstore,movgf,fsconv,movfg,fstore,movgf")])
+
+;; Split 2 word load of constants into sethi/setlo instructions
+(define_split
+  [(set (match_operand:HI 0 "integer_register_operand" "")
+       (match_operand:HI 1 "int_2word_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 0)
+       (high:HI (match_dup 1)))
+   (set (match_dup 0)
+       (lo_sum:HI (match_dup 0)
+               (match_dup 1)))]
+  "")
+
+(define_insn "movhi_high"
+  [(set (match_operand:HI 0 "integer_register_operand" "=d")
+       (high:HI (match_operand:HI 1 "int_2word_operand" "i")))]
+  ""
+  "sethi #hi(%1), %0"
+  [(set_attr "type" "sethi")
+   (set_attr "length" "4")])
+
+(define_insn "movhi_lo_sum"
+  [(set (match_operand:HI 0 "integer_register_operand" "+d")
+       (lo_sum:HI (match_dup 0)
+                  (match_operand:HI 1 "int_2word_operand" "i")))]
+  ""
+  "setlo #lo(%1), %0"
+  [(set_attr "type" "setlo")
+   (set_attr "length" "4")])
+
+(define_expand "movsi"
+  [(set (match_operand:SI 0 "move_destination_operand" "")
+       (match_operand:SI 1 "move_source_operand" ""))]
+  ""
+  "
+{
+  if (frv_emit_movsi (operands[0], operands[1]))
+    DONE;
+}")
+
+;; Note - it is best to only have one movsi pattern and to handle
+;; all the various contingencies by the use of alternatives.  This
+;; allows reload the greatest amount of flexability (since reload will
+;; only choose amoungst alternatives for a selected insn, it will not
+;; replace the insn with another one).
+
+;; Unfortunately, we do have to separate out load-type moves from the rest,
+;; and only allow memory source operands in the former.  If we do memory and
+;; constant loads in a single pattern, reload will be tempted to force
+;; constants into memory when the destination is a floating-point register.
+;; That may make a function use a PIC pointer when it didn't before, and we
+;; cannot change PIC usage (and hence stack layout) so late in the game.
+;; The resulting sequences for loading cosntants into FPRs are preferable
+;; even when we're not generating PIC code.
+
+(define_insn "*movsi_load"
+  [(set (match_operand:SI 0 "register_operand" "=d,f")
+       (match_operand:SI 1 "frv_load_operand" "m,m"))]
+  ""
+  "* return output_move_single (operands, insn);"
+  [(set_attr "length" "4")
+   (set_attr "type" "gload,fload")])
+
+(define_insn "*movsi_internal"
+  [(set (match_operand:SI 0 "move_destination_operand" "=d,d,d,m,m,z,d,d,f,f,m,?f,?z")
+       (match_operand:SI 1 "move_source_operand"      "LQ,i,d,d,O,d,z,f,d,f,f,GO,GO"))]
+  "register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode)"
+  "* return output_move_single (operands, insn);"
+  [(set_attr "length" "4,8,4,4,4,4,4,4,4,4,4,4,4")
+   (set_attr "type" "int,multi,int,gstore,gstore,spr,spr,movfg,movgf,fsconv,fstore,movgf,spr")])
+
+(define_insn "*movsi_lda_sdata"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (plus:SI (match_operand:SI 1 "small_data_register_operand" "d")
+                (match_operand:SI 2 "small_data_symbolic_operand" "Q")))]
+  ""
+  "addi %1, #gprel12(%2), %0"
+  [(set_attr "type" "int")
+   (set_attr "length" "4")])
+
+;; Split 2 word load of constants into sethi/setlo instructions
+(define_split
+  [(set (match_operand:SI 0 "integer_register_operand" "")
+       (match_operand:SI 1 "int_2word_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 0)
+       (high:SI (match_dup 1)))
+   (set (match_dup 0)
+       (lo_sum:SI (match_dup 0)
+               (match_dup 1)))]
+  "")
+
+(define_insn "movsi_high"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (high:SI (match_operand:SI 1 "int_2word_operand" "i")))]
+  ""
+  "sethi #hi(%1), %0"
+  [(set_attr "type" "sethi")
+   (set_attr "length" "4")])
+
+(define_insn "movsi_lo_sum"
+  [(set (match_operand:SI 0 "integer_register_operand" "+d")
+       (lo_sum:SI (match_dup 0)
+                  (match_operand:SI 1 "int_2word_operand" "i")))]
+  ""
+  "setlo #lo(%1), %0"
+  [(set_attr "type" "setlo")
+   (set_attr "length" "4")])
+
+;; Split loads of addresses with PIC specified into 3 separate instructions
+(define_insn_and_split "*movsi_pic"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (plus:SI (match_operand:SI 1 "pic_register_operand" "d")
+                (match_operand:SI 2 "pic_symbolic_operand" "")))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (match_dup 0)
+       (high:SI (match_dup 2)))
+   (set (match_dup 0)
+       (lo_sum:SI (match_dup 0)
+                  (match_dup 2)))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0) (match_dup 1)))]
+
+  ""
+  [(set_attr "type" "multi")
+   (set_attr "length" "12")])
+
+(define_insn "movsi_high_pic"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (high:SI (match_operand:SI 1 "pic_symbolic_operand" "")))]
+  ""
+  "sethi #gprelhi(%1), %0"
+  [(set_attr "type" "sethi")
+   (set_attr "length" "4")])
+
+(define_insn "movsi_lo_sum_pic"
+  [(set (match_operand:SI 0 "integer_register_operand" "+d")
+       (lo_sum:SI (match_dup 0)
+                  (match_operand:SI 1 "pic_symbolic_operand" "")))]
+  ""
+  "setlo #gprello(%1), %0"
+  [(set_attr "type" "setlo")
+   (set_attr "length" "4")])
+
+(define_expand "movdi"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+       (match_operand:DI 1 "general_operand" ""))]
+  ""
+  "
+{
+  if (!reload_in_progress
+      && !reload_completed
+      && !register_operand (operands[0], DImode)
+      && !reg_or_0_operand (operands[1], DImode))
+    operands[1] = copy_to_mode_reg (DImode, operands[1]);
+}")
+
+(define_insn "*movdi_double"
+  [(set (match_operand:DI 0 "move_destination_operand" "=e,?h,??d,??f,R,?R,??m,??m,e,?h,??d,??f,?e,??d,?h,??f,R,m,e,??d,e,??d,?h,??f")
+       (match_operand:DI 1 "move_source_operand"      " e,h,d,f,e,h,d,f,R,R,m,m,h,f,e,d,GO,GO,GO,GO,nF,nF,GO,GO"))]
+  "TARGET_DOUBLE
+   && (register_operand (operands[0], DImode)
+       || reg_or_0_operand (operands[1], DImode))"
+  "* return output_move_double (operands, insn);"
+  [(set_attr "length" "8,4,8,8,4,4,8,8,4,4,8,8,4,8,4,8,4,8,8,8,16,16,8,8")
+   (set_attr "type" "multi,fdconv,multi,multi,gstore,fstore,gstore,fstore,gload,fload,gload,fload,movfg,movfg,movgf,movgf,gstore,gstore,multi,multi,multi,multi,movgf,movgf")])
+
+(define_insn "*movdi_nodouble"
+  [(set (match_operand:DI 0 "move_destination_operand" "=e,?h,??d,??f,R,?R,??m,??m,e,?h,??d,??f,?e,??d,?h,??f,R,m,e,??d,e,??d,?h,??f")
+       (match_operand:DI 1 "move_source_operand"      " e,h,d,f,e,h,d,f,R,R,m,m,h,f,e,d,GO,GO,GO,GO,nF,nF,GO,GO"))]
+  "!TARGET_DOUBLE
+   && (register_operand (operands[0], DImode)
+       || reg_or_0_operand (operands[1], DImode))"
+  "* return output_move_double (operands, insn);"
+  [(set_attr "length" "8,8,8,8,4,4,8,8,4,4,8,8,8,8,8,8,4,8,8,8,16,16,8,8")
+   (set_attr "type" "multi,multi,multi,multi,gstore,fstore,gstore,fstore,gload,fload,gload,fload,movfg,movfg,movgf,movgf,gstore,gstore,multi,multi,multi,multi,movgf,movgf")])
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (match_operand:DI 1 "dbl_memory_two_insn_operand" ""))]
+  "reload_completed"
+  [(const_int 0)]
+  "frv_split_double_load (operands[0], operands[1]);")
+
+(define_split
+  [(set (match_operand:DI 0 "odd_reg_operand" "")
+       (match_operand:DI 1 "memory_operand" ""))]
+  "reload_completed"
+  [(const_int 0)]
+  "frv_split_double_load (operands[0], operands[1]);")
+
+(define_split
+  [(set (match_operand:DI 0 "dbl_memory_two_insn_operand" "")
+       (match_operand:DI 1 "reg_or_0_operand" ""))]
+  "reload_completed"
+  [(const_int 0)]
+  "frv_split_double_store (operands[0], operands[1]);")
+
+(define_split
+  [(set (match_operand:DI 0 "memory_operand" "")
+       (match_operand:DI 1 "odd_reg_operand" ""))]
+  "reload_completed"
+  [(const_int 0)]
+  "frv_split_double_store (operands[0], operands[1]);")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (match_operand:DI 1 "register_operand" ""))]
+  "reload_completed
+   && (odd_reg_operand (operands[0], DImode)
+       || odd_reg_operand (operands[1], DImode)
+       || (integer_register_operand (operands[0], DImode)
+          && integer_register_operand (operands[1], DImode))
+       || (!TARGET_DOUBLE
+          && fpr_operand (operands[0], DImode)
+          && fpr_operand (operands[1], DImode)))"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))]
+  "
+{
+  rtx op0      = operands[0];
+  rtx op0_low  = gen_lowpart (SImode, op0);
+  rtx op0_high = gen_highpart (SImode, op0);
+  rtx op1      = operands[1];
+  rtx op1_low  = gen_lowpart (SImode, op1);
+  rtx op1_high = gen_highpart (SImode, op1);
+
+  /* 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.  */
+
+  if (REGNO (op0_high) == REGNO (op1_low))
+    {
+      operands[2] = op0_low;
+      operands[3] = op0_high;
+      operands[4] = op1_low;
+      operands[5] = op1_high;
+    }
+  else
+    {
+      operands[2] = op0_high;
+      operands[3] = op0_low;
+      operands[4] = op1_high;
+      operands[5] = op1_low;
+    }
+}")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (match_operand:DI 1 "const_int_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 1))]
+  "
+{
+  rtx op0 = operands[0];
+  rtx op1 = operands[1];
+
+  operands[2] = gen_highpart (SImode, op0);
+  operands[3] = gen_lowpart (SImode, op0);
+  operands[4] = GEN_INT ((INTVAL (op1) < 0) ? -1 : 0);
+}")
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (match_operand:DI 1 "const_double_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))]
+  "
+{
+  rtx op0 = operands[0];
+  rtx op1 = operands[1];
+
+  operands[2] = gen_highpart (SImode, op0);
+  operands[3] = gen_lowpart (SImode, op0);
+  operands[4] = GEN_INT (CONST_DOUBLE_HIGH (op1));
+  operands[5] = GEN_INT (CONST_DOUBLE_LOW (op1));
+}")
+
+;; Floating Point Moves
+;;
+;; Note - Patterns for SF mode moves are compulsory, but
+;; patterns for DF are optional, as GCC can synthesise them.
+
+(define_expand "movsf"
+  [(set (match_operand:SF 0 "general_operand" "")
+       (match_operand:SF 1 "general_operand" ""))]
+  ""
+  "
+{
+  if (!reload_in_progress
+      && !reload_completed
+      && !register_operand (operands[0], SFmode)
+      && !reg_or_0_operand (operands[1], SFmode))
+    operands[1] = copy_to_mode_reg (SFmode, operands[1]);
+}")
+
+(define_split
+  [(set (match_operand:SF 0 "integer_register_operand" "")
+       (match_operand:SF 1 "int_2word_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 0)
+       (high:SF (match_dup 1)))
+   (set (match_dup 0)
+       (lo_sum:SF (match_dup 0)
+               (match_dup 1)))]
+  "")
+
+(define_insn "*movsf_load_has_fprs"
+  [(set (match_operand:SF 0 "register_operand" "=f,d")
+       (match_operand:SF 1 "frv_load_operand" "m,m"))]
+  "TARGET_HAS_FPRS"
+  "* return output_move_single (operands, insn);"
+  [(set_attr "length" "4")
+   (set_attr "type" "fload,gload")])
+
+(define_insn "*movsf_internal_has_fprs"
+  [(set (match_operand:SF 0 "move_destination_operand" "=f,f,m,m,?f,?d,?d,m,?d")
+       (match_operand:SF 1 "move_source_operand" "f,OG,f,OG,d,f,d,d,F"))]
+  "TARGET_HAS_FPRS
+   && (register_operand (operands[0], SFmode) || reg_or_0_operand (operands[1], SFmode))"
+  "* return output_move_single (operands, insn);"
+  [(set_attr "length" "4,4,4,4,4,4,4,4,8")
+   (set_attr "type" "fsconv,movgf,fstore,gstore,movgf,movfg,int,gstore,multi")])
+
+;; If we don't support the double instructions, prefer gprs over fprs, since it
+;; will all be emulated
+(define_insn "*movsf_internal_no_fprs"
+  [(set (match_operand:SF 0 "move_destination_operand" "=d,d,m,d,d")
+       (match_operand:SF 1 "move_source_operand"      " d,OG,dOG,m,F"))]
+  "!TARGET_HAS_FPRS
+   && (register_operand (operands[0], SFmode) || reg_or_0_operand (operands[1], SFmode))"
+  "* return output_move_single (operands, insn);"
+  [(set_attr "length" "4,4,4,4,8")
+   (set_attr "type" "int,int,gstore,gload,multi")])
+
+(define_insn "movsf_high"
+  [(set (match_operand:SF 0 "integer_register_operand" "=d")
+       (high:SF (match_operand:SF 1 "int_2word_operand" "i")))]
+  ""
+  "sethi #hi(%1), %0"
+  [(set_attr "type" "sethi")
+   (set_attr "length" "4")])
+
+(define_insn "movsf_lo_sum"
+  [(set (match_operand:SF 0 "integer_register_operand" "+d")
+       (lo_sum:SF (match_dup 0)
+                  (match_operand:SF 1 "int_2word_operand" "i")))]
+  ""
+  "setlo #lo(%1), %0"
+  [(set_attr "type" "setlo")
+   (set_attr "length" "4")])
+
+(define_expand "movdf"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "")
+       (match_operand:DF 1 "general_operand" ""))]
+  ""
+  "
+{
+  if (!reload_in_progress
+      && !reload_completed
+      && !register_operand (operands[0], DFmode)
+      && !reg_or_0_operand (operands[1], DFmode))
+    operands[1] = copy_to_mode_reg (DFmode, operands[1]);
+}")
+
+(define_insn "*movdf_double"
+  [(set (match_operand:DF 0 "move_destination_operand" "=h,?e,??f,??d,R,?R,??m,??m,h,?e,??f,??d,?h,??f,?e,??d,R,m,h,??f,e,??d")
+       (match_operand:DF 1 "move_source_operand"      " h,e,f,d,h,e,f,d,R,R,m,m,e,d,h,f,GO,GO,GO,GO,GO,GO"))]
+  "TARGET_DOUBLE
+   && (register_operand (operands[0], DFmode)
+       || reg_or_0_operand (operands[1], DFmode))"
+  "* return output_move_double (operands, insn);"
+  [(set_attr "length" "4,8,8,8,4,4,8,8,4,4,8,8,4,8,4,8,4,8,8,8,8,8")
+   (set_attr "type" "fdconv,multi,multi,multi,fstore,gstore,fstore,gstore,fload,gload,fload,gload,movgf,movgf,movfg,movfg,gstore,gstore,movgf,movgf,multi,multi")])
+
+;; If we don't support the double instructions, prefer gprs over fprs, since it
+;; will all be emulated
+(define_insn "*movdf_nodouble"
+  [(set (match_operand:DF 0 "move_destination_operand" "=e,?h,??d,??f,R,?R,??m,??m,e,?h,??d,??f,?e,??d,?h,??f,R,m,e,??d,e,??d,?h,??f")
+       (match_operand:DF 1 "move_source_operand"      " e,h,d,f,e,h,d,f,R,R,m,m,h,f,e,d,GO,GO,GO,GO,nF,nF,GO,GO"))]
+  "!TARGET_DOUBLE
+   && (register_operand (operands[0], DFmode)
+       || reg_or_0_operand (operands[1], DFmode))"
+  "* return output_move_double (operands, insn);"
+  [(set_attr "length" "8,8,8,8,4,4,8,8,4,4,8,8,8,8,8,8,4,8,8,8,16,16,8,8")
+   (set_attr "type" "multi,multi,multi,multi,gstore,fstore,gstore,fstore,gload,fload,gload,fload,movfg,movfg,movgf,movgf,gstore,gstore,multi,multi,multi,multi,movgf,movgf")])
+
+(define_split
+  [(set (match_operand:DF 0 "register_operand" "")
+       (match_operand:DF 1 "dbl_memory_two_insn_operand" ""))]
+  "reload_completed"
+  [(const_int 0)]
+  "frv_split_double_load (operands[0], operands[1]);")
+
+(define_split
+  [(set (match_operand:DF 0 "odd_reg_operand" "")
+       (match_operand:DF 1 "memory_operand" ""))]
+  "reload_completed"
+  [(const_int 0)]
+  "frv_split_double_load (operands[0], operands[1]);")
+
+(define_split
+  [(set (match_operand:DF 0 "dbl_memory_two_insn_operand" "")
+       (match_operand:DF 1 "reg_or_0_operand" ""))]
+  "reload_completed"
+  [(const_int 0)]
+  "frv_split_double_store (operands[0], operands[1]);")
+
+(define_split
+  [(set (match_operand:DF 0 "memory_operand" "")
+       (match_operand:DF 1 "odd_reg_operand" ""))]
+  "reload_completed"
+  [(const_int 0)]
+  "frv_split_double_store (operands[0], operands[1]);")
+
+(define_split
+  [(set (match_operand:DF 0 "register_operand" "")
+       (match_operand:DF 1 "register_operand" ""))]
+  "reload_completed
+   && (odd_reg_operand (operands[0], DFmode)
+       || odd_reg_operand (operands[1], DFmode)
+       || (integer_register_operand (operands[0], DFmode)
+          && integer_register_operand (operands[1], DFmode))
+       || (!TARGET_DOUBLE
+          && fpr_operand (operands[0], DFmode)
+          && fpr_operand (operands[1], DFmode)))"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))]
+  "
+{
+  rtx op0      = operands[0];
+  rtx op0_low  = gen_lowpart (SImode, op0);
+  rtx op0_high = gen_highpart (SImode, op0);
+  rtx op1      = operands[1];
+  rtx op1_low  = gen_lowpart (SImode, op1);
+  rtx op1_high = gen_highpart (SImode, op1);
+
+  /* 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.  */
+
+  if (REGNO (op0_high) == REGNO (op1_low))
+    {
+      operands[2] = op0_low;
+      operands[3] = op0_high;
+      operands[4] = op1_low;
+      operands[5] = op1_high;
+    }
+  else
+    {
+      operands[2] = op0_high;
+      operands[3] = op0_low;
+      operands[4] = op1_high;
+      operands[5] = op1_low;
+    }
+}")
+
+(define_split
+  [(set (match_operand:DF 0 "register_operand" "")
+       (match_operand:DF 1 "const_int_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 1))]
+  "
+{
+  rtx op0 = operands[0];
+  rtx op1 = operands[1];
+
+  operands[2] = gen_highpart (SImode, op0);
+  operands[3] = gen_lowpart (SImode, op0);
+  operands[4] = GEN_INT ((INTVAL (op1) < 0) ? -1 : 0);
+}")
+
+(define_split
+  [(set (match_operand:DF 0 "register_operand" "")
+       (match_operand:DF 1 "const_double_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))]
+  "
+{
+  rtx op0 = operands[0];
+  rtx op1 = operands[1];
+  REAL_VALUE_TYPE rv;
+  long l[2];
+
+  REAL_VALUE_FROM_CONST_DOUBLE (rv, op1);
+  REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
+
+  operands[2] = gen_highpart (SImode, op0);
+  operands[3] = gen_lowpart (SImode, op0);
+  operands[4] = GEN_INT (l[0]);
+  operands[5] = GEN_INT (l[1]);
+}")
+
+;; String/block move insn.
+;; Argument 0 is the destination
+;; Argument 1 is the source
+;; Argument 2 is the length
+;; Argument 3 is the alignment
+
+(define_expand "movstrsi"
+  [(parallel [(set (match_operand:BLK 0 "" "")
+                  (match_operand:BLK 1 "" ""))
+             (use (match_operand:SI 2 "" ""))
+             (use (match_operand:SI 3 "" ""))])]
+  ""
+  "
+{
+  if (frv_expand_block_move (operands))
+    DONE;
+  else
+    FAIL;
+}")
+
+;; String/block clear insn.
+;; Argument 0 is the destination
+;; Argument 1 is the length
+;; Argument 2 is the alignment
+
+(define_expand "clrstrsi"
+  [(parallel [(set (match_operand:BLK 0 "" "")
+                  (const_int 0))
+             (use (match_operand:SI 1 "" ""))
+             (use (match_operand:SI 2 "" ""))])]
+  ""
+  "
+{
+  if (frv_expand_block_clear (operands))
+    DONE;
+  else
+    FAIL;
+}")
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Reload CC registers
+;; ::
+;; ::::::::::::::::::::
+
+;; Use as a define_expand so that cse/gcse/combine can't accidentally
+;; create movcc insns.
+
+(define_expand "movcc"
+  [(parallel [(set (match_operand:CC 0 "move_destination_operand" "")
+                  (match_operand:CC 1 "move_source_operand" ""))
+             (clobber (match_dup 2))])]
+  ""
+  "
+{
+ if (! reload_in_progress && ! reload_completed)
+    FAIL;
+
+ operands[2] = gen_rtx_REG (CC_CCRmode, ICR_TEMP);
+}")
+
+(define_insn "*internal_movcc"
+  [(set (match_operand:CC 0 "move_destination_operand" "=t,d,d,m,d")
+       (match_operand:CC 1 "move_source_operand" "d,d,m,d,t"))
+   (clobber (match_scratch:CC_CCR 2 "=X,X,X,X,&v"))]
+  "reload_in_progress || reload_completed"
+  "@
+   cmpi %1, #0, %0
+   mov %1, %0
+   ld%I1%U1 %M1, %0
+   st%I0%U0 %1, %M0
+   #"
+  [(set_attr "length" "4,4,4,4,20")
+   (set_attr "type" "int,int,gload,gstore,multi")])
+
+;; To move an ICC value to a GPR for a signed comparison, we create a value
+;; that when compared to 0, sets the N and Z flags appropriately (we don't care
+;; about the V and C flags, since these comparisons are signed).
+
+(define_split
+  [(set (match_operand:CC 0 "integer_register_operand" "")
+       (match_operand:CC 1 "icc_operand" ""))
+   (clobber (match_operand:CC_CCR 2 "icr_operand" ""))]
+  "reload_in_progress || reload_completed"
+  [(match_dup 3)]
+  "
+{
+  rtx dest = simplify_gen_subreg (SImode, operands[0], CCmode, 0);
+  rtx icc  = operands[1];
+  rtx icr  = operands[2];
+
+  start_sequence ();
+
+  emit_insn (gen_rtx_SET (VOIDmode, icr,
+                         gen_rtx_LT (CC_CCRmode, icc, const0_rtx)));
+
+  emit_insn (gen_movsi (dest, const1_rtx));
+
+  emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                               gen_rtx_NE (CC_CCRmode, icr, const0_rtx),
+                               gen_rtx_SET (VOIDmode, dest,
+                                            gen_rtx_NEG (SImode, dest))));
+
+  emit_insn (gen_rtx_SET (VOIDmode, icr,
+                         gen_rtx_EQ (CC_CCRmode, icc, const0_rtx)));
+
+  emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                               gen_rtx_NE (CC_CCRmode, icr, const0_rtx),
+                               gen_rtx_SET (VOIDmode, dest, const0_rtx)));
+
+  operands[3] = get_insns ();
+  end_sequence ();
+}")
+
+(define_expand "reload_incc"
+  [(parallel [(set (match_operand:CC 2 "integer_register_operand" "=&d")
+                  (match_operand:CC 1 "memory_operand" "m"))
+             (clobber (match_scratch:CC_CCR 3 ""))])
+   (parallel [(set (match_operand:CC 0 "icc_operand" "=t")
+                  (match_dup 2))
+             (clobber (match_scratch:CC_CCR 4 ""))])]
+  ""
+  "")
+
+(define_expand "reload_outcc"
+  [(parallel [(set (match_operand:CC 2 "integer_register_operand" "=&d")
+                  (match_operand:CC 1 "icc_operand" "t"))
+             (clobber (match_dup 3))])
+   (parallel [(set (match_operand:CC 0 "memory_operand" "=m")
+                  (match_dup 2))
+             (clobber (match_scratch:CC_CCR 4 ""))])]
+  ""
+  "operands[3] = gen_rtx_REG (CC_CCRmode, ICR_TEMP);")
+
+;; Reload CC_UNSmode for unsigned integer comparisons
+;; Use define_expand so that cse/gcse/combine can't create movcc_uns insns
+
+(define_expand "movcc_uns"
+  [(parallel [(set (match_operand:CC_UNS 0 "move_destination_operand" "")
+                  (match_operand:CC_UNS 1 "move_source_operand" ""))
+             (clobber (match_dup 2))])]
+  ""
+  "
+{
+ if (! reload_in_progress && ! reload_completed)
+    FAIL;
+ operands[2] = gen_rtx_REG (CC_CCRmode, ICR_TEMP);
+}")
+
+(define_insn "*internal_movcc_uns"
+  [(set (match_operand:CC_UNS 0 "move_destination_operand" "=t,d,d,m,d")
+       (match_operand:CC_UNS 1 "move_source_operand" "d,d,m,d,t"))
+   (clobber (match_scratch:CC_CCR 2 "=X,X,X,X,&v"))]
+  "reload_in_progress || reload_completed"
+  "@
+   cmpi %1, #1, %0
+   mov %1, %0
+   ld%I1%U1 %M1, %0
+   st%I0%U0 %1, %M0
+   #"
+  [(set_attr "length" "4,4,4,4,20")
+   (set_attr "type" "int,int,gload,gstore,multi")])
+
+;; To move an ICC value to a GPR for an unsigned comparison, we create a value
+;; that when compared to 1, sets the Z, V, and C flags appropriately (we don't
+;; care about the N flag, since these comparisons are unsigned).
+
+(define_split
+  [(set (match_operand:CC_UNS 0 "integer_register_operand" "")
+       (match_operand:CC_UNS 1 "icc_operand" ""))
+   (clobber (match_operand:CC_CCR 2 "icr_operand" ""))]
+  "reload_in_progress || reload_completed"
+  [(match_dup 3)]
+  "
+{
+  rtx dest = simplify_gen_subreg (SImode, operands[0], CC_UNSmode, 0);
+  rtx icc  = operands[1];
+  rtx icr  = operands[2];
+
+  start_sequence ();
+
+  emit_insn (gen_rtx_SET (VOIDmode, icr,
+                         gen_rtx_GTU (CC_CCRmode, icc, const0_rtx)));
+
+  emit_insn (gen_movsi (dest, const1_rtx));
+
+  emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                               gen_rtx_NE (CC_CCRmode, icr, const0_rtx),
+                               gen_addsi3 (dest, dest, dest)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, icr,
+                         gen_rtx_LTU (CC_CCRmode, icc, const0_rtx)));
+
+  emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                               gen_rtx_NE (CC_CCRmode, icr, const0_rtx),
+                               gen_rtx_SET (VOIDmode, dest, const0_rtx)));
+
+  operands[3] = get_insns ();
+  end_sequence ();
+}")
+
+(define_expand "reload_incc_uns"
+  [(parallel [(set (match_operand:CC_UNS 2 "integer_register_operand" "=&d")
+                  (match_operand:CC_UNS 1 "memory_operand" "m"))
+             (clobber (match_scratch:CC_CCR 3 ""))])
+   (parallel [(set (match_operand:CC_UNS 0 "icc_operand" "=t")
+                  (match_dup 2))
+             (clobber (match_scratch:CC_CCR 4 ""))])]
+  ""
+  "")
+
+(define_expand "reload_outcc_uns"
+  [(parallel [(set (match_operand:CC_UNS 2 "integer_register_operand" "=&d")
+                  (match_operand:CC_UNS 1 "icc_operand" "t"))
+             (clobber (match_dup 3))])
+   (parallel [(set (match_operand:CC_UNS 0 "memory_operand" "=m")
+                  (match_dup 2))
+             (clobber (match_scratch:CC_CCR 4 ""))])]
+  ""
+  "operands[3] = gen_rtx_REG (CC_CCRmode, ICR_TEMP);")
+
+;; Reload CC_FPmode for floating point comparisons
+;; We use a define_expand here so that cse/gcse/combine can't accidentally
+;; create movcc insns.  If this was a named define_insn, we would not be able
+;; to make it conditional on reload.
+
+(define_expand "movcc_fp"
+  [(set (match_operand:CC_FP 0 "move_destination_operand" "")
+       (match_operand:CC_FP 1 "move_source_operand" ""))]
+  "TARGET_HAS_FPRS"
+  "
+{
+ if (! reload_in_progress && ! reload_completed)
+    FAIL;
+}")
+
+(define_insn "*movcc_fp_internal"
+  [(set (match_operand:CC_FP 0 "move_destination_operand" "=d,d,d,m")
+       (match_operand:CC_FP 1 "move_source_operand" "u,d,m,d"))]
+  "TARGET_HAS_FPRS && (reload_in_progress || reload_completed)"
+  "@
+   #
+   mov %1, %0
+   ld%I1%U1 %M1, %0
+   st%I0%U0 %1, %M0"
+  [(set_attr "length" "12,4,4,4")
+   (set_attr "type" "multi,int,gload,gstore")])
+
+
+(define_expand "reload_incc_fp"
+  [(match_operand:CC_FP 0 "fcc_operand" "=u")
+   (match_operand:CC_FP 1 "memory_operand" "m")
+   (match_operand:TI 2 "integer_register_operand" "=&d")]
+  "TARGET_HAS_FPRS"
+  "
+{
+  rtx cc_op2 = simplify_gen_subreg (CC_FPmode, operands[2], TImode, 0);
+  rtx int_op2 = simplify_gen_subreg (SImode, operands[2], TImode, 0);
+  rtx temp1 = simplify_gen_subreg (SImode, operands[2], TImode, 4);
+  rtx temp2 = simplify_gen_subreg (SImode, operands[2], TImode, 8);
+  int shift = CC_SHIFT_RIGHT (REGNO (operands[0]));
+  HOST_WIDE_INT mask;
+
+  emit_insn (gen_movcc_fp (cc_op2, operands[1]));
+  if (shift)
+    emit_insn (gen_ashlsi3 (int_op2, int_op2, GEN_INT (shift)));
+
+  mask = ~ ((HOST_WIDE_INT)CC_MASK << shift);
+  emit_insn (gen_movsi (temp1, GEN_INT (mask)));
+  emit_insn (gen_update_fcc (operands[0], int_op2, temp1, temp2));
+  DONE;
+}")
+
+(define_expand "reload_outcc_fp"
+  [(set (match_operand:CC_FP 2 "integer_register_operand" "=&d")
+       (match_operand:CC_FP 1 "fcc_operand" "u"))
+   (set (match_operand:CC_FP 0 "memory_operand" "=m")
+       (match_dup 2))]
+  "TARGET_HAS_FPRS"
+ "")
+
+;; Convert a FCC value to gpr
+(define_insn "read_fcc"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (unspec:SI [(match_operand:CC_FP 1 "fcc_operand" "u")]
+                  UNSPEC_CC_TO_GPR))]
+  "TARGET_HAS_FPRS"
+  "movsg ccr, %0"
+  [(set_attr "type" "spr")
+   (set_attr "length" "4")])
+
+(define_split
+  [(set (match_operand:CC_FP 0 "integer_register_operand" "")
+       (match_operand:CC_FP 1 "fcc_operand" ""))]
+  "reload_completed && TARGET_HAS_FPRS"
+  [(match_dup 2)]
+  "
+{
+  rtx int_op0 = simplify_gen_subreg (SImode, operands[0], CC_FPmode, 0);
+  int shift = CC_SHIFT_RIGHT (REGNO (operands[1]));
+
+  start_sequence ();
+
+  emit_insn (gen_read_fcc (int_op0, operands[1]));
+  if (shift)
+    emit_insn (gen_lshrsi3 (int_op0, int_op0, GEN_INT (shift)));
+
+  emit_insn (gen_andsi3 (int_op0, int_op0, GEN_INT (CC_MASK)));
+
+  operands[2] = get_insns ();
+  end_sequence ();
+}")
+
+;; Move a gpr value to FCC.
+;; Operand0 = FCC
+;; Operand1 = reloaded value shifted appropriately
+;; Operand2 = mask to eliminate current register
+;; Operand3 = temporary to load/store ccr
+(define_insn "update_fcc"
+  [(set (match_operand:CC_FP 0 "fcc_operand" "=u")
+       (unspec:CC_FP [(match_operand:SI 1 "integer_register_operand" "d")
+                      (match_operand:SI 2 "integer_register_operand" "d")]
+                     UNSPEC_GPR_TO_CC))
+   (clobber (match_operand:SI 3 "integer_register_operand" "=&d"))]
+  "TARGET_HAS_FPRS"
+  "movsg ccr, %3\;and %2, %3, %3\;or %1, %3, %3\;movgs %3, ccr"
+  [(set_attr "type" "multi")
+   (set_attr "length" "16")])
+
+;; Reload CC_CCRmode for conditional execution registers
+(define_insn "movcc_ccr"
+  [(set (match_operand:CC_CCR 0 "move_destination_operand" "=d,d,d,m,v,?w,C,d")
+       (match_operand:CC_CCR 1 "move_source_operand" "C,d,m,d,n,n,C,L"))]
+  ""
+  "@
+   #
+   mov %1, %0
+   ld%I1%U1 %M1, %0
+   st%I0%U0 %1, %M0
+   #
+   #
+   orcr %1, %1, %0
+   setlos #%1, %0"
+  [(set_attr "length" "8,4,4,4,8,12,4,4")
+   (set_attr "type" "multi,int,gload,gstore,multi,multi,ccr,int")])
+
+(define_expand "reload_incc_ccr"
+  [(match_operand:CC_CCR 0 "cr_operand" "=C")
+   (match_operand:CC_CCR 1 "memory_operand" "m")
+   (match_operand:CC_CCR 2 "integer_register_operand" "=&d")]
+  ""
+  "
+{
+  rtx icc = gen_rtx_REG (CCmode, ICC_TEMP);
+  rtx int_op2 = simplify_gen_subreg (SImode, operands[2], CC_CCRmode, 0);
+  rtx icr = (ICR_P (REGNO (operands[0]))
+            ? operands[0] : gen_rtx_REG (CC_CCRmode, ICR_TEMP));
+
+  emit_insn (gen_movcc_ccr (operands[2], operands[1]));
+  emit_insn (gen_cmpsi_cc (icc, int_op2, const0_rtx));
+  emit_insn (gen_movcc_ccr (icr, gen_rtx_NE (CC_CCRmode, icc, const0_rtx)));
+
+  if (! ICR_P (REGNO (operands[0])))
+    emit_insn (gen_movcc_ccr (operands[0], icr));
+
+  DONE;
+}")
+
+(define_expand "reload_outcc_ccr"
+  [(set (match_operand:CC_CCR 2 "integer_register_operand" "=&d")
+       (match_operand:CC_CCR 1 "cr_operand" "C"))
+   (set (match_operand:CC_CCR 0 "memory_operand" "=m")
+       (match_dup 2))]
+  ""
+  "")
+
+(define_split
+  [(set (match_operand:CC_CCR 0 "integer_register_operand" "")
+       (match_operand:CC_CCR 1 "cr_operand" ""))]
+  "reload_completed"
+  [(match_dup 2)]
+  "
+{
+  rtx int_op0 = simplify_gen_subreg (SImode, operands[0], CC_CCRmode, 0);
+
+  start_sequence ();
+  emit_move_insn (operands[0], const1_rtx);
+  emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+                               gen_rtx_EQ (CC_CCRmode,
+                                           operands[1],
+                                           const0_rtx),
+                               gen_rtx_SET (VOIDmode, int_op0,
+                                            const0_rtx)));
+
+  operands[2] = get_insns ();
+  end_sequence ();
+}")
+
+(define_split
+  [(set (match_operand:CC_CCR 0 "cr_operand" "")
+       (match_operand:CC_CCR 1 "const_int_operand" ""))]
+  "reload_completed"
+  [(match_dup 2)]
+  "
+{
+  rtx icc = gen_rtx_REG (CCmode, ICC_TEMP);
+  rtx r0  = gen_rtx_REG (SImode, GPR_FIRST);
+  rtx icr = (ICR_P (REGNO (operands[0]))
+            ? operands[0] : gen_rtx_REG (CC_CCRmode, ICR_TEMP));
+
+  start_sequence ();
+
+ emit_insn (gen_cmpsi_cc (icc, r0, const0_rtx));
+
+  emit_insn (gen_movcc_ccr (icr,
+                           gen_rtx_fmt_ee (((INTVAL (operands[1]) == 0)
+                                            ? EQ : NE), CC_CCRmode,
+                                           r0, const0_rtx)));
+
+  if (! ICR_P (REGNO (operands[0])))
+    emit_insn (gen_movcc_ccr (operands[0], icr));
+
+  operands[2] = get_insns ();
+  end_sequence ();
+}")
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Conversions
+;; ::
+;; ::::::::::::::::::::
+
+;; Signed conversions from a smaller integer to a larger integer
+;;
+;; These operations are optional.  If they are not
+;; present GCC will synthesise them for itself
+;; Even though frv does not provide these instructions, we define them
+;; to allow load + sign extend to be collapsed together
+(define_insn "extendqihi2"
+  [(set (match_operand:HI 0 "integer_register_operand" "=d,d")
+       (sign_extend:HI (match_operand:QI 1 "gpr_or_memory_operand" "d,m")))]
+  ""
+  "@
+   #
+   ldsb%I1%U1 %M1,%0"
+  [(set_attr "length" "8,4")
+   (set_attr "type" "multi,gload")])
+
+(define_split
+  [(set (match_operand:HI 0 "integer_register_operand" "")
+       (sign_extend:HI (match_operand:QI 1 "integer_register_operand" "")))]
+  "reload_completed"
+  [(match_dup 2)
+   (match_dup 3)]
+  "
+{
+  rtx op0   = gen_lowpart (SImode, operands[0]);
+  rtx op1   = gen_lowpart (SImode, operands[1]);
+  rtx shift = GEN_INT (24);
+
+  operands[2] = gen_ashlsi3 (op0, op1, shift);
+  operands[3] = gen_ashrsi3 (op0, op0, shift);
+}")
+
+(define_insn "extendqisi2"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d")
+       (sign_extend:SI (match_operand:QI 1 "gpr_or_memory_operand" "d,m")))]
+  ""
+  "@
+   #
+   ldsb%I1%U1 %M1,%0"
+  [(set_attr "length" "8,4")
+   (set_attr "type" "multi,gload")])
+
+(define_split
+  [(set (match_operand:SI 0 "integer_register_operand" "")
+       (sign_extend:SI (match_operand:QI 1 "integer_register_operand" "")))]
+  "reload_completed"
+  [(match_dup 2)
+   (match_dup 3)]
+  "
+{
+  rtx op0   = gen_lowpart (SImode, operands[0]);
+  rtx op1   = gen_lowpart (SImode, operands[1]);
+  rtx shift = GEN_INT (24);
+
+  operands[2] = gen_ashlsi3 (op0, op1, shift);
+  operands[3] = gen_ashrsi3 (op0, op0, shift);
+}")
+
+;;(define_insn "extendqidi2"
+;;  [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (sign_extend:DI (match_operand:QI 1 "general_operand" "g")))]
+;;  ""
+;;  "extendqihi2 %0,%1"
+;;  [(set_attr "length" "4")])
+
+(define_insn "extendhisi2"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d")
+       (sign_extend:SI (match_operand:HI 1 "gpr_or_memory_operand" "d,m")))]
+  ""
+  "@
+   #
+   ldsh%I1%U1 %M1,%0"
+  [(set_attr "length" "8,4")
+   (set_attr "type" "multi,gload")])
+
+(define_split
+  [(set (match_operand:SI 0 "integer_register_operand" "")
+       (sign_extend:SI (match_operand:HI 1 "integer_register_operand" "")))]
+  "reload_completed"
+  [(match_dup 2)
+   (match_dup 3)]
+  "
+{
+  rtx op0   = gen_lowpart (SImode, operands[0]);
+  rtx op1   = gen_lowpart (SImode, operands[1]);
+  rtx shift = GEN_INT (16);
+
+  operands[2] = gen_ashlsi3 (op0, op1, shift);
+  operands[3] = gen_ashrsi3 (op0, op0, shift);
+}")
+
+;;(define_insn "extendhidi2"
+;;  [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (sign_extend:DI (match_operand:HI 1 "general_operand" "g")))]
+;;  ""
+;;  "extendhihi2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "extendsidi2"
+;;  [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (sign_extend:DI (match_operand:SI 1 "general_operand" "g")))]
+;;  ""
+;;  "extendsidi2 %0,%1"
+;;  [(set_attr "length" "4")])
+
+;; Unsigned conversions from a smaller integer to a larger integer
+(define_insn "zero_extendqihi2"
+  [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d")
+       (zero_extend:HI
+         (match_operand:QI 1 "gpr_or_memory_operand" "d,L,m")))]
+  ""
+  "@
+   andi %1,#0xff,%0
+   setlos %1,%0
+   ldub%I1%U1 %M1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,int,gload")])
+
+(define_insn "zero_extendqisi2"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d")
+       (zero_extend:SI
+         (match_operand:QI 1 "gpr_or_memory_operand" "d,L,m")))]
+  ""
+  "@
+   andi %1,#0xff,%0
+   setlos %1,%0
+   ldub%I1%U1 %M1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,int,gload")])
+
+;;(define_insn "zero_extendqidi2"
+;;  [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (zero_extend:DI (match_operand:QI 1 "general_operand" "g")))]
+;;  ""
+;;  "zero_extendqihi2 %0,%1"
+;;  [(set_attr "length" "4")])
+
+;; Do not set the type for the sethi to "sethi", since the scheduler will think
+;; the sethi takes 0 cycles as part of allowing sethi/setlo to be in the same
+;; VLIW instruction.
+(define_insn "zero_extendhisi2"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d")
+       (zero_extend:SI (match_operand:HI 1 "gpr_or_memory_operand" "0,m")))]
+  ""
+  "@
+    sethi #hi(#0),%0
+    lduh%I1%U1 %M1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,gload")])
+
+;;(define_insn "zero_extendhidi2"
+;;  [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (zero_extend:DI (match_operand:HI 1 "general_operand" "g")))]
+;;  ""
+;;  "zero_extendhihi2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "zero_extendsidi2"
+;;  [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (zero_extend:DI (match_operand:SI 1 "general_operand" "g")))]
+;;  ""
+;;  "zero_extendsidi2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;;; Convert between floating point types of different sizes.
+;;
+;;(define_insn "extendsfdf2"
+;;  [(set (match_operand:DF 0 "register_operand" "=r")
+;;     (float_extend:DF (match_operand:SF 1 "register_operand" "r")))]
+;;  ""
+;;  "extendsfdf2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "truncdfsf2"
+;;  [(set (match_operand:SF 0 "register_operand" "=r")
+;;     (float_truncate:SF (match_operand:DF 1 "register_operand" "r")))]
+;;  ""
+;;  "truncdfsf2 %0,%1"
+;;  [(set_attr "length" "4")])
+
+;;;; Convert between signed integer types and floating point.
+(define_insn "floatsisf2"
+  [(set (match_operand:SF 0 "fpr_operand" "=f")
+       (float:SF (match_operand:SI 1 "fpr_operand" "f")))]
+  "TARGET_HARD_FLOAT"
+  "fitos %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsconv")])
+
+(define_insn "floatsidf2"
+  [(set (match_operand:DF 0 "fpr_operand" "=h")
+       (float:DF (match_operand:SI 1 "fpr_operand" "f")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "fitod %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fdconv")])
+
+;;(define_insn "floatdisf2"
+;;  [(set (match_operand:SF 0 "register_operand" "=r")
+;;     (float:SF (match_operand:DI 1 "register_operand" "r")))]
+;;  ""
+;;  "floatdisf2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "floatdidf2"
+;;  [(set (match_operand:DF 0 "register_operand" "=r")
+;;     (float:DF (match_operand:DI 1 "register_operand" "r")))]
+;;  ""
+;;  "floatdidf2 %0,%1"
+;;  [(set_attr "length" "4")])
+
+(define_insn "fix_truncsfsi2"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+       (fix:SI (match_operand:SF 1 "fpr_operand" "f")))]
+  "TARGET_HARD_FLOAT"
+  "fstoi %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsconv")])
+
+(define_insn "fix_truncdfsi2"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+       (fix:SI (match_operand:DF 1 "fpr_operand" "h")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "fdtoi %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fdconv")])
+
+;;(define_insn "fix_truncsfdi2"
+;;  [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (fix:DI (match_operand:SF 1 "register_operand" "r")))]
+;;  ""
+;;  "fix_truncsfdi2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "fix_truncdfdi2"
+;;  [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (fix:DI (match_operand:DF 1 "register_operand" "r")))]
+;;  ""
+;;  "fix_truncdfdi2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;;; Convert between unsigned integer types and floating point.
+;;
+;;(define_insn "floatunssisf2"
+;;  [(set (match_operand:SF 0 "register_operand" "=r")
+;;     (unsigned_float:SF (match_operand:SI 1 "register_operand" "r")))]
+;;  ""
+;;  "floatunssisf2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "floatunssidf2"
+;;  [(set (match_operand:DF 0 "register_operand" "=r")
+;;     (unsigned_float:DF (match_operand:SI 1 "register_operand" "r")))]
+;;  ""
+;;  "floatunssidf2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "floatunsdisf2"
+;;  [(set (match_operand:SF 0 "register_operand" "=r")
+;;     (unsigned_float:SF (match_operand:DI 1 "register_operand" "r")))]
+;;  ""
+;;  "floatunsdisf2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "floatunsdidf2"
+;;  [(set (match_operand:DF 0 "register_operand" "=r")
+;;     (unsigned_float:DF (match_operand:DI 1 "register_operand" "r")))]
+;;  ""
+;;  "floatunsdidf2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "fixuns_truncsfsi2"
+;;  [(set (match_operand:SI 0 "register_operand" "=r")
+;;     (unsigned_fix:SI (match_operand:SF 1 "register_operand" "r")))]
+;;  ""
+;;  "fixuns_truncsfsi2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "fixuns_truncdfsi2"
+;;  [(set (match_operand:SI 0 "register_operand" "=r")
+;;     (unsigned_fix:SI (match_operand:DF 1 "register_operand" "r")))]
+;;  ""
+;;  "fixuns_truncdfsi2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "fixuns_truncsfdi2"
+;;  [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (unsigned_fix:DI (match_operand:SF 1 "register_operand" "r")))]
+;;  ""
+;;  "fixuns_truncsfdi2 %0,%1"
+;;  [(set_attr "length" "4")])
+;;
+;;(define_insn "fixuns_truncdfdi2"
+;;  [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (unsigned_fix:DI (match_operand:DF 1 "register_operand" "r")))]
+;;  ""
+;;  "fixuns_truncdfdi2 %0,%1"
+;;  [(set_attr "length" "4")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: 32 bit Integer arithmetic
+;; ::
+;; ::::::::::::::::::::
+
+;; Addition
+(define_insn "addsi3"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (plus:SI (match_operand:SI 1 "integer_register_operand" "%d")
+                (match_operand:SI 2 "gpr_or_int12_operand" "dNOP")))]
+  ""
+  "add%I2 %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+;; Subtraction.  No need to worry about constants, since the compiler
+;; canonicalizes them into addsi3's.  We prevent SUBREG's here to work around a
+;; combine bug, that combines the 32x32->upper 32 bit multiply that uses a
+;; SUBREG with a minus that shows up in modulus by constants.
+(define_insn "subsi3"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (minus:SI (match_operand:SI 1 "gpr_no_subreg_operand" "d")
+                 (match_operand:SI 2 "gpr_no_subreg_operand" "d")))]
+  ""
+  "sub %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+;; Signed multiplication producing 64 bit results from 32 bit inputs
+;; Note, frv doesn't have a 32x32->32 bit multiply, but the compiler
+;; will do the 32x32->64 bit multiply and use the bottom word.
+(define_expand "mulsidi3"
+  [(set (match_operand:DI 0 "integer_register_operand" "")
+       (mult:DI (sign_extend:DI (match_operand:SI 1 "integer_register_operand" ""))
+                (sign_extend:DI (match_operand:SI 2 "gpr_or_int12_operand" ""))))]
+  ""
+  "
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      emit_insn (gen_mulsidi3_const (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+}")
+
+(define_insn "*mulsidi3_reg"
+  [(set (match_operand:DI 0 "even_gpr_operand" "=e")
+       (mult:DI (sign_extend:DI (match_operand:SI 1 "integer_register_operand" "%d"))
+                (sign_extend:DI (match_operand:SI 2 "integer_register_operand" "d"))))]
+  ""
+  "smul %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mul")])
+
+(define_insn "mulsidi3_const"
+  [(set (match_operand:DI 0 "even_gpr_operand" "=e")
+       (mult:DI (sign_extend:DI (match_operand:SI 1 "integer_register_operand" "d"))
+                (match_operand:SI 2 "int12_operand" "NOP")))]
+  ""
+  "smuli %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mul")])
+
+;; Unsigned multiplication producing 64 bit results from 32 bit inputs
+(define_expand "umulsidi3"
+  [(set (match_operand:DI 0 "even_gpr_operand" "")
+       (mult:DI (zero_extend:DI (match_operand:SI 1 "integer_register_operand" ""))
+                (zero_extend:DI (match_operand:SI 2 "gpr_or_int12_operand" ""))))]
+  ""
+  "
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      emit_insn (gen_umulsidi3_const (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+}")
+
+(define_insn "*mulsidi3_reg"
+  [(set (match_operand:DI 0 "even_gpr_operand" "=e")
+       (mult:DI (zero_extend:DI (match_operand:SI 1 "integer_register_operand" "%d"))
+                (zero_extend:DI (match_operand:SI 2 "integer_register_operand" "d"))))]
+  ""
+  "umul %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mul")])
+
+(define_insn "umulsidi3_const"
+  [(set (match_operand:DI 0 "even_gpr_operand" "=e")
+       (mult:DI (zero_extend:DI (match_operand:SI 1 "integer_register_operand" "d"))
+                (match_operand:SI 2 "int12_operand" "NOP")))]
+  ""
+  "umuli %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mul")])
+
+;; Signed Division
+(define_insn "divsi3"
+  [(set (match_operand:SI 0 "register_operand" "=d,d")
+       (div:SI (match_operand:SI 1 "register_operand" "d,d")
+               (match_operand:SI 2 "gpr_or_int12_operand" "d,NOP")))]
+  ""
+  "sdiv%I2 %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "div")])
+
+;; Unsigned Division
+(define_insn "udivsi3"
+  [(set (match_operand:SI 0 "register_operand" "=d,d")
+       (udiv:SI (match_operand:SI 1 "register_operand" "d,d")
+                (match_operand:SI 2 "gpr_or_int12_operand" "d,NOP")))]
+  ""
+  "udiv%I2 %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "div")])
+
+;; Negation
+(define_insn "negsi2"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (neg:SI (match_operand:SI 1 "integer_register_operand" "d")))]
+  ""
+  "sub %.,%1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+;; Find first one bit
+;; (define_insn "ffssi2"
+;;   [(set (match_operand:SI 0 "register_operand" "=r")
+;;     (ffs:SI (match_operand:SI 1 "register_operand" "r")))]
+;;   ""
+;;   "ffssi2 %0,%1"
+;;   [(set_attr "length" "4")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: 64 bit Integer arithmetic
+;; ::
+;; ::::::::::::::::::::
+
+;; Addition
+(define_expand "adddi3"
+  [(parallel [(set (match_operand:DI 0 "integer_register_operand" "")
+                  (plus:DI (match_operand:DI 1 "integer_register_operand" "")
+                           (match_operand:DI 2 "gpr_or_int10_operand" "")))
+             (clobber (match_scratch:CC 3 ""))])]
+  ""
+  "
+{
+  if (GET_CODE (operands[2]) == CONST_INT
+      && INTVAL (operands[2]) == -2048
+      && !no_new_pseudos)
+    operands[2] = force_reg (DImode, operands[2]);
+}")
+
+(define_insn_and_split "*adddi3_internal"
+  [(set (match_operand:DI 0 "integer_register_operand" "=&e,e,e,&e,e,&e,e")
+       (plus:DI (match_operand:DI 1 "integer_register_operand" "%e,0,e,e,0,e,0")
+                (match_operand:DI 2 "gpr_or_int10_operand" "e,e,0,N,N,OP,OP")))
+   (clobber (match_scratch:CC 3 "=t,t,t,t,t,t,t"))]
+  "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -2048"
+  "#"
+  "reload_completed"
+  [(match_dup 4)
+   (match_dup 5)]
+  "
+{
+  rtx op0_high = gen_highpart (SImode, operands[0]);
+  rtx op1_high = gen_highpart (SImode, operands[1]);
+  rtx op0_low  = gen_lowpart (SImode, operands[0]);
+  rtx op1_low  = gen_lowpart (SImode, operands[1]);
+  rtx op2 = operands[2];
+  rtx op3 = operands[3];
+
+  if (GET_CODE (op2) != CONST_INT)
+    {
+      rtx op2_high = gen_highpart (SImode, operands[2]);
+      rtx op2_low  = gen_lowpart (SImode, operands[2]);
+      operands[4] = gen_adddi3_lower (op0_low, op1_low, op2_low, op3);
+      operands[5] = gen_adddi3_upper (op0_high, op1_high, op2_high, op3);
+    }
+  else if (INTVAL (op2) >= 0)
+    {
+      operands[4] = gen_adddi3_lower (op0_low, op1_low, op2, op3);
+      operands[5] = gen_adddi3_upper (op0_high, op1_high, const0_rtx, op3);
+    }
+  else
+    {
+      operands[4] = gen_subdi3_lower (op0_low, op1_low,
+                                     GEN_INT (- INTVAL (op2)), op3);
+      operands[5] = gen_subdi3_upper (op0_high, op1_high, const0_rtx, op3);
+    }
+}"
+  [(set_attr "length" "8")
+   (set_attr "type" "multi")])
+
+;; Subtraction  No need to worry about constants, since the compiler
+;; canonicalizes them into adddi3's.
+(define_expand "subdi3"
+  [(parallel [(set (match_operand:DI 0 "integer_register_operand" "")
+                  (minus:DI (match_operand:DI 1 "integer_register_operand" "")
+                            (match_operand:DI 2 "integer_register_operand" "")))
+             (clobber (match_dup 3))])]
+  ""
+  "
+{
+  operands[3] = gen_reg_rtx (CCmode);
+}")
+
+(define_insn_and_split "*subdi3_internal"
+  [(set (match_operand:DI 0 "integer_register_operand" "=&e,e,e")
+       (minus:DI (match_operand:DI 1 "integer_register_operand" "e,0,e")
+                 (match_operand:DI 2 "integer_register_operand" "e,e,0")))
+   (clobber (match_operand:CC 3 "icc_operand" "=t,t,t"))]
+  ""
+  "#"
+  "reload_completed"
+  [(match_dup 4)
+   (match_dup 5)]
+  "
+{
+  rtx op0_high = gen_highpart (SImode, operands[0]);
+  rtx op1_high = gen_highpart (SImode, operands[1]);
+  rtx op2_high = gen_highpart (SImode, operands[2]);
+  rtx op0_low  = gen_lowpart (SImode, operands[0]);
+  rtx op1_low  = gen_lowpart (SImode, operands[1]);
+  rtx op2_low  = gen_lowpart (SImode, operands[2]);
+  rtx op3 = operands[3];
+
+  operands[4] = gen_subdi3_lower (op0_low, op1_low, op2_low, op3);
+  operands[5] = gen_subdi3_upper (op0_high, op1_high, op2_high, op3);
+}"
+  [(set_attr "length" "8")
+   (set_attr "type" "multi")])
+
+;; Patterns for addsi3/subdi3 after spliting
+(define_insn "adddi3_lower"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (plus:SI (match_operand:SI 1 "integer_register_operand" "d")
+                (match_operand:SI 2 "gpr_or_int10_operand" "dOP")))
+   (set (match_operand:CC 3 "icc_operand" "=t")
+       (compare:CC (plus:SI (match_dup 1)
+                            (match_dup 2))
+                   (const_int 0)))]
+  "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) >= 0"
+  "add%I2cc %1,%2,%0,%3"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_insn "adddi3_upper"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d")
+       (plus:SI (match_operand:SI 1 "integer_register_operand" "d,d")
+                (plus:SI (match_operand:SI 2 "reg_or_0_operand" "d,O")
+                         (match_operand:CC 3 "icc_operand" "t,t"))))]
+  ""
+  "@
+   addx %1,%2,%0,%3
+   addx %1,%.,%0,%3"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_insn "subdi3_lower"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (minus:SI (match_operand:SI 1 "integer_register_operand" "d")
+                 (match_operand:SI 2 "gpr_or_int10_operand" "dOP")))
+   (set (match_operand:CC 3 "icc_operand" "=t")
+       (compare:CC (plus:SI (match_dup 1)
+                            (match_dup 2))
+                   (const_int 0)))]
+  "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) >= 0"
+  "sub%I2cc %1,%2,%0,%3"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_insn "subdi3_upper"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d")
+       (minus:SI (match_operand:SI 1 "integer_register_operand" "d,d")
+                 (minus:SI (match_operand:SI 2 "reg_or_0_operand" "d,O")
+                           (match_operand:CC 3 "icc_operand" "t,t"))))]
+  ""
+  "@
+   subx %1,%2,%0,%3
+   subx %1,%.,%0,%3"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+;; Multiplication (same size)
+;; (define_insn "muldi3"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (mult:DI (match_operand:DI 1 "register_operand" "%r")
+;;              (match_operand:DI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "muldi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+;; Signed Division
+;; (define_insn "divdi3"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (div:DI (match_operand:DI 1 "register_operand" "r")
+;;             (match_operand:DI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "divdi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+;; Undsgned Division
+;; (define_insn "udivdi3"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (udiv:DI (match_operand:DI 1 "register_operand" "r")
+;;              (match_operand:DI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "udivdi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+;; Negation
+;; (define_insn "negdi2"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (neg:DI (match_operand:DI 1 "register_operand" "r")))]
+;;   ""
+;;   "negdi2 %0,%1"
+;;   [(set_attr "length" "4")])
+
+;; Find first one bit
+;; (define_insn "ffsdi2"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (ffs:DI (match_operand:DI 1 "register_operand" "r")))]
+;;   ""
+;;   "ffsdi2 %0,%1"
+;;   [(set_attr "length" "4")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: 32 bit floating point arithmetic
+;; ::
+;; ::::::::::::::::::::
+
+;; Addition
+(define_insn "addsf3"
+  [(set (match_operand:SF 0 "fpr_operand" "=f")
+       (plus:SF (match_operand:SF 1 "fpr_operand" "%f")
+                (match_operand:SF 2 "fpr_operand" "f")))]
+  "TARGET_HARD_FLOAT"
+  "fadds %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsadd")])
+
+;; Subtraction
+(define_insn "subsf3"
+  [(set (match_operand:SF 0 "fpr_operand" "=f")
+       (minus:SF (match_operand:SF 1 "fpr_operand" "f")
+                 (match_operand:SF 2 "fpr_operand" "f")))]
+  "TARGET_HARD_FLOAT"
+  "fsubs %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsadd")])
+
+;; Multiplication
+(define_insn "mulsf3"
+  [(set (match_operand:SF 0 "fpr_operand" "=f")
+       (mult:SF (match_operand:SF 1 "fpr_operand" "%f")
+                (match_operand:SF 2 "fpr_operand" "f")))]
+  "TARGET_HARD_FLOAT"
+  "fmuls %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsmul")])
+
+;; Multiplication with addition/subtraction
+(define_insn "*muladdsf4"
+  [(set (match_operand:SF 0 "fpr_operand" "=f")
+       (plus:SF (mult:SF (match_operand:SF 1 "fpr_operand" "%f")
+                         (match_operand:SF 2 "fpr_operand" "f"))
+                (match_operand:SF 3 "fpr_operand" "0")))]
+  "TARGET_HARD_FLOAT && TARGET_MULADD"
+  "fmadds %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fmas")])
+
+(define_insn "*mulsubsf4"
+  [(set (match_operand:SF 0 "fpr_operand" "=f")
+       (minus:SF (mult:SF (match_operand:SF 1 "fpr_operand" "%f")
+                          (match_operand:SF 2 "fpr_operand" "f"))
+                 (match_operand:SF 3 "fpr_operand" "0")))]
+  "TARGET_HARD_FLOAT && TARGET_MULADD"
+  "fmsubs %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fmas")])
+
+;; Division
+(define_insn "divsf3"
+  [(set (match_operand:SF 0 "fpr_operand" "=f")
+       (div:SF (match_operand:SF 1 "fpr_operand" "f")
+               (match_operand:SF 2 "fpr_operand" "f")))]
+  "TARGET_HARD_FLOAT"
+  "fdivs %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsdiv")])
+
+;; Negation
+(define_insn "negsf2"
+  [(set (match_operand:SF 0 "fpr_operand" "=f")
+       (neg:SF (match_operand:SF 1 "fpr_operand" "f")))]
+  "TARGET_HARD_FLOAT"
+  "fnegs %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsconv")])
+
+;; Absolute value
+(define_insn "abssf2"
+  [(set (match_operand:SF 0 "fpr_operand" "=f")
+       (abs:SF (match_operand:SF 1 "fpr_operand" "f")))]
+  "TARGET_HARD_FLOAT"
+  "fabss %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsconv")])
+
+;; Square root
+(define_insn "sqrtsf2"
+  [(set (match_operand:SF 0 "fpr_operand" "=f")
+       (sqrt:SF (match_operand:SF 1 "fpr_operand" "f")))]
+  "TARGET_HARD_FLOAT"
+  "fsqrts %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "sqrt_single")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: 64 bit floating point arithmetic
+;; ::
+;; ::::::::::::::::::::
+
+;; Addition
+(define_insn "adddf3"
+  [(set (match_operand:DF 0 "even_fpr_operand" "=h")
+       (plus:DF (match_operand:DF 1 "fpr_operand" "%h")
+                (match_operand:DF 2 "fpr_operand" "h")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "faddd %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fdadd")])
+
+;; Subtraction
+(define_insn "subdf3"
+  [(set (match_operand:DF 0 "even_fpr_operand" "=h")
+       (minus:DF (match_operand:DF 1 "fpr_operand" "h")
+                 (match_operand:DF 2 "fpr_operand" "h")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "fsubd %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fdadd")])
+
+;; Multiplication
+(define_insn "muldf3"
+  [(set (match_operand:DF 0 "even_fpr_operand" "=h")
+       (mult:DF (match_operand:DF 1 "fpr_operand" "%h")
+                (match_operand:DF 2 "fpr_operand" "h")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "fmuld %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fdmul")])
+
+;; Multiplication with addition/subtraction
+(define_insn "*muladddf4"
+  [(set (match_operand:DF 0 "fpr_operand" "=f")
+       (plus:DF (mult:DF (match_operand:DF 1 "fpr_operand" "%f")
+                         (match_operand:DF 2 "fpr_operand" "f"))
+                (match_operand:DF 3 "fpr_operand" "0")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE && TARGET_MULADD"
+  "fmaddd %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fmas")])
+
+(define_insn "*mulsubdf4"
+  [(set (match_operand:DF 0 "fpr_operand" "=f")
+       (minus:DF (mult:DF (match_operand:DF 1 "fpr_operand" "%f")
+                          (match_operand:DF 2 "fpr_operand" "f"))
+                 (match_operand:DF 3 "fpr_operand" "0")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE && TARGET_MULADD"
+  "fmsubd %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fmas")])
+
+;; Division
+(define_insn "divdf3"
+  [(set (match_operand:DF 0 "even_fpr_operand" "=h")
+       (div:DF (match_operand:DF 1 "fpr_operand" "h")
+               (match_operand:DF 2 "fpr_operand" "h")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "fdivd %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fddiv")])
+
+;; Negation
+(define_insn "negdf2"
+  [(set (match_operand:DF 0 "even_fpr_operand" "=h")
+       (neg:DF (match_operand:DF 1 "fpr_operand" "h")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "fnegd %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fdconv")])
+
+;; Absolute value
+(define_insn "absdf2"
+  [(set (match_operand:DF 0 "even_fpr_operand" "=h")
+       (abs:DF (match_operand:DF 1 "fpr_operand" "h")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "fabsd %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fdconv")])
+
+;; Square root
+(define_insn "sqrtdf2"
+  [(set (match_operand:DF 0 "even_fpr_operand" "=h")
+       (sqrt:DF (match_operand:DF 1 "fpr_operand" "h")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "fsqrtd %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "sqrt_double")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: 32 bit Integer Shifts and Rotates
+;; ::
+;; ::::::::::::::::::::
+
+;; Arithmetic Shift Left
+(define_insn "ashlsi3"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d")
+       (ashift:SI (match_operand:SI 1 "integer_register_operand" "d,d")
+                  (match_operand:SI 2 "gpr_or_int12_operand" "d,NOP")))]
+  ""
+  "sll%I2 %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+;; Arithmetic Shift Right
+(define_insn "ashrsi3"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d")
+       (ashiftrt:SI (match_operand:SI 1 "integer_register_operand" "d,d")
+                    (match_operand:SI 2 "gpr_or_int12_operand" "d,NOP")))]
+  ""
+  "sra%I2 %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+;; Logical Shift Right
+(define_insn "lshrsi3"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d")
+       (lshiftrt:SI (match_operand:SI 1 "integer_register_operand" "d,d")
+                    (match_operand:SI 2 "gpr_or_int12_operand" "d,NOP")))]
+  ""
+  "srl%I2 %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+;; Rotate Left
+;; (define_insn "rotlsi3"
+;;   [(set (match_operand:SI 0 "register_operand" "=r")
+;;     (rotate:SI (match_operand:SI 1 "register_operand" "r")
+;;                (match_operand:SI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "rotlsi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+;; Rotate Right
+;; (define_insn "rotrsi3"
+;;   [(set (match_operand:SI 0 "register_operand" "=r")
+;;     (rotatert:SI (match_operand:SI 1 "register_operand" "r")
+;;                  (match_operand:SI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "rotrsi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: 64 bit Integer Shifts and Rotates
+;; ::
+;; ::::::::::::::::::::
+
+;; Arithmetic Shift Left
+;; (define_insn "ashldi3"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (ashift:DI (match_operand:DI 1 "register_operand" "r")
+;;                (match_operand:SI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "ashldi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+;; Arithmetic Shift Right
+;; (define_insn "ashrdi3"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (ashiftrt:DI (match_operand:DI 1 "register_operand" "r")
+;;                  (match_operand:SI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "ashrdi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+;; Logical Shift Right
+;; (define_insn "lshrdi3"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (lshiftrt:DI (match_operand:DI 1 "register_operand" "r")
+;;                  (match_operand:SI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "lshrdi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+;; Rotate Left
+;; (define_insn "rotldi3"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (rotate:DI (match_operand:DI 1 "register_operand" "r")
+;;                (match_operand:SI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "rotldi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+;; Rotate Right
+;; (define_insn "rotrdi3"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (rotatert:DI (match_operand:DI 1 "register_operand" "r")
+;;                  (match_operand:SI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "rotrdi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: 32 Bit Integer Logical operations
+;; ::
+;; ::::::::::::::::::::
+
+;; Logical AND, 32 bit integers
+(define_insn "andsi3_media"
+  [(set (match_operand:SI 0 "gpr_or_fpr_operand" "=d,f")
+       (and:SI (match_operand:SI 1 "gpr_or_fpr_operand" "%d,f")
+               (match_operand:SI 2 "gpr_fpr_or_int12_operand" "dNOP,f")))]
+  "TARGET_MEDIA"
+  "@
+   and%I2 %1, %2, %0
+   mand %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,mlogic")])
+
+(define_insn "andsi3_nomedia"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (and:SI (match_operand:SI 1 "integer_register_operand" "%d")
+               (match_operand:SI 2 "gpr_or_int12_operand" "dNOP")))]
+  "!TARGET_MEDIA"
+  "and%I2 %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_expand "andsi3"
+  [(set (match_operand:SI 0 "gpr_or_fpr_operand" "")
+       (and:SI (match_operand:SI 1 "gpr_or_fpr_operand" "")
+               (match_operand:SI 2 "gpr_fpr_or_int12_operand" "")))]
+  ""
+  "")
+
+;; Inclusive OR, 32 bit integers
+(define_insn "iorsi3_media"
+  [(set (match_operand:SI 0 "gpr_or_fpr_operand" "=d,f")
+       (ior:SI (match_operand:SI 1 "gpr_or_fpr_operand" "%d,f")
+               (match_operand:SI 2 "gpr_fpr_or_int12_operand" "dNOP,f")))]
+  "TARGET_MEDIA"
+  "@
+   or%I2 %1, %2, %0
+   mor %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,mlogic")])
+
+(define_insn "iorsi3_nomedia"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (ior:SI (match_operand:SI 1 "integer_register_operand" "%d")
+               (match_operand:SI 2 "gpr_or_int12_operand" "dNOP")))]
+  "!TARGET_MEDIA"
+  "or%I2 %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_expand "iorsi3"
+  [(set (match_operand:SI 0 "gpr_or_fpr_operand" "")
+       (ior:SI (match_operand:SI 1 "gpr_or_fpr_operand" "")
+               (match_operand:SI 2 "gpr_fpr_or_int12_operand" "")))]
+  ""
+  "")
+
+;; Exclusive OR, 32 bit integers
+(define_insn "xorsi3_media"
+  [(set (match_operand:SI 0 "gpr_or_fpr_operand" "=d,f")
+       (xor:SI (match_operand:SI 1 "gpr_or_fpr_operand" "%d,f")
+               (match_operand:SI 2 "gpr_fpr_or_int12_operand" "dNOP,f")))]
+  "TARGET_MEDIA"
+  "@
+   xor%I2 %1, %2, %0
+   mxor %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,mlogic")])
+
+(define_insn "xorsi3_nomedia"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (xor:SI (match_operand:SI 1 "integer_register_operand" "%d")
+               (match_operand:SI 2 "gpr_or_int12_operand" "dNOP")))]
+  "!TARGET_MEDIA"
+  "xor%I2 %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_expand "xorsi3"
+  [(set (match_operand:SI 0 "gpr_or_fpr_operand" "")
+       (xor:SI (match_operand:SI 1 "gpr_or_fpr_operand" "")
+               (match_operand:SI 2 "gpr_fpr_or_int12_operand" "")))]
+  ""
+  "")
+
+;; One's complement, 32 bit integers
+(define_insn "one_cmplsi2_media"
+  [(set (match_operand:SI 0 "gpr_or_fpr_operand" "=d,f")
+       (not:SI (match_operand:SI 1 "gpr_or_fpr_operand" "d,f")))]
+  "TARGET_MEDIA"
+  "@
+   not %1, %0
+   mnot %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,mlogic")])
+
+(define_insn "one_cmplsi2_nomedia"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (not:SI (match_operand:SI 1 "integer_register_operand" "d")))]
+  "!TARGET_MEDIA"
+  "not %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_expand "one_cmplsi2"
+  [(set (match_operand:SI 0 "gpr_or_fpr_operand" "")
+       (not:SI (match_operand:SI 1 "gpr_or_fpr_operand" "")))]
+  ""
+  "")
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: 64 Bit Integer Logical operations
+;; ::
+;; ::::::::::::::::::::
+
+;; Logical AND, 64 bit integers
+;; (define_insn "anddi3"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (and:DI (match_operand:DI 1 "register_operand" "%r")
+;;             (match_operand:DI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "anddi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+;; Includive OR, 64 bit integers
+;; (define_insn "iordi3"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (ior:DI (match_operand:DI 1 "register_operand" "%r")
+;;             (match_operand:DI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "iordi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+;; Excludive OR, 64 bit integers
+;; (define_insn "xordi3"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (xor:DI (match_operand:DI 1 "register_operand" "%r")
+;;             (match_operand:DI 2 "nonmemory_operand" "ri")))]
+;;   ""
+;;   "xordi3 %0,%1,%2"
+;;   [(set_attr "length" "4")])
+
+;; One's complement, 64 bit integers
+;; (define_insn "one_cmpldi2"
+;;   [(set (match_operand:DI 0 "register_operand" "=r")
+;;     (not:DI (match_operand:DI 1 "register_operand" "r")))]
+;;   ""
+;;   "notdi3 %0,%1"
+;;   [(set_attr "length" "4")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Combination of integer operation with comparison
+;; ::
+;; ::::::::::::::::::::
+
+(define_insn "*combo_intop_compare1"
+  [(set (match_operand:CC 0 "icc_operand" "=t")
+       (compare:CC (match_operator:SI 1 "intop_compare_operator"
+                                      [(match_operand:SI 2 "integer_register_operand" "d")
+                                       (match_operand:SI 3 "gpr_or_int10_operand" "dJ")])
+                   (const_int 0)))]
+  ""
+  "%O1%I3cc %2, %3, %., %0"
+  [(set_attr "type" "int")
+   (set_attr "length" "4")])
+
+(define_insn "*combo_intop_compare2"
+  [(set (match_operand:CC_UNS 0 "icc_operand" "=t")
+       (compare:CC_UNS (match_operator:SI 1 "intop_compare_operator"
+                                          [(match_operand:SI 2 "integer_register_operand" "d")
+                                           (match_operand:SI 3 "gpr_or_int10_operand" "dJ")])
+                       (const_int 0)))]
+  ""
+  "%O1%I3cc %2, %3, %., %0"
+  [(set_attr "type" "int")
+   (set_attr "length" "4")])
+
+(define_insn "*combo_intop_compare3"
+  [(set (match_operand:CC 0 "icc_operand" "=t")
+       (compare:CC (match_operator:SI 1 "intop_compare_operator"
+                                      [(match_operand:SI 2 "integer_register_operand" "d")
+                                       (match_operand:SI 3 "gpr_or_int10_operand" "dJ")])
+                   (const_int 0)))
+   (set (match_operand:SI 4 "integer_register_operand" "=d")
+       (match_operator:SI 5 "intop_compare_operator"
+                          [(match_dup 2)
+                           (match_dup 3)]))]
+  "GET_CODE (operands[1]) == GET_CODE (operands[5])"
+  "%O1%I3cc %2, %3, %4, %0"
+  [(set_attr "type" "int")
+   (set_attr "length" "4")])
+
+(define_insn "*combo_intop_compare4"
+  [(set (match_operand:CC_UNS 0 "icc_operand" "=t")
+       (compare:CC_UNS (match_operator:SI 1 "intop_compare_operator"
+                                          [(match_operand:SI 2 "integer_register_operand" "d")
+                                           (match_operand:SI 3 "gpr_or_int10_operand" "dJ")])
+                   (const_int 0)))
+   (set (match_operand:SI 4 "integer_register_operand" "=d")
+       (match_operator:SI 5 "intop_compare_operator"
+                          [(match_dup 2)
+                           (match_dup 3)]))]
+  "GET_CODE (operands[1]) == GET_CODE (operands[5])"
+  "%O1%I3cc %2, %3, %4, %0"
+  [(set_attr "type" "int")
+   (set_attr "length" "4")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Comparisons
+;; ::
+;; ::::::::::::::::::::
+
+;; Note, we store the operands in the comparison insns, and use them later
+;; when generating the branch or scc operation.
+
+;; First the routines called by the machine independent part of the compiler
+(define_expand "cmpsi"
+  [(set (cc0)
+        (compare (match_operand:SI 0 "integer_register_operand" "")
+                (match_operand:SI 1 "gpr_or_int10_operand" "")))]
+  ""
+  "
+{
+  frv_compare_op0 = operands[0];
+  frv_compare_op1 = operands[1];
+  DONE;
+}")
+
+;(define_expand "cmpdi"
+;  [(set (cc0)
+;        (compare (match_operand:DI 0 "register_operand" "")
+;               (match_operand:DI 1 "nonmemory_operand" "")))]
+;  ""
+;  "
+;{
+;  frv_compare_op0 = operands[0];
+;  frv_compare_op1 = operands[1];
+;  DONE;
+;}")
+
+(define_expand "cmpsf"
+ [(set (cc0)
+       (compare (match_operand:SF 0 "fpr_operand" "")
+                (match_operand:SF 1 "fpr_operand" "")))]
+ "TARGET_HARD_FLOAT"
+ "
+{
+  frv_compare_op0 = operands[0];
+  frv_compare_op1 = operands[1];
+  DONE;
+}")
+
+(define_expand "cmpdf"
+  [(set (cc0)
+        (compare (match_operand:DF 0 "fpr_operand" "")
+                (match_operand:DF 1 "fpr_operand" "")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "
+{
+  frv_compare_op0 = operands[0];
+  frv_compare_op1 = operands[1];
+  DONE;
+}")
+
+;; Now, the actual comparisons, generated by the branch and/or scc operations
+
+(define_insn "cmpsi_cc"
+  [(set (match_operand:CC 0 "icc_operand" "=t,t")
+       (compare:CC (match_operand:SI 1 "integer_register_operand" "d,d")
+                   (match_operand:SI 2 "gpr_or_int10_operand" "d,J")))]
+  ""
+  "cmp%I2 %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_insn "*cmpsi_cc_uns"
+  [(set (match_operand:CC_UNS 0 "icc_operand" "=t,t")
+       (compare:CC_UNS (match_operand:SI 1 "integer_register_operand" "d,d")
+                       (match_operand:SI 2 "gpr_or_int10_operand" "d,J")))]
+  ""
+  "cmp%I2 %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_insn "*cmpsf_cc_fp"
+  [(set (match_operand:CC_FP 0 "fcc_operand" "=u")
+       (compare:CC_FP (match_operand:SF 1 "fpr_operand" "f")
+                      (match_operand:SF 2 "fpr_operand" "f")))]
+  "TARGET_HARD_FLOAT"
+  "fcmps %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsadd")])
+
+(define_insn "*cmpdf_cc_fp"
+  [(set (match_operand:CC_FP 0 "fcc_operand" "=u")
+       (compare:CC_FP (match_operand:DF 1 "even_fpr_operand" "h")
+                      (match_operand:DF 2 "even_fpr_operand" "h")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "fcmpd %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fdadd")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Branches
+;; ::
+;; ::::::::::::::::::::
+
+;; Define_expands called by the machine independent part of the compiler
+;; to allocate a new comparison register.  Each of these named patterns
+;; must be present, and they cannot be amalgamated into one pattern.
+;;
+;; If a fixed condition code register is being used, (as opposed to, say,
+;; using cc0), then the expands should look like this:
+;;
+;; (define_expand "<name_of_test>"
+;;   [(set (reg:CC <number_of_CC_register>)
+;;     (compare:CC (match_dup 1)
+;;                 (match_dup 2)))
+;;    (set (pc)
+;;     (if_then_else (eq:CC (reg:CC <number_of_CC_register>)
+;;                          (const_int 0))
+;;                   (label_ref (match_operand 0 "" ""))
+;;                   (pc)))]
+;;   ""
+;;   "{
+;;     operands[1] = frv_compare_op0;
+;;     operands[2] = frv_compare_op1;
+;;   }"
+;; )
+
+(define_expand "beq"
+  [(use (match_operand 0 "" ""))]
+  ""
+  "
+{
+  if (! frv_emit_cond_branch (EQ, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "bne"
+  [(use (match_operand 0 "" ""))]
+  ""
+  "
+{
+  if (! frv_emit_cond_branch (NE, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "blt"
+  [(use (match_operand 0 "" ""))]
+  ""
+  "
+{
+  if (! frv_emit_cond_branch (LT, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "ble"
+  [(use (match_operand 0 "" ""))]
+  ""
+  "
+{
+  if (! frv_emit_cond_branch (LE, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "bgt"
+  [(use (match_operand 0 "" ""))]
+  ""
+  "
+{
+  if (! frv_emit_cond_branch (GT, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "bge"
+  [(use (match_operand 0 "" ""))]
+  ""
+  "
+{
+  if (! frv_emit_cond_branch (GE, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "bltu"
+  [(use (match_operand 0 "" ""))]
+  ""
+  "
+{
+  if (! frv_emit_cond_branch (LTU, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "bleu"
+  [(use (match_operand 0 "" ""))]
+  ""
+  "
+{
+  if (! frv_emit_cond_branch (LEU, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "bgtu"
+  [(use (match_operand 0 "" ""))]
+  ""
+  "
+{
+  if (! frv_emit_cond_branch (GTU, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "bgeu"
+  [(use (match_operand 0 "" ""))]
+  ""
+  "
+{
+  if (! frv_emit_cond_branch (GEU, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+;; Actual branches.  We must allow for the (label_ref) and the (pc) to be
+;; swapped.  If they are swapped, it reverses the sense of the branch.
+;;
+;; Note - unlike the define expands above, these patterns can be amalgamated
+;; into one pattern for branch-if-true and one for branch-if-false.  This does
+;; require an operand operator to select the correct branch mnemonic.
+;;
+;; If a fixed condition code register is being used, (as opposed to, say,
+;; using cc0), then the expands could look like this:
+;;
+;; (define_insn "*branch_true"
+;;   [(set (pc)
+;;     (if_then_else (match_operator:CC 0 "comparison_operator"
+;;                                      [(reg:CC <number_of_CC_register>)
+;;                                       (const_int 0)])
+;;                   (label_ref (match_operand 1 "" ""))
+;;                   (pc)))]
+;;   ""
+;;   "b%B0 %1"
+;;   [(set_attr "length" "4")]
+;; )
+;;
+;; In the above example the %B is a directive to frv_print_operand()
+;; to decode and print the correct branch mnemonic.
+
+(define_insn "*branch_signed_true"
+  [(set (pc)
+       (if_then_else (match_operator:CC 0 "signed_relational_operator"
+                                        [(match_operand 1 "icc_operand" "t")
+                                         (const_int 0)])
+                     (label_ref (match_operand 2 "" ""))
+                     (pc)))]
+  ""
+  "*
+{
+  if (get_attr_length (insn) == 4)
+    return \"b%c0 %1,%#,%l2\";
+  else
+    return \"b%C0 %1,%#,1f\;call %l2\\n1:\";
+}"
+  [(set (attr "length")
+       (if_then_else
+           (and (ge (minus (match_dup 2) (pc)) (const_int -32768))
+                (le (minus (match_dup 2) (pc)) (const_int 32764)))
+           (const_int 4)
+           (const_int 8)))
+   (set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "4")
+           (const_string "no")
+           (const_string "yes")))
+   (set (attr "type")
+       (if_then_else
+           (eq_attr "length" "4")
+           (const_string "branch")
+           (const_string "multi")))])
+
+(define_insn "*branch_signed_false"
+  [(set (pc)
+       (if_then_else (match_operator:CC 0 "signed_relational_operator"
+                                        [(match_operand 1 "icc_operand" "t")
+                                         (const_int 0)])
+                     (pc)
+                     (label_ref (match_operand 2 "" ""))))]
+  ""
+  "*
+{
+  if (get_attr_length (insn) == 4)
+    return \"b%C0 %1,%#,%l2\";
+  else
+    return \"b%c0 %1,%#,1f\;call %l2\\n1:\";
+}"
+  [(set (attr "length")
+       (if_then_else
+           (and (ge (minus (match_dup 2) (pc)) (const_int -32768))
+                (le (minus (match_dup 2) (pc)) (const_int 32764)))
+           (const_int 4)
+           (const_int 8)))
+   (set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "4")
+           (const_string "no")
+           (const_string "yes")))
+   (set (attr "type")
+       (if_then_else
+           (eq_attr "length" "4")
+           (const_string "branch")
+           (const_string "multi")))])
+
+(define_insn "*branch_unsigned_true"
+  [(set (pc)
+       (if_then_else (match_operator:CC_UNS 0 "unsigned_relational_operator"
+                                            [(match_operand 1 "icc_operand" "t")
+                                             (const_int 0)])
+                     (label_ref (match_operand 2 "" ""))
+                     (pc)))]
+  ""
+  "*
+{
+  if (get_attr_length (insn) == 4)
+    return \"b%c0 %1,%#,%l2\";
+  else
+    return \"b%C0 %1,%#,1f\;call %l2\\n1:\";
+}"
+  [(set (attr "length")
+       (if_then_else
+           (and (ge (minus (match_dup 2) (pc)) (const_int -32768))
+                (le (minus (match_dup 2) (pc)) (const_int 32764)))
+           (const_int 4)
+           (const_int 8)))
+   (set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "4")
+           (const_string "no")
+           (const_string "yes")))
+   (set (attr "type")
+       (if_then_else
+           (eq_attr "length" "4")
+           (const_string "branch")
+           (const_string "multi")))])
+
+(define_insn "*branch_unsigned_false"
+  [(set (pc)
+       (if_then_else (match_operator:CC_UNS 0 "unsigned_relational_operator"
+                                            [(match_operand 1 "icc_operand" "t")
+                                             (const_int 0)])
+                     (pc)
+                     (label_ref (match_operand 2 "" ""))))]
+  ""
+  "*
+{
+  if (get_attr_length (insn) == 4)
+    return \"b%C0 %1,%#,%l2\";
+  else
+    return \"b%c0 %1,%#,1f\;call %l2\\n1:\";
+}"
+  [(set (attr "length")
+       (if_then_else
+           (and (ge (minus (match_dup 2) (pc)) (const_int -32768))
+                (le (minus (match_dup 2) (pc)) (const_int 32764)))
+           (const_int 4)
+           (const_int 8)))
+   (set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "4")
+           (const_string "no")
+           (const_string "yes")))
+   (set (attr "type")
+       (if_then_else
+           (eq_attr "length" "4")
+           (const_string "branch")
+           (const_string "multi")))])
+
+(define_insn "*branch_fp_true"
+  [(set (pc)
+       (if_then_else (match_operator:CC_FP 0 "float_relational_operator"
+                                           [(match_operand 1 "fcc_operand" "u")
+                                            (const_int 0)])
+                     (label_ref (match_operand 2 "" ""))
+                     (pc)))]
+  ""
+  "*
+{
+  if (get_attr_length (insn) == 4)
+    return \"fb%f0 %1,%#,%l2\";
+  else
+    return \"fb%F0 %1,%#,1f\;call %l2\\n1:\";
+}"
+  [(set (attr "length")
+       (if_then_else
+           (and (ge (minus (match_dup 2) (pc)) (const_int -32768))
+                (le (minus (match_dup 2) (pc)) (const_int 32764)))
+           (const_int 4)
+           (const_int 8)))
+   (set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "4")
+           (const_string "no")
+           (const_string "yes")))
+   (set (attr "type")
+       (if_then_else
+           (eq_attr "length" "4")
+           (const_string "branch")
+           (const_string "multi")))])
+
+(define_insn "*branch_fp_false"
+  [(set (pc)
+       (if_then_else (match_operator:CC_FP 0 "float_relational_operator"
+                                           [(match_operand 1 "fcc_operand" "u")
+                                            (const_int 0)])
+                     (pc)
+                     (label_ref (match_operand 2 "" ""))))]
+  ""
+  "*
+{
+  if (get_attr_length (insn) == 4)
+    return \"fb%F0 %1,%#,%l2\";
+  else
+    return \"fb%f0 %1,%#,1f\;call %l2\\n1:\";
+}"
+  [(set (attr "length")
+       (if_then_else
+           (and (ge (minus (match_dup 2) (pc)) (const_int -32768))
+                (le (minus (match_dup 2) (pc)) (const_int 32764)))
+           (const_int 4)
+           (const_int 8)))
+   (set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "4")
+           (const_string "no")
+           (const_string "yes")))
+   (set (attr "type")
+       (if_then_else
+           (eq_attr "length" "4")
+           (const_string "branch")
+           (const_string "multi")))])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Set flag operations
+;; ::
+;; ::::::::::::::::::::
+
+;; Define_expands called by the machine independent part of the compiler
+;; to allocate a new comparison register
+
+(define_expand "seq"
+  [(match_operand:SI 0 "integer_register_operand" "")]
+  "TARGET_SCC"
+  "
+{
+  if (! frv_emit_scc (EQ, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "sne"
+  [(match_operand:SI 0 "integer_register_operand" "")]
+  "TARGET_SCC"
+  "
+{
+  if (! frv_emit_scc (NE, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "slt"
+  [(match_operand:SI 0 "integer_register_operand" "")]
+  "TARGET_SCC"
+  "
+{
+  if (! frv_emit_scc (LT, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "sle"
+  [(match_operand:SI 0 "integer_register_operand" "")]
+  "TARGET_SCC"
+  "
+{
+  if (! frv_emit_scc (LE, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "sgt"
+  [(match_operand:SI 0 "integer_register_operand" "")]
+  "TARGET_SCC"
+  "
+{
+  if (! frv_emit_scc (GT, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "sge"
+  [(match_operand:SI 0 "integer_register_operand" "")]
+  "TARGET_SCC"
+  "
+{
+  if (! frv_emit_scc (GE, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "sltu"
+  [(match_operand:SI 0 "integer_register_operand" "")]
+  "TARGET_SCC"
+  "
+{
+  if (! frv_emit_scc (LTU, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "sleu"
+  [(match_operand:SI 0 "integer_register_operand" "")]
+  "TARGET_SCC"
+  "
+{
+  if (! frv_emit_scc (LEU, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "sgtu"
+  [(match_operand:SI 0 "integer_register_operand" "")]
+  "TARGET_SCC"
+  "
+{
+  if (! frv_emit_scc (GTU, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_expand "sgeu"
+  [(match_operand:SI 0 "integer_register_operand" "")]
+  "TARGET_SCC"
+  "
+{
+  if (! frv_emit_scc (GEU, operands[0]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_insn "*scc_signed"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (match_operator:SI 1 "signed_relational_operator"
+                          [(match_operand:CC 2 "icc_operand" "t")
+                           (const_int 0)]))
+   (clobber (match_operand:CC_CCR 3 "icr_operand" "=v"))]
+  ""
+  "#"
+  [(set_attr "length" "12")
+   (set_attr "type" "multi")])
+
+(define_insn "*scc_unsigned"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (match_operator:SI 1 "unsigned_relational_operator"
+                          [(match_operand:CC_UNS 2 "icc_operand" "t")
+                           (const_int 0)]))
+   (clobber (match_operand:CC_CCR 3 "icr_operand" "=v"))]
+  ""
+  "#"
+  [(set_attr "length" "12")
+   (set_attr "type" "multi")])
+
+(define_insn "*scc_float"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (match_operator:SI 1 "float_relational_operator"
+                          [(match_operand:CC_FP 2 "fcc_operand" "u")
+                           (const_int 0)]))
+   (clobber (match_operand:CC_CCR 3 "fcr_operand" "=w"))]
+  ""
+  "#"
+  [(set_attr "length" "12")
+   (set_attr "type" "multi")])
+
+;; XXX -- add reload_completed to the splits, because register allocation
+;; currently isn't ready to see cond_exec packets.
+(define_split
+  [(set (match_operand:SI 0 "integer_register_operand" "")
+       (match_operator:SI 1 "relational_operator"
+                          [(match_operand 2 "cc_operand" "")
+                           (const_int 0)]))
+   (clobber (match_operand 3 "cr_operand" ""))]
+  "reload_completed"
+  [(match_dup 4)]
+  "operands[4] = frv_split_scc (operands[0], operands[1], operands[2],
+                               operands[3], (HOST_WIDE_INT) 1);")
+
+(define_insn "*scc_neg1_signed"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (neg:SI (match_operator:SI 1 "signed_relational_operator"
+                                  [(match_operand:CC 2 "icc_operand" "t")
+                                   (const_int 0)])))
+   (clobber (match_operand:CC_CCR 3 "icr_operand" "=v"))]
+  ""
+  "#"
+  [(set_attr "length" "12")
+   (set_attr "type" "multi")])
+
+(define_insn "*scc_neg1_unsigned"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (neg:SI (match_operator:SI 1 "unsigned_relational_operator"
+                                  [(match_operand:CC_UNS 2 "icc_operand" "t")
+                                   (const_int 0)])))
+   (clobber (match_operand:CC_CCR 3 "icr_operand" "=v"))]
+  ""
+  "#"
+  [(set_attr "length" "12")
+   (set_attr "type" "multi")])
+
+(define_insn "*scc_neg1_float"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+       (neg:SI (match_operator:SI 1 "float_relational_operator"
+                                  [(match_operand:CC_FP 2 "fcc_operand" "u")
+                                   (const_int 0)])))
+   (clobber (match_operand:CC_CCR 3 "fcr_operand" "=w"))]
+  ""
+  "#"
+  [(set_attr "length" "12")
+   (set_attr "type" "multi")])
+
+(define_split
+  [(set (match_operand:SI 0 "integer_register_operand" "")
+       (neg:SI (match_operator:SI 1 "relational_operator"
+                                  [(match_operand 2 "cc_operand" "")
+                                   (const_int 0)])))
+   (clobber (match_operand 3 "cr_operand" ""))]
+  "reload_completed"
+  [(match_dup 4)]
+  "operands[4] = frv_split_scc (operands[0], operands[1], operands[2],
+                               operands[3], (HOST_WIDE_INT) -1);")
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Conditionally executed instructions
+;; ::
+;; ::::::::::::::::::::
+
+;; Convert ICC/FCC comparison into CCR bits so we can do conditional execution
+(define_insn "*ck_signed"
+  [(set (match_operand:CC_CCR 0 "icr_operand" "=v")
+       (match_operator:CC_CCR 1 "signed_relational_operator"
+                              [(match_operand:CC 2 "icc_operand" "t")
+                               (const_int 0)]))]
+  ""
+  "ck%c1 %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "ccr")])
+
+(define_insn "*ck_unsigned"
+  [(set (match_operand:CC_CCR 0 "icr_operand" "=v")
+       (match_operator:CC_CCR 1 "unsigned_relational_operator"
+                              [(match_operand:CC_UNS 2 "icc_operand" "t")
+                               (const_int 0)]))]
+  ""
+  "ck%c1 %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "ccr")])
+
+(define_insn "*fck_float"
+  [(set (match_operand:CC_CCR 0 "fcr_operand" "=w")
+       (match_operator:CC_CCR 1 "float_relational_operator"
+                              [(match_operand:CC_FP 2 "fcc_operand" "u")
+                               (const_int 0)]))]
+  "TARGET_HAS_FPRS"
+  "fck%c1 %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "ccr")])
+
+;; Conditionally convert ICC/FCC comparison into CCR bits to provide && and ||
+;; tests in conditional execution
+(define_insn "cond_exec_ck"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "=v,w")
+       (if_then_else:CC_CCR (match_operator 1 "ccr_eqne_operator"
+                                            [(match_operand 2 "cr_operand" "C,C")
+                                             (const_int 0)])
+                            (match_operator 3 "relational_operator"
+                                            [(match_operand 4 "cc_operand" "t,u")
+                                             (const_int 0)])
+                            (const_int 0)))]
+  ""
+  "@
+   cck%c3 %4, %0, %2, %e1
+   cfck%f3 %4, %0, %2, %e1"
+  [(set_attr "length" "4")
+   (set_attr "type" "ccr")])
+
+;; Conditionally set a register to either 0 or another register
+(define_insn "*cond_exec_movqi"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C,C,C,C,C,C")
+                    (const_int 0)])
+    (set (match_operand:QI 2 "condexec_dest_operand" "=d,d,U,?f,?f,?d")
+        (match_operand:QI 3 "condexec_source_operand" "dO,U,dO,f,d,f")))]
+  "register_operand(operands[2], QImode) || reg_or_0_operand (operands[3], QImode)"
+  "* return output_condmove_single (operands, insn);"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,gload,gstore,fsconv,movgf,movfg")])
+
+(define_insn "*cond_exec_movhi"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C,C,C,C,C,C")
+                    (const_int 0)])
+    (set (match_operand:HI 2 "condexec_dest_operand" "=d,d,U,?f,?f,?d")
+        (match_operand:HI 3 "condexec_source_operand" "dO,U,dO,f,d,f")))]
+  "register_operand(operands[2], HImode) || reg_or_0_operand (operands[3], HImode)"
+  "* return output_condmove_single (operands, insn);"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,gload,gstore,fsconv,movgf,movfg")])
+
+(define_insn "*cond_exec_movsi"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C,C,C,C,C,C,C,C")
+                    (const_int 0)])
+    (set (match_operand:SI 2 "condexec_dest_operand" "=d,d,U,?f,?f,?d,?f,?m")
+        (match_operand:SI 3 "condexec_source_operand" "dO,U,dO,f,d,f,m,f")))]
+  "register_operand(operands[2], SImode) || reg_or_0_operand (operands[3], SImode)"
+  "* return output_condmove_single (operands, insn);"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,gload,gstore,fsconv,movgf,movfg,fload,fstore")])
+
+
+(define_insn "*cond_exec_movsf_has_fprs"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C,C,C,C,C,C,C,C,C,C")
+                    (const_int 0)])
+    (set (match_operand:SF 2 "condexec_dest_operand" "=f,?d,?d,?f,f,f,?d,U,?U,U")
+        (match_operand:SF 3 "condexec_source_operand" "f,d,f,d,G,U,U,f,d,G")))]
+  "TARGET_HAS_FPRS"
+  "* return output_condmove_single (operands, insn);"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsconv,int,movgf,movfg,movgf,fload,gload,fstore,gstore,gstore")])
+
+(define_insn "*cond_exec_movsf_no_fprs"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C,C,C")
+                    (const_int 0)])
+    (set (match_operand:SF 2 "condexec_dest_operand" "=d,d,U")
+        (match_operand:SF 3 "condexec_source_operand" "d,U,dG")))]
+  "! TARGET_HAS_FPRS"
+  "* return output_condmove_single (operands, insn);"
+  [(set_attr "length" "4")
+   (set_attr "type" "int,gload,gstore")])
+
+(define_insn "*cond_exec_si_binary1"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SI 2 "integer_register_operand" "=d")
+        (match_operator:SI 3 "condexec_si_binary_operator"
+                           [(match_operand:SI 4 "integer_register_operand" "d")
+                            (match_operand:SI 5 "integer_register_operand" "d")])))]
+  ""
+  "*
+{
+  switch (GET_CODE (operands[3]))
+    {
+      case PLUS:     return \"cadd %4, %z5, %2, %1, %e0\";
+      case MINUS:    return \"csub %4, %z5, %2, %1, %e0\";
+      case AND:      return \"cand %4, %z5, %2, %1, %e0\";
+      case IOR:      return \"cor %4, %z5, %2, %1, %e0\";
+      case XOR:      return \"cxor %4, %z5, %2, %1, %e0\";
+      case ASHIFT:   return \"csll %4, %z5, %2, %1, %e0\";
+      case ASHIFTRT: return \"csra %4, %z5, %2, %1, %e0\";
+      case LSHIFTRT: return \"csrl %4, %z5, %2, %1, %e0\";
+      default:       abort ();
+    }
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_insn "*cond_exec_si_binary2"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SI 2 "fpr_operand" "=f")
+        (match_operator:SI 3 "condexec_si_media_operator"
+                           [(match_operand:SI 4 "fpr_operand" "f")
+                            (match_operand:SI 5 "fpr_operand" "f")])))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (GET_CODE (operands[3]))
+    {
+      case AND: return \"cmand %4, %5, %2, %1, %e0\";
+      case IOR: return \"cmor %4, %5, %2, %1, %e0\";
+      case XOR: return \"cmxor %4, %5, %2, %1, %e0\";
+      default:  abort ();
+    }
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mlogic")])
+
+;; Note, flow does not (currently) know how to handle an operation that uses
+;; only part of the hard registers allocated for a multiregister value, such as
+;; DImode in this case if the user is only interested in the lower 32-bits.  So
+;; we emit a USE of the entire register after the csmul instruction so it won't
+;; get confused.  See frv_ifcvt_modify_insn for more details.
+
+(define_insn "*cond_exec_si_smul"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:DI 2 "even_gpr_operand" "=e")
+        (mult:DI (sign_extend:DI (match_operand:SI 3 "integer_register_operand" "%d"))
+                 (sign_extend:DI (match_operand:SI 4 "integer_register_operand" "d")))))]
+  ""
+  "csmul %3, %4, %2, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mul")])
+
+(define_insn "*cond_exec_si_divide"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SI 2 "integer_register_operand" "=d")
+        (match_operator:SI 3 "condexec_si_divide_operator"
+                           [(match_operand:SI 4 "integer_register_operand" "d")
+                            (match_operand:SI 5 "integer_register_operand" "d")])))]
+  ""
+  "*
+{
+  switch (GET_CODE (operands[3]))
+    {
+      case DIV:  return \"csdiv %4, %z5, %2, %1, %e0\";
+      case UDIV: return \"cudiv %4, %z5, %2, %1, %e0\";
+      default:   abort ();
+    }
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "div")])
+
+(define_insn "*cond_exec_si_unary1"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SI 2 "integer_register_operand" "=d")
+        (match_operator:SI 3 "condexec_si_unary_operator"
+                           [(match_operand:SI 4 "integer_register_operand" "d")])))]
+  ""
+  "*
+{
+  switch (GET_CODE (operands[3]))
+    {
+      case NOT: return \"cnot %4, %2, %1, %e0\";
+      case NEG: return \"csub %., %4, %2, %1, %e0\";
+      default:  abort ();
+    }
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_insn "*cond_exec_si_unary2"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SI 2 "fpr_operand" "=f")
+        (not:SI (match_operand:SI 3 "fpr_operand" "f"))))]
+  "TARGET_MEDIA"
+  "cmnot %3, %2, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mlogic")])
+
+(define_insn "*cond_exec_cmpsi_cc"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:CC 2 "icc_operand" "=t")
+        (compare:CC (match_operand:SI 3 "integer_register_operand" "d")
+                    (match_operand:SI 4 "reg_or_0_operand" "dO"))))]
+  "reload_completed
+   && REGNO (operands[1]) == REGNO (operands[2]) - ICC_FIRST + ICR_FIRST"
+  "ccmp %3, %z4, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_insn "*cond_exec_cmpsi_cc_uns"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:CC_UNS 2 "icc_operand" "=t")
+        (compare:CC_UNS (match_operand:SI 3 "integer_register_operand" "d")
+                        (match_operand:SI 4 "reg_or_0_operand" "dO"))))]
+  "reload_completed
+   && REGNO (operands[1]) == REGNO (operands[2]) - ICC_FIRST + ICR_FIRST"
+  "ccmp %3, %z4, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+(define_insn "*cond_exec_sf_conv"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SF 2 "fpr_operand" "=f")
+        (match_operator:SF 3 "condexec_sf_conv_operator"
+                           [(match_operand:SF 4 "fpr_operand" "f")])))]
+  "TARGET_HARD_FLOAT"
+  "*
+{
+  switch (GET_CODE (operands[3]))
+    {
+      case ABS: return \"cfabss %4, %2, %1, %e0\";
+      case NEG: return \"cfnegs %4, %2, %1, %e0\";
+      default:  abort ();
+    }
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsconv")])
+
+(define_insn "*cond_exec_sf_add"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SF 2 "fpr_operand" "=f")
+        (match_operator:SF 3 "condexec_sf_add_operator"
+                           [(match_operand:SF 4 "fpr_operand" "f")
+                            (match_operand:SF 5 "fpr_operand" "f")])))]
+  "TARGET_HARD_FLOAT"
+  "*
+{
+  switch (GET_CODE (operands[3]))
+    {
+      case PLUS:  return \"cfadds %4, %5, %2, %1, %e0\";
+      case MINUS: return \"cfsubs %4, %5, %2, %1, %e0\";
+      default:    abort ();
+    }
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsadd")])
+
+(define_insn "*cond_exec_sf_mul"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SF 2 "fpr_operand" "=f")
+        (mult:SF (match_operand:SF 3 "fpr_operand" "f")
+                 (match_operand:SF 4 "fpr_operand" "f"))))]
+  "TARGET_HARD_FLOAT"
+  "cfmuls %3, %4, %2, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsmul")])
+
+(define_insn "*cond_exec_sf_div"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SF 2 "fpr_operand" "=f")
+        (div:SF (match_operand:SF 3 "fpr_operand" "f")
+                (match_operand:SF 4 "fpr_operand" "f"))))]
+  "TARGET_HARD_FLOAT"
+  "cfdivs %3, %4, %2, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsdiv")])
+
+(define_insn "*cond_exec_sf_sqrt"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SF 2 "fpr_operand" "=f")
+        (sqrt:SF (match_operand:SF 3 "fpr_operand" "f"))))]
+  "TARGET_HARD_FLOAT"
+  "cfsqrts %3, %2, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsdiv")])
+
+(define_insn "*cond_exec_cmpsi_cc_fp"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:CC_FP 2 "fcc_operand" "=u")
+        (compare:CC_FP (match_operand:SF 3 "fpr_operand" "f")
+                       (match_operand:SF 4 "fpr_operand" "f"))))]
+  "reload_completed && TARGET_HARD_FLOAT
+   && REGNO (operands[1]) == REGNO (operands[2]) - FCC_FIRST + FCR_FIRST"
+  "cfcmps %3, %4, %2, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "fsconv")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Logical operations on CR registers
+;; ::
+;; ::::::::::::::::::::
+
+;; We use UNSPEC to encode andcr/iorcr/etc. rather than the normal RTL
+;; operations, since the RTL operations only have an idea of TRUE and FALSE,
+;; while the CRs have TRUE, FALSE, and UNDEFINED.
+
+(define_expand "andcr"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "")
+       (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "")
+                       (match_operand:CC_CCR 2 "cr_operand" "")
+                       (const_int 0)] UNSPEC_CR_LOGIC))]
+  ""
+  "")
+
+(define_expand "orcr"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "")
+       (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "")
+                       (match_operand:CC_CCR 2 "cr_operand" "")
+                       (const_int 1)] UNSPEC_CR_LOGIC))]
+  ""
+  "")
+
+(define_expand "xorcr"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "")
+       (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "")
+                       (match_operand:CC_CCR 2 "cr_operand" "")
+                       (const_int 2)] UNSPEC_CR_LOGIC))]
+  ""
+  "")
+
+(define_expand "nandcr"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "")
+       (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "")
+                       (match_operand:CC_CCR 2 "cr_operand" "")
+                       (const_int 3)] UNSPEC_CR_LOGIC))]
+  ""
+  "")
+
+(define_expand "norcr"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "")
+       (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "")
+                       (match_operand:CC_CCR 2 "cr_operand" "")
+                       (const_int 4)] UNSPEC_CR_LOGIC))]
+  ""
+  "")
+
+(define_expand "andncr"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "")
+       (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "")
+                       (match_operand:CC_CCR 2 "cr_operand" "")
+                       (const_int 5)] UNSPEC_CR_LOGIC))]
+  ""
+  "")
+
+(define_expand "orncr"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "")
+       (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "")
+                       (match_operand:CC_CCR 2 "cr_operand" "")
+                       (const_int 6)] UNSPEC_CR_LOGIC))]
+  ""
+  "")
+
+(define_expand "nandncr"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "")
+       (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "")
+                       (match_operand:CC_CCR 2 "cr_operand" "")
+                       (const_int 7)] UNSPEC_CR_LOGIC))]
+  ""
+  "")
+
+(define_expand "norncr"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "")
+       (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "")
+                       (match_operand:CC_CCR 2 "cr_operand" "")
+                       (const_int 8)] UNSPEC_CR_LOGIC))]
+  ""
+  "")
+
+(define_expand "notcr"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "")
+       (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "")
+                       (match_dup 1)
+                       (const_int 9)] UNSPEC_CR_LOGIC))]
+  ""
+  "")
+
+(define_insn "*logical_cr"
+  [(set (match_operand:CC_CCR 0 "cr_operand" "=C")
+       (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "C")
+                       (match_operand:CC_CCR 2 "cr_operand" "C")
+                       (match_operand:SI 3 "const_int_operand" "n")]
+                      UNSPEC_CR_LOGIC))]
+  ""
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default: break;
+  case 0: return \"andcr %1, %2, %0\";
+  case 1: return \"orcr %1, %2, %0\";
+  case 2: return \"xorcr %1, %2, %0\";
+  case 3: return \"nandcr %1, %2, %0\";
+  case 4: return \"norcr %1, %2, %0\";
+  case 5: return \"andncr %1, %2, %0\";
+  case 6: return \"orncr %1, %2, %0\";
+  case 7: return \"nandncr %1, %2, %0\";
+  case 8: return \"norncr %1, %2, %0\";
+  case 9: return \"notcr %1, %0\";
+  }
+
+  fatal_insn (\"logical_cr\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "ccr")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Conditional move instructions
+;; ::
+;; ::::::::::::::::::::
+
+
+;; - conditional moves based on floating-point comparisons require
+;;   TARGET_HARD_FLOAT, because an FPU is required to do the comparison.
+
+;; - conditional moves between FPRs based on integer comparisons
+;;   require TARGET_HAS_FPRS.
+
+(define_expand "movqicc"
+  [(set (match_operand:QI 0 "integer_register_operand" "")
+       (if_then_else:QI (match_operand 1 "" "")
+                        (match_operand:QI 2 "gpr_or_int_operand" "")
+                        (match_operand:QI 3 "gpr_or_int_operand" "")))]
+  "TARGET_COND_MOVE"
+  "
+{
+  if (!frv_emit_cond_move (operands[0], operands[1], operands[2], operands[3]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_insn "*movqicc_internal1_signed"
+  [(set (match_operand:QI 0 "integer_register_operand" "=d,d,d")
+       (if_then_else:QI (match_operator:CC 1 "signed_relational_operator"
+                            [(match_operand:CC 2 "icc_operand" "t,t,t")
+                             (const_int 0)])
+                        (match_operand:QI 3 "reg_or_0_operand" "0,dO,dO")
+                        (match_operand:QI 4 "reg_or_0_operand" "dO,0,dO")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))]
+  ""
+  "#"
+  [(set_attr "length" "8,8,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movqicc_internal1_unsigned"
+  [(set (match_operand:QI 0 "integer_register_operand" "=d,d,d")
+       (if_then_else:QI (match_operator:CC_UNS 1 "unsigned_relational_operator"
+                            [(match_operand:CC_UNS 2 "icc_operand" "t,t,t")
+                             (const_int 0)])
+                        (match_operand:QI 3 "reg_or_0_operand" "0,dO,dO")
+                        (match_operand:QI 4 "reg_or_0_operand" "dO,0,dO")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))]
+  ""
+  "#"
+  [(set_attr "length" "8,8,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movqicc_internal1_float"
+  [(set (match_operand:QI 0 "integer_register_operand" "=d,d,d")
+       (if_then_else:QI (match_operator:CC_FP 1 "float_relational_operator"
+                            [(match_operand:CC_FP 2 "fcc_operand" "u,u,u")
+                             (const_int 0)])
+                        (match_operand:QI 3 "reg_or_0_operand" "0,dO,dO")
+                        (match_operand:QI 4 "reg_or_0_operand" "dO,0,dO")))
+   (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w"))]
+  "TARGET_HARD_FLOAT"
+  "#"
+  [(set_attr "length" "8,8,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movqicc_internal2_signed"
+  [(set (match_operand:QI 0 "integer_register_operand" "=d,d,d,d,d")
+       (if_then_else:QI (match_operator:CC 1 "signed_relational_operator"
+                            [(match_operand:CC 2 "icc_operand" "t,t,t,t,t")
+                             (const_int 0)])
+                        (match_operand:QI 3 "const_int_operand" "O,O,L,n,n")
+                        (match_operand:QI 4 "const_int_operand" "L,n,O,O,n")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v"))]
+  "(INTVAL (operands[3]) == 0
+    || INTVAL (operands[4]) == 0
+    || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047)
+        && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))"
+  "#"
+  [(set_attr "length" "8,12,8,12,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movqicc_internal2_unsigned"
+  [(set (match_operand:QI 0 "integer_register_operand" "=d,d,d,d,d")
+       (if_then_else:QI (match_operator:CC_UNS 1 "unsigned_relational_operator"
+                            [(match_operand:CC_UNS 2 "icc_operand" "t,t,t,t,t")
+                             (const_int 0)])
+                        (match_operand:QI 3 "const_int_operand" "O,O,L,n,n")
+                        (match_operand:QI 4 "const_int_operand" "L,n,O,O,n")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v"))]
+  "(INTVAL (operands[3]) == 0
+    || INTVAL (operands[4]) == 0
+    || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047)
+        && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))"
+  "#"
+  [(set_attr "length" "8,12,8,12,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movqicc_internal2_float"
+  [(set (match_operand:QI 0 "integer_register_operand" "=d,d,d,d,d")
+       (if_then_else:QI (match_operator:CC_FP 1 "float_relational_operator"
+                            [(match_operand:CC_FP 2 "fcc_operand" "u,u,u,u,u")
+                             (const_int 0)])
+                        (match_operand:QI 3 "const_int_operand" "O,O,L,n,n")
+                        (match_operand:QI 4 "const_int_operand" "L,n,O,O,n")))
+   (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w,w,w"))]
+  "TARGET_HARD_FLOAT
+   && (INTVAL (operands[3]) == 0
+       || INTVAL (operands[4]) == 0
+       || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047)
+          && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))"
+  "#"
+  [(set_attr "length" "8,12,8,12,12")
+   (set_attr "type" "multi")])
+
+(define_split
+  [(set (match_operand:QI 0 "integer_register_operand" "")
+       (if_then_else:QI (match_operator 1 "relational_operator"
+                            [(match_operand 2 "cc_operand" "")
+                             (const_int 0)])
+                        (match_operand:QI 3 "gpr_or_int_operand" "")
+                        (match_operand:QI 4 "gpr_or_int_operand" "")))
+   (clobber (match_operand:CC_CCR 5 "cr_operand" ""))]
+  "reload_completed"
+  [(match_dup 6)]
+  "operands[6] = frv_split_cond_move (operands);")
+
+(define_expand "movhicc"
+  [(set (match_operand:HI 0 "integer_register_operand" "")
+       (if_then_else:HI (match_operand 1 "" "")
+                        (match_operand:HI 2 "gpr_or_int_operand" "")
+                        (match_operand:HI 3 "gpr_or_int_operand" "")))]
+  "TARGET_COND_MOVE"
+  "
+{
+  if (!frv_emit_cond_move (operands[0], operands[1], operands[2], operands[3]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_insn "*movhicc_internal1_signed"
+  [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d")
+       (if_then_else:HI (match_operator:CC 1 "signed_relational_operator"
+                            [(match_operand:CC 2 "icc_operand" "t,t,t")
+                             (const_int 0)])
+                        (match_operand:HI 3 "reg_or_0_operand" "0,dO,dO")
+                        (match_operand:HI 4 "reg_or_0_operand" "dO,0,dO")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))]
+  ""
+  "#"
+  [(set_attr "length" "8,8,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movhicc_internal1_unsigned"
+  [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d")
+       (if_then_else:HI (match_operator:CC_UNS 1 "unsigned_relational_operator"
+                            [(match_operand:CC_UNS 2 "icc_operand" "t,t,t")
+                             (const_int 0)])
+                        (match_operand:HI 3 "reg_or_0_operand" "0,dO,dO")
+                        (match_operand:HI 4 "reg_or_0_operand" "dO,0,dO")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))]
+  ""
+  "#"
+  [(set_attr "length" "8,8,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movhicc_internal1_float"
+  [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d")
+       (if_then_else:HI (match_operator:CC_FP 1 "float_relational_operator"
+                            [(match_operand:CC_FP 2 "fcc_operand" "u,u,u")
+                             (const_int 0)])
+                        (match_operand:HI 3 "reg_or_0_operand" "0,dO,dO")
+                        (match_operand:HI 4 "reg_or_0_operand" "dO,0,dO")))
+   (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w"))]
+  "TARGET_HARD_FLOAT"
+  "#"
+  [(set_attr "length" "8,8,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movhicc_internal2_signed"
+  [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d,d,d")
+       (if_then_else:HI (match_operator:CC 1 "signed_relational_operator"
+                            [(match_operand:CC 2 "icc_operand" "t,t,t,t,t")
+                             (const_int 0)])
+                        (match_operand:HI 3 "const_int_operand" "O,O,L,n,n")
+                        (match_operand:HI 4 "const_int_operand" "L,n,O,O,n")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v"))]
+  "(INTVAL (operands[3]) == 0
+    || INTVAL (operands[4]) == 0
+    || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047)
+        && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))"
+  "#"
+  [(set_attr "length" "8,12,8,12,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movhicc_internal2_unsigned"
+  [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d,d,d")
+       (if_then_else:HI (match_operator:CC_UNS 1 "unsigned_relational_operator"
+                            [(match_operand:CC_UNS 2 "icc_operand" "t,t,t,t,t")
+                             (const_int 0)])
+                        (match_operand:HI 3 "const_int_operand" "O,O,L,n,n")
+                        (match_operand:HI 4 "const_int_operand" "L,n,O,O,n")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v"))]
+  "(INTVAL (operands[3]) == 0
+    || INTVAL (operands[4]) == 0
+    || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047)
+        && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))"
+  "#"
+  [(set_attr "length" "8,12,8,12,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movhicc_internal2_float"
+  [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d,d,d")
+       (if_then_else:HI (match_operator:CC_FP 1 "float_relational_operator"
+                            [(match_operand:CC_FP 2 "fcc_operand" "u,u,u,u,u")
+                             (const_int 0)])
+                        (match_operand:HI 3 "const_int_operand" "O,O,L,n,n")
+                        (match_operand:HI 4 "const_int_operand" "L,n,O,O,n")))
+   (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w,w,w"))]
+  "TARGET_HARD_FLOAT
+   && (INTVAL (operands[3]) == 0
+       || INTVAL (operands[4]) == 0
+       || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047)
+          && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))"
+  "#"
+  [(set_attr "length" "8,12,8,12,12")
+   (set_attr "type" "multi")])
+
+(define_split
+  [(set (match_operand:HI 0 "integer_register_operand" "")
+       (if_then_else:HI (match_operator 1 "relational_operator"
+                            [(match_operand 2 "cc_operand" "")
+                             (const_int 0)])
+                        (match_operand:HI 3 "gpr_or_int_operand" "")
+                        (match_operand:HI 4 "gpr_or_int_operand" "")))
+   (clobber (match_operand:CC_CCR 5 "cr_operand" ""))]
+  "reload_completed"
+  [(match_dup 6)]
+  "operands[6] = frv_split_cond_move (operands);")
+
+(define_expand "movsicc"
+  [(set (match_operand:SI 0 "integer_register_operand" "")
+       (if_then_else:SI (match_operand 1 "" "")
+                        (match_operand:SI 2 "gpr_or_int_operand" "")
+                        (match_operand:SI 3 "gpr_or_int_operand" "")))]
+  "TARGET_COND_MOVE"
+  "
+{
+  if (!frv_emit_cond_move (operands[0], operands[1], operands[2], operands[3]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_insn "*movsicc_internal1_signed"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d")
+       (if_then_else:SI (match_operator:CC 1 "signed_relational_operator"
+                            [(match_operand:CC 2 "icc_operand" "t,t,t")
+                             (const_int 0)])
+                        (match_operand:SI 3 "reg_or_0_operand" "0,dO,dO")
+                        (match_operand:SI 4 "reg_or_0_operand" "dO,0,dO")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))]
+  ""
+  "#"
+  [(set_attr "length" "8,8,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movsicc_internal1_unsigned"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d")
+       (if_then_else:SI (match_operator:CC_UNS 1 "unsigned_relational_operator"
+                            [(match_operand:CC_UNS 2 "icc_operand" "t,t,t")
+                             (const_int 0)])
+                        (match_operand:SI 3 "reg_or_0_operand" "0,dO,dO")
+                        (match_operand:SI 4 "reg_or_0_operand" "dO,0,dO")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))]
+  ""
+  "#"
+  [(set_attr "length" "8,8,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movsicc_internal1_float"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d")
+       (if_then_else:SI (match_operator:CC_FP 1 "float_relational_operator"
+                            [(match_operand:CC_FP 2 "fcc_operand" "u,u,u")
+                             (const_int 0)])
+                        (match_operand:SI 3 "reg_or_0_operand" "0,dO,dO")
+                        (match_operand:SI 4 "reg_or_0_operand" "dO,0,dO")))
+   (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w"))]
+  "TARGET_HARD_FLOAT"
+  "#"
+  [(set_attr "length" "8,8,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movsicc_internal2_signed"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d,d,d")
+       (if_then_else:SI (match_operator:CC 1 "signed_relational_operator"
+                            [(match_operand:CC 2 "icc_operand" "t,t,t,t,t")
+                             (const_int 0)])
+                        (match_operand:SI 3 "const_int_operand" "O,O,L,n,n")
+                        (match_operand:SI 4 "const_int_operand" "L,n,O,O,n")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v"))]
+  "(INTVAL (operands[3]) == 0
+    || INTVAL (operands[4]) == 0
+    || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047)
+        && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))"
+  "#"
+  [(set_attr "length" "8,12,8,12,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movsicc_internal2_unsigned"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d,d,d")
+       (if_then_else:SI (match_operator:CC_UNS 1 "unsigned_relational_operator"
+                            [(match_operand:CC_UNS 2 "icc_operand" "t,t,t,t,t")
+                             (const_int 0)])
+                        (match_operand:SI 3 "const_int_operand" "O,O,L,n,n")
+                        (match_operand:SI 4 "const_int_operand" "L,n,O,O,n")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v"))]
+  "(INTVAL (operands[3]) == 0
+    || INTVAL (operands[4]) == 0
+    || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047)
+        && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))"
+  "#"
+  [(set_attr "length" "8,12,8,12,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movsicc_internal2_float"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d,d,d")
+       (if_then_else:SI (match_operator:CC_FP 1 "float_relational_operator"
+                            [(match_operand:CC_FP 2 "fcc_operand" "u,u,u,u,u")
+                             (const_int 0)])
+                        (match_operand:SI 3 "const_int_operand" "O,O,L,n,n")
+                        (match_operand:SI 4 "const_int_operand" "L,n,O,O,n")))
+   (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w,w,w"))]
+  "TARGET_HARD_FLOAT
+   && (INTVAL (operands[3]) == 0
+       || INTVAL (operands[4]) == 0
+       || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047)
+          && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))"
+  "#"
+  [(set_attr "length" "8,12,8,12,12")
+   (set_attr "type" "multi")])
+
+(define_split
+  [(set (match_operand:SI 0 "integer_register_operand" "")
+       (if_then_else:SI (match_operator 1 "relational_operator"
+                            [(match_operand 2 "cc_operand" "")
+                             (const_int 0)])
+                        (match_operand:SI 3 "gpr_or_int_operand" "")
+                        (match_operand:SI 4 "gpr_or_int_operand" "")))
+   (clobber (match_operand:CC_CCR 5 "cr_operand" ""))]
+  "reload_completed"
+  [(match_dup 6)]
+  "operands[6] = frv_split_cond_move (operands);")
+
+(define_expand "movsfcc"
+  [(set (match_operand:SF 0 "register_operand" "")
+       (if_then_else:SF (match_operand 1 "" "")
+                        (match_operand:SF 2 "register_operand" "")
+                        (match_operand:SF 3 "register_operand" "")))]
+  "TARGET_COND_MOVE"
+  "
+{
+  if (!frv_emit_cond_move (operands[0], operands[1], operands[2], operands[3]))
+    FAIL;
+
+  DONE;
+}")
+
+(define_insn "*movsfcc_has_fprs_signed"
+  [(set (match_operand:SF 0 "register_operand" "=f,f,f,?f,?f,?d")
+       (if_then_else:SF (match_operator:CC 1 "signed_relational_operator"
+                            [(match_operand:CC 2 "icc_operand" "t,t,t,t,t,t")
+                             (const_int 0)])
+                        (match_operand:SF 3 "register_operand" "0,f,f,f,d,fd")
+                        (match_operand:SF 4 "register_operand" "f,0,f,d,fd,fd")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v,v"))]
+  "TARGET_HAS_FPRS"
+  "#"
+  [(set_attr "length" "8,8,12,12,12,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movsfcc_has_fprs_unsigned"
+  [(set (match_operand:SF 0 "register_operand" "=f,f,f,?f,?f,?d")
+       (if_then_else:SF (match_operator:CC_UNS 1 "unsigned_relational_operator"
+                            [(match_operand:CC_UNS 2 "icc_operand" "t,t,t,t,t,t")
+                             (const_int 0)])
+                        (match_operand:SF 3 "register_operand" "0,f,f,f,d,fd")
+                        (match_operand:SF 4 "register_operand" "f,0,f,d,fd,fd")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v,v"))]
+  "TARGET_HAS_FPRS"
+  "#"
+  [(set_attr "length" "8,8,12,12,12,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movsfcc_hardfloat_float"
+  [(set (match_operand:SF 0 "register_operand" "=f,f,f,?f,?f,?d")
+       (if_then_else:SF (match_operator:CC_FP 1 "float_relational_operator"
+                            [(match_operand:CC_FP 2 "fcc_operand" "u,u,u,u,u,u")
+                             (const_int 0)])
+                        (match_operand:SF 3 "register_operand" "0,f,f,f,d,fd")
+                        (match_operand:SF 4 "register_operand" "f,0,f,d,fd,fd")))
+   (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w,w,w,w"))]
+  "TARGET_HARD_FLOAT"
+  "#"
+  [(set_attr "length" "8,8,12,12,12,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movsfcc_no_fprs_signed"
+  [(set (match_operand:SF 0 "integer_register_operand" "=d,d,d")
+       (if_then_else:SF (match_operator:CC 1 "signed_relational_operator"
+                            [(match_operand:CC 2 "icc_operand" "t,t,t")
+                             (const_int 0)])
+                        (match_operand:SF 3 "integer_register_operand" "0,d,d")
+                        (match_operand:SF 4 "integer_register_operand" "d,0,d")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))]
+  "! TARGET_HAS_FPRS"
+  "#"
+  [(set_attr "length" "8,8,12")
+   (set_attr "type" "multi")])
+
+(define_insn "*movsfcc_no_fprs_unsigned"
+  [(set (match_operand:SF 0 "integer_register_operand" "=d,d,d")
+       (if_then_else:SF (match_operator:CC_UNS 1 "unsigned_relational_operator"
+                            [(match_operand:CC_UNS 2 "icc_operand" "t,t,t")
+                             (const_int 0)])
+                        (match_operand:SF 3 "integer_register_operand" "0,d,d")
+                        (match_operand:SF 4 "integer_register_operand" "d,0,d")))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))]
+  "! TARGET_HAS_FPRS"
+  "#"
+  [(set_attr "length" "8,8,12")
+   (set_attr "type" "multi")])
+
+(define_split
+  [(set (match_operand:SF 0 "register_operand" "")
+       (if_then_else:SF (match_operator 1 "relational_operator"
+                            [(match_operand 2 "cc_operand" "")
+                             (const_int 0)])
+                        (match_operand:SF 3 "register_operand" "")
+                        (match_operand:SF 4 "register_operand" "")))
+   (clobber (match_operand:CC_CCR 5 "cr_operand" ""))]
+  "reload_completed"
+  [(match_dup 6)]
+  "operands[6] = frv_split_cond_move (operands);")
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Minimum, maximum, and integer absolute value
+;; ::
+;; ::::::::::::::::::::
+
+;; These 'instructions' are provided to give the compiler a slightly better
+;; nudge at register allocation, then it would if it constructed the
+;; instructions from basic building blocks (since it indicates it prefers one
+;; of the operands to be the same as the destination.  It also helps the
+;; earlier passes of the compiler, by not breaking things into small basic
+;; blocks.
+
+(define_expand "abssi2"
+  [(parallel [(set (match_operand:SI 0 "integer_register_operand" "")
+                  (abs:SI (match_operand:SI 1 "integer_register_operand" "")))
+             (clobber (match_dup 2))
+             (clobber (match_dup 3))])]
+  "TARGET_COND_MOVE"
+  "
+{
+  operands[2] = gen_reg_rtx (CCmode);
+  operands[3] = gen_reg_rtx (CC_CCRmode);
+}")
+
+(define_insn_and_split "*abssi2_internal"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d")
+       (abs:SI (match_operand:SI 1 "integer_register_operand" "0,d")))
+   (clobber (match_operand:CC 2 "icc_operand" "=t,t"))
+   (clobber (match_operand:CC_CCR 3 "icr_operand" "=v,v"))]
+  "TARGET_COND_MOVE"
+  "#"
+  "reload_completed"
+  [(match_dup 4)]
+  "operands[4] = frv_split_abs (operands);"
+  [(set_attr "length" "12,16")
+   (set_attr "type" "multi")])
+
+(define_expand "sminsi3"
+  [(parallel [(set (match_operand:SI 0 "integer_register_operand" "")
+                  (smin:SI (match_operand:SI 1 "integer_register_operand" "")
+                           (match_operand:SI 2 "gpr_or_int10_operand" "")))
+             (clobber (match_dup 3))
+             (clobber (match_dup 4))])]
+  "TARGET_COND_MOVE"
+  "
+{
+  operands[3] = gen_reg_rtx (CCmode);
+  operands[4] = gen_reg_rtx (CC_CCRmode);
+}")
+
+(define_expand "smaxsi3"
+  [(parallel [(set (match_operand:SI 0 "integer_register_operand" "")
+                  (smax:SI (match_operand:SI 1 "integer_register_operand" "")
+                           (match_operand:SI 2 "gpr_or_int10_operand" "")))
+             (clobber (match_dup 3))
+             (clobber (match_dup 4))])]
+  "TARGET_COND_MOVE"
+  "
+{
+  operands[3] = gen_reg_rtx (CCmode);
+  operands[4] = gen_reg_rtx (CC_CCRmode);
+}")
+
+(define_insn_and_split "*minmax_si_signed"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d,&d")
+       (match_operator:SI 1 "minmax_operator"
+                          [(match_operand:SI 2 "integer_register_operand" "%0,dO,d")
+                           (match_operand:SI 3 "gpr_or_int10_operand" "dO,0,dJ")]))
+   (clobber (match_operand:CC 4 "icc_operand" "=t,t,t"))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))]
+  "TARGET_COND_MOVE"
+  "#"
+  "reload_completed"
+  [(match_dup 6)]
+  "operands[6] = frv_split_minmax (operands);"
+  [(set_attr "length" "12,12,16")
+   (set_attr "type" "multi")])
+
+(define_expand "uminsi3"
+  [(parallel [(set (match_operand:SI 0 "integer_register_operand" "")
+                  (umin:SI (match_operand:SI 1 "integer_register_operand" "")
+                           (match_operand:SI 2 "gpr_or_int10_operand" "")))
+             (clobber (match_dup 3))
+             (clobber (match_dup 4))])]
+  "TARGET_COND_MOVE"
+  "
+{
+  operands[3] = gen_reg_rtx (CC_UNSmode);
+  operands[4] = gen_reg_rtx (CC_CCRmode);
+}")
+
+(define_expand "umaxsi3"
+  [(parallel [(set (match_operand:SI 0 "integer_register_operand" "")
+                  (umax:SI (match_operand:SI 1 "integer_register_operand" "")
+                           (match_operand:SI 2 "gpr_or_int10_operand" "")))
+             (clobber (match_dup 3))
+             (clobber (match_dup 4))])]
+  "TARGET_COND_MOVE"
+  "
+{
+  operands[3] = gen_reg_rtx (CC_UNSmode);
+  operands[4] = gen_reg_rtx (CC_CCRmode);
+}")
+
+(define_insn_and_split "*minmax_si_unsigned"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d,d,&d")
+       (match_operator:SI 1 "minmax_operator"
+                          [(match_operand:SI 2 "integer_register_operand" "%0,dO,d")
+                           (match_operand:SI 3 "gpr_or_int10_operand" "dO,0,dJ")]))
+   (clobber (match_operand:CC_UNS 4 "icc_operand" "=t,t,t"))
+   (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))]
+  "TARGET_COND_MOVE"
+  "#"
+  "reload_completed"
+  [(match_dup 6)]
+  "operands[6] = frv_split_minmax (operands);"
+  [(set_attr "length" "12,12,16")
+   (set_attr "type" "multi")])
+
+(define_expand "sminsf3"
+  [(parallel [(set (match_operand:SF 0 "fpr_operand" "")
+                  (smin:SF (match_operand:SF 1 "fpr_operand" "")
+                           (match_operand:SF 2 "fpr_operand" "")))
+             (clobber (match_dup 3))
+             (clobber (match_dup 4))])]
+  "TARGET_COND_MOVE && TARGET_HARD_FLOAT"
+  "
+{
+  operands[3] = gen_reg_rtx (CC_FPmode);
+  operands[4] = gen_reg_rtx (CC_CCRmode);
+}")
+
+(define_expand "smaxsf3"
+  [(parallel [(set (match_operand:SF 0 "fpr_operand" "")
+                  (smax:SF (match_operand:SF 1 "fpr_operand" "")
+                           (match_operand:SF 2 "fpr_operand" "")))
+             (clobber (match_dup 3))
+             (clobber (match_dup 4))])]
+  "TARGET_COND_MOVE && TARGET_HARD_FLOAT"
+  "
+{
+  operands[3] = gen_reg_rtx (CC_FPmode);
+  operands[4] = gen_reg_rtx (CC_CCRmode);
+}")
+
+(define_insn_and_split "*minmax_sf"
+  [(set (match_operand:SF 0 "fpr_operand" "=f,f,f")
+       (match_operator:SF 1 "minmax_operator"
+                          [(match_operand:SF 2 "fpr_operand" "%0,f,f")
+                           (match_operand:SF 3 "fpr_operand" "f,0,f")]))
+   (clobber (match_operand:CC_FP 4 "fcc_operand" "=u,u,u"))
+   (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w"))]
+  "TARGET_COND_MOVE && TARGET_HARD_FLOAT"
+  "#"
+  "reload_completed"
+  [(match_dup 6)]
+  "operands[6] = frv_split_minmax (operands);"
+  [(set_attr "length" "12,12,16")
+   (set_attr "type" "multi")])
+
+(define_expand "smindf3"
+  [(parallel [(set (match_operand:DF 0 "fpr_operand" "")
+                  (smin:DF (match_operand:DF 1 "fpr_operand" "")
+                           (match_operand:DF 2 "fpr_operand" "")))
+             (clobber (match_dup 3))
+             (clobber (match_dup 4))])]
+  "TARGET_COND_MOVE && TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "
+{
+  operands[3] = gen_reg_rtx (CC_FPmode);
+  operands[4] = gen_reg_rtx (CC_CCRmode);
+}")
+
+(define_expand "smaxdf3"
+  [(parallel [(set (match_operand:DF 0 "fpr_operand" "")
+                  (smax:DF (match_operand:DF 1 "fpr_operand" "")
+                           (match_operand:DF 2 "fpr_operand" "")))
+             (clobber (match_dup 3))
+             (clobber (match_dup 4))])]
+  "TARGET_COND_MOVE && TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "
+{
+  operands[3] = gen_reg_rtx (CC_FPmode);
+  operands[4] = gen_reg_rtx (CC_CCRmode);
+}")
+
+(define_insn_and_split "*minmax_df"
+  [(set (match_operand:DF 0 "fpr_operand" "=f,f,f")
+       (match_operator:DF 1 "minmax_operator"
+                          [(match_operand:DF 2 "fpr_operand" "%0,f,f")
+                           (match_operand:DF 3 "fpr_operand" "f,0,f")]))
+   (clobber (match_operand:CC_FP 4 "fcc_operand" "=u,u,u"))
+   (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w"))]
+  "TARGET_COND_MOVE && TARGET_HARD_FLOAT && TARGET_DOUBLE"
+  "#"
+  "reload_completed"
+  [(match_dup 6)]
+  "operands[6] = frv_split_minmax (operands);"
+  [(set_attr "length" "12,12,16")
+   (set_attr "type" "multi")])
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Call and branch instructions
+;; ::
+;; ::::::::::::::::::::
+
+;; Subroutine call instruction returning no value.  Operand 0 is the function
+;; to call; operand 1 is the number of bytes of arguments pushed (in mode
+;; `SImode', except it is normally a `const_int'); operand 2 is the number of
+;; registers used as operands.
+
+;; On most machines, operand 2 is not actually stored into the RTL pattern.  It
+;; is supplied for the sake of some RISC machines which need to put this
+;; information into the assembler code; they can put it in the RTL instead of
+;; operand 1.
+
+(define_expand "call"
+  [(use (match_operand:QI 0 "" ""))
+   (use (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (use (match_operand 3 "" ""))]
+  ""
+  "
+{
+  rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
+  rtx addr;
+
+  if (GET_CODE (operands[0]) != MEM)
+    abort ();
+
+  addr = XEXP (operands[0], 0);
+  if (! call_operand (addr, Pmode))
+    addr = force_reg (Pmode, addr);
+
+  if (! operands[2])
+    operands[2] = const0_rtx;
+
+  emit_call_insn (gen_call_internal (addr, operands[1], operands[2], lr));
+  DONE;
+}")
+
+(define_insn "call_internal"
+  [(call (mem:QI (match_operand:SI 0 "call_operand" "S,dNOP"))
+        (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (match_operand:SI 3 "lr_operand" "=l,l"))]
+  ""
+  "@
+   call %0
+   call%i0l %M0"
+  [(set_attr "length" "4")
+   (set_attr "type" "call,jumpl")])
+
+;; Subroutine call instruction returning a value.  Operand 0 is the hard
+;; register in which the value is returned.  There are three more operands, the
+;; same as the three operands of the `call' instruction (but with numbers
+;; increased by one).
+
+;; Subroutines that return `BLKmode' objects use the `call' insn.
+
+(define_expand "call_value"
+  [(use (match_operand 0 "" ""))
+   (use (match_operand:QI 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (use (match_operand 3 "" ""))
+   (use (match_operand 4 "" ""))]
+  ""
+  "
+{
+  rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
+  rtx addr;
+
+  if (GET_CODE (operands[1]) != MEM)
+    abort ();
+
+  addr = XEXP (operands[1], 0);
+  if (! call_operand (addr, Pmode))
+    addr = force_reg (Pmode, addr);
+
+  if (! operands[3])
+    operands[3] = const0_rtx;
+
+  emit_call_insn (gen_call_value_internal (operands[0], addr, operands[2],
+                                          operands[3], lr));
+  DONE;
+}")
+
+(define_insn "call_value_internal"
+  [(set (match_operand 0 "register_operand" "=d,d")
+       (call (mem:QI (match_operand:SI 1 "call_operand" "S,dNOP"))
+                     (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (match_operand:SI 4 "lr_operand" "=l,l"))]
+  ""
+  "@
+   call %1
+   call%i1l %M1"
+  [(set_attr "length" "4")
+   (set_attr "type" "call,jumpl")])
+
+;; return instruction generated instead of jmp to epilog
+(define_expand "return"
+  [(parallel [(return)
+             (use (match_dup 0))
+             (use (const_int 1))])]
+  "direct_return_p ()"
+  "
+{
+  operands[0] = gen_rtx_REG (Pmode, LR_REGNO);
+}")
+
+;; return instruction generated by the epilogue
+(define_expand "epilogue_return"
+  [(parallel [(return)
+             (use (match_operand:SI 0 "register_operand" ""))
+             (use (const_int 0))])]
+  ""
+  "")
+
+(define_insn "*return_internal"
+  [(return)
+   (use (match_operand:SI 0 "register_operand" "l,d"))
+   (use (match_operand:SI 1 "immediate_operand" "n,n"))]
+  ""
+  "@
+    ret
+    jmpl @(%0,%.)"
+  [(set_attr "length" "4")
+   (set_attr "type" "jump,jumpl")])
+
+;; A version of addsi3 for deallocating stack space at the end of the
+;; epilogue.  The addition is done in parallel with an (unspec_volatile),
+;; which represents the clobbering of the deallocated space.
+(define_insn "stack_adjust"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "d")
+                (match_operand:SI 2 "general_operand" "dNOP")))
+   (unspec_volatile [(const_int 0)] UNSPEC_STACK_ADJUST)]
+  ""
+  "add%I2 %1,%2,%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+;; Normal unconditional jump
+
+;; Use the "call" instruction for long branches, but prefer to use "bra" for
+;; short ones since it does not force us to save the link register.
+
+;; This define_insn uses the branch-shortening code to decide which
+;; instruction it emits.  Since the main branch-shortening interface is
+;; through get_attr_length(), the two alternatives must be given different
+;; lengths.  Here we pretend that the far jump is 8 rather than 4 bytes
+;; long, though both alternatives are really the same size.
+(define_insn "jump"
+  [(set (pc) (label_ref (match_operand 0 "" "")))]
+  ""
+  "*
+{
+  if (get_attr_length (insn) == 4)
+    return \"bra %l0\";
+  else
+    return \"call %l0\";
+}"
+  [(set (attr "length")
+        (if_then_else
+           (and (ge (minus (match_dup 0) (pc)) (const_int -32768))
+                (le (minus (match_dup 0) (pc)) (const_int 32764)))
+           (const_int 4)
+           (const_int 8)))
+   (set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "4")
+           (const_string "no")
+           (const_string "yes")))
+   (set (attr "type")
+       (if_then_else
+           (eq_attr "length" "4")
+           (const_string "jump")
+           (const_string "call")))])
+
+;; Indirect jump through a register
+(define_insn "indirect_jump"
+  [(set (pc) (match_operand:SI 0 "register_operand" "d,l"))]
+  ""
+  "@
+   jmpl @(%0,%.)
+   bralr"
+  [(set_attr "length" "4")
+   (set_attr "type" "jumpl,branch")])
+
+;; Instruction to jump to a variable address.  This is a low-level capability
+;; which can be used to implement a dispatch table when there is no `casesi'
+;; pattern.  Either the 'casesi' pattern or the 'tablejump' pattern, or both,
+;; MUST be present in this file.
+
+;; This pattern requires two operands: the address or offset, and a label which
+;; should immediately precede the jump table.  If the macro
+;; `CASE_VECTOR_PC_RELATIVE' is defined then the first operand is an offset
+;; which counts from the address of the table; otherwise, it is an absolute
+;; address to jump to.  In either case, the first operand has mode `Pmode'.
+
+;; The `tablejump' insn is always the last insn before the jump table it uses.
+;; Its assembler code normally has no need to use the second operand, but you
+;; should incorporate it in the RTL pattern so that the jump optimizer will not
+;; delete the table as unreachable code.
+
+(define_expand "tablejump"
+  [(parallel [(set (pc) (match_operand:SI 0 "address_operand" "p"))
+             (use (label_ref (match_operand 1 "" "")))])]
+  "!flag_pic"
+  "")
+
+(define_insn "tablejump_insn"
+  [(set (pc) (match_operand:SI 0 "address_operand" "p"))
+   (use (label_ref (match_operand 1 "" "")))]
+  ""
+  "jmp%I0l %M0"
+  [(set_attr "length" "4")
+   (set_attr "type" "jumpl")])
+
+;; Implement switch statements when generating PIC code.  Switches are
+;; implemented by `tablejump' when not using -fpic.
+
+;; Emit code here to do the range checking and make the index zero based.
+;; operand 0 is the index
+;; operand 1 is the lower bound
+;; operand 2 is the range of indices (highest - lowest + 1)
+;; operand 3 is the label that precedes the table itself
+;; operand 4 is the fall through label
+
+(define_expand "casesi"
+  [(use (match_operand:SI 0 "integer_register_operand" ""))
+   (use (match_operand:SI 1 "const_int_operand" ""))
+   (use (match_operand:SI 2 "const_int_operand" ""))
+   (use (match_operand 3 "" ""))
+   (use (match_operand 4 "" ""))]
+  "flag_pic"
+  "
+{
+  rtx indx;
+  rtx scale;
+  rtx low = operands[1];
+  rtx range = operands[2];
+  rtx table = operands[3];
+  rtx treg;
+  rtx fail = operands[4];
+  rtx mem;
+  rtx reg2;
+  rtx reg3;
+
+  if (GET_CODE (operands[1]) != CONST_INT)
+    abort ();
+
+  if (GET_CODE (operands[2]) != CONST_INT)
+    abort ();
+
+  /* If we can't generate an immediate instruction, promote to register */
+  if (! IN_RANGE_P (INTVAL (range), -2048, 2047))
+    range = force_reg (SImode, range);
+
+  /* If low bound is 0, we don't have to subtract it.  */
+  if (INTVAL (operands[1]) == 0)
+    indx = operands[0];
+  else
+    {
+      indx = gen_reg_rtx (SImode);
+      if (IN_RANGE_P (INTVAL (low), -2047, 2048))
+       emit_insn (gen_addsi3 (indx, operands[0], GEN_INT (- INTVAL (low))));
+      else
+       emit_insn (gen_subsi3 (indx, operands[0], force_reg (SImode, low)));
+    }
+
+  /* Do an unsigned comparison (in the proper mode) between the index
+     expression and the value which represents the length of the range.
+     Since we just finished subtracting the lower bound of the range
+     from the index expression, this comparison allows us to simultaneously
+     check that the original index expression value is both greater than
+     or equal to the minimum value of the range and less than or equal to
+     the maximum value of the range.  */
+
+  emit_cmp_and_jump_insns (indx, range, GTU, NULL_RTX, SImode, 1, fail);
+
+  /* Move the table address to a register */
+  treg = gen_reg_rtx (Pmode);
+  emit_insn (gen_movsi (treg, gen_rtx_LABEL_REF (VOIDmode, table)));
+
+  /* scale index-low by wordsize */
+  scale = gen_reg_rtx (SImode);
+  emit_insn (gen_ashlsi3 (scale, indx, GEN_INT (2)));
+
+  /* Load the address, add the start of the table back in,
+     and jump to it.  */
+  mem = gen_rtx_MEM (SImode, gen_rtx_PLUS (Pmode, scale, treg));
+  reg2 = gen_reg_rtx (SImode);
+  reg3 = gen_reg_rtx (SImode);
+  emit_insn (gen_movsi (reg2, mem));
+  emit_insn (gen_addsi3 (reg3, reg2, treg));
+  emit_jump_insn (gen_tablejump_insn (reg3, table));
+  DONE;
+}")
+
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Prologue and Epilogue instructions
+;; ::
+;; ::::::::::::::::::::
+
+;; Called after register allocation to add any instructions needed for the
+;; prologue.  Using a prologue insn is favored compared to putting all of the
+;; instructions in the FUNCTION_PROLOGUE macro, since it allows the scheduler
+;; to intermix instructions with the saves of the caller saved registers.  In
+;; some cases, it might be necessary to emit a barrier instruction as the last
+;; insn to prevent such scheduling.
+(define_expand "prologue"
+  [(const_int 1)]
+  ""
+  "
+{
+  frv_expand_prologue ();
+  DONE;
+}")
+
+;; Called after register allocation to add any instructions needed for the
+;; epilogue.  Using a epilogue insn is favored compared to putting all of the
+;; instructions in the FUNCTION_EPILOGUE macro, since it allows the scheduler
+;; to intermix instructions with the restires of the caller saved registers.
+;; In some cases, it might be necessary to emit a barrier instruction as the
+;; first insn to prevent such scheduling.
+(define_expand "epilogue"
+  [(const_int 2)]
+  ""
+  "
+{
+  frv_expand_epilogue (FALSE);
+  DONE;
+}")
+
+;; This pattern, if defined, emits RTL for exit from a function without the final
+;; branch back to the calling function.  This pattern will be emitted before any
+;; sibling call (aka tail call) sites.
+;;
+;; The sibcall_epilogue pattern must not clobber any arguments used for
+;; parameter passing or any stack slots for arguments passed to the current
+;; function.
+(define_expand "sibcall_epilogue"
+  [(const_int 3)]
+  ""
+  "
+{
+  frv_expand_epilogue (TRUE);
+  DONE;
+}")
+
+;; Set up the pic register to hold the address of the pic table
+(define_insn "pic_prologue"
+  [(set (match_operand:SI 0 "integer_register_operand" "=d")
+        (unspec_volatile:SI [(const_int 0)] UNSPEC_PIC_PROLOGUE))
+   (clobber (match_operand:SI 1 "lr_operand" "=l"))
+   (clobber (match_operand:SI 2 "integer_register_operand" "=d"))]
+  ""
+  "*
+{
+  static int frv_pic_labelno = 0;
+
+  operands[3] = GEN_INT (frv_pic_labelno++);
+  return \"call %P3\\n%P3:\;movsg %1, %0\;sethi #gprelhi(%P3), %2\;setlo #gprello(%P3), %2\;sub %0,%2,%0\";
+}"
+  [(set_attr "length" "16")
+   (set_attr "type" "multi")])
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Miscellaneous instructions
+;; ::
+;; ::::::::::::::::::::
+
+;; No operation, needed in case the user uses -g but not -O.
+(define_insn "nop"
+  [(const_int 0)]
+  ""
+  "nop"
+  [(set_attr "length" "4")
+   (set_attr "type" "int")])
+
+;; Pseudo instruction that prevents the scheduler from moving code above this
+;; point.  Note, type unknown is used to make sure the VLIW instructions are
+;; not continued past this point.
+(define_insn "blockage"
+  [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)]
+  ""
+  "# blockage"
+  [(set_attr "length" "0")
+   (set_attr "type" "unknown")])
+\f
+;; ::::::::::::::::::::
+;; ::
+;; :: Media instructions
+;; ::
+;; ::::::::::::::::::::
+
+;; Unimplemented instructions:
+;;   - MCMPSH, MCMPUH
+
+(define_constants
+  [(UNSPEC_MLOGIC              100)
+   (UNSPEC_MNOT                        101)
+   (UNSPEC_MAVEH               102)
+   (UNSPEC_MSATH               103)
+   (UNSPEC_MADDH               104)
+   (UNSPEC_MQADDH              105)
+   (UNSPEC_MPACKH              106)
+   (UNSPEC_MUNPACKH            107)
+   (UNSPEC_MDPACKH             108)
+   (UNSPEC_MBTOH               109)
+   (UNSPEC_MHTOB               110)
+   (UNSPEC_MROT                        111)
+   (UNSPEC_MSHIFT              112)
+   (UNSPEC_MEXPDHW             113)
+   (UNSPEC_MEXPDHD             114)
+   (UNSPEC_MWCUT               115)
+   (UNSPEC_MMULH               116)
+   (UNSPEC_MMULXH              117)
+   (UNSPEC_MMACH               118)
+   (UNSPEC_MMRDH               119)
+   (UNSPEC_MQMULH              120)
+   (UNSPEC_MQMULXH             121)
+   (UNSPEC_MQMACH              122)
+   (UNSPEC_MCPX                        123)
+   (UNSPEC_MQCPX               124)
+   (UNSPEC_MCUT                        125)
+   (UNSPEC_MRDACC              126)
+   (UNSPEC_MRDACCG             127)
+   (UNSPEC_MWTACC              128)
+   (UNSPEC_MWTACCG             129)
+   (UNSPEC_MTRAP               130)
+   (UNSPEC_MCLRACC             131)
+   (UNSPEC_MCLRACCA            132)
+   (UNSPEC_MCOP1               133)
+   (UNSPEC_MCOP2               134)
+   (UNSPEC_MDUNPACKH           135)
+   (UNSPEC_MDUNPACKH_INTERNAL  136)
+   (UNSPEC_MBTOHE              137)
+   (UNSPEC_MBTOHE_INTERNAL     138)
+   (UNSPEC_MBTOHE              137)
+   (UNSPEC_MBTOHE_INTERNAL     138)
+   (UNSPEC_MQMACH2             139)
+   (UNSPEC_MADDACC             140)
+   (UNSPEC_MDADDACC            141)
+   (UNSPEC_MABSHS              142)
+   (UNSPEC_MDROTLI             143)
+   (UNSPEC_MCPLHI              144)
+   (UNSPEC_MCPLI               145)
+   (UNSPEC_MDCUTSSI            146)
+   (UNSPEC_MQSATHS             147)
+   (UNSPEC_MHSETLOS            148)
+   (UNSPEC_MHSETLOH            149)
+   (UNSPEC_MHSETHIS            150)
+   (UNSPEC_MHSETHIH            151)
+   (UNSPEC_MHDSETS             152)
+   (UNSPEC_MHDSETH             153)
+])
+
+;; Logic operations: type "mlogic"
+
+(define_expand "mand"
+  [(set (match_operand:SI 0 "fpr_operand" "")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "")
+                   (match_operand:SI 2 "fpr_operand" "")
+                   (match_dup 3)]
+                  UNSPEC_MLOGIC))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MAND);")
+
+(define_expand "mor"
+  [(set (match_operand:SI 0 "fpr_operand" "")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "")
+                   (match_operand:SI 2 "fpr_operand" "")
+                   (match_dup 3)]
+                  UNSPEC_MLOGIC))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MOR);")
+
+(define_expand "mxor"
+  [(set (match_operand:SI 0 "fpr_operand" "")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "")
+                   (match_operand:SI 2 "fpr_operand" "")
+                   (match_dup 3)]
+                  UNSPEC_MLOGIC))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MXOR);")
+
+(define_insn "*mlogic"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                   (match_operand:SI 2 "fpr_operand" "f")
+                   (match_operand:SI 3 "const_int_operand" "n")]
+                  UNSPEC_MLOGIC))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:              break;
+  case FRV_BUILTIN_MAND: return \"mand %1, %2, %0\";
+  case FRV_BUILTIN_MOR:  return \"mor %1, %2, %0\";
+  case FRV_BUILTIN_MXOR: return \"mxor %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mlogic\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mlogic")])
+
+(define_insn "*cond_exec_mlogic"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SI 2 "fpr_operand" "=f")
+         (unspec:SI [(match_operand:SI 3 "fpr_operand" "f")
+                    (match_operand:SI 4 "fpr_operand" "f")
+                    (match_operand:SI 5 "const_int_operand" "n")]
+                   UNSPEC_MLOGIC)))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[5]))
+  {
+  default:                 break;
+  case FRV_BUILTIN_MAND: return \"cmand %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MOR:  return \"cmor %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MXOR: return \"cmxor %3, %4, %2, %1, %e0\";
+  }
+
+  fatal_insn (\"Bad media insn, cond_exec_mlogic\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mlogic")])
+
+;; Logical not: type "mlogic"
+
+(define_insn "mnot"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")] UNSPEC_MNOT))]
+  "TARGET_MEDIA"
+  "mnot %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mlogic")])
+
+(define_insn "*cond_exec_mnot"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SI 2 "fpr_operand" "=f")
+         (unspec:SI [(match_operand:SI 3 "fpr_operand" "f")] UNSPEC_MNOT)))]
+  "TARGET_MEDIA"
+  "cmnot %3, %2, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mlogic")])
+
+;; Dual average (halfword): type "maveh"
+
+(define_insn "maveh"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")]
+                  UNSPEC_MAVEH))]
+  "TARGET_MEDIA"
+  "maveh %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "maveh")])
+
+;; Dual saturation (halfword): type "msath"
+
+(define_expand "msaths"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_dup 3)]
+                   UNSPEC_MSATH))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MSATHS);")
+
+(define_expand "msathu"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_dup 3)]
+                   UNSPEC_MSATH))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MSATHU);")
+
+(define_insn "*msath"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_operand:SI 3 "const_int_operand" "n")]
+                  UNSPEC_MSATH))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:                 break;
+  case FRV_BUILTIN_MSATHS:  return \"msaths %1, %2, %0\";
+  case FRV_BUILTIN_MSATHU:  return \"msathu %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, msath\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "msath")])
+
+;; Dual addition/subtraction with saturation (halfword): type "maddh"
+
+(define_expand "maddhss"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_dup 3)]
+                  UNSPEC_MADDH))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MADDHSS);")
+
+(define_expand "maddhus"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_dup 3)]
+                   UNSPEC_MADDH))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MADDHUS);")
+
+(define_expand "msubhss"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_dup 3)]
+                   UNSPEC_MADDH))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MSUBHSS);")
+
+(define_expand "msubhus"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_dup 3)]
+                   UNSPEC_MADDH))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MSUBHUS);")
+
+(define_insn "*maddh"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_operand:SI 3 "const_int_operand" "n")]
+                  UNSPEC_MADDH))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:                 break;
+  case FRV_BUILTIN_MADDHSS: return \"maddhss %1, %2, %0\";
+  case FRV_BUILTIN_MADDHUS: return \"maddhus %1, %2, %0\";
+  case FRV_BUILTIN_MSUBHSS: return \"msubhss %1, %2, %0\";
+  case FRV_BUILTIN_MSUBHUS: return \"msubhus %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, maddh\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "maddh")])
+
+(define_insn "*cond_exec_maddh"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SI 2 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 3 "fpr_operand" "f")
+                    (match_operand:SI 4 "fpr_operand" "f")
+                    (match_operand:SI 5 "const_int_operand" "n")]
+                   UNSPEC_MADDH)))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[5]))
+  {
+  default:                 break;
+  case FRV_BUILTIN_MADDHSS: return \"cmaddhss %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MADDHUS: return \"cmaddhus %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MSUBHSS: return \"cmsubhss %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MSUBHUS: return \"cmsubhus %3, %4, %2, %1, %e0\";
+  }
+
+  fatal_insn (\"Bad media insn, cond_exec_maddh\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "maddh")])
+
+;; Quad addition/subtraction with saturation (halfword): type "mqaddh"
+
+(define_expand "mqaddhss"
+  [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+                    (match_operand:DI 2 "even_fpr_operand" "h")
+                   (match_dup 3)]
+                  UNSPEC_MQADDH))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MQADDHSS);")
+
+(define_expand "mqaddhus"
+  [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+                    (match_operand:DI 2 "even_fpr_operand" "h")
+                   (match_dup 3)]
+                  UNSPEC_MQADDH))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MQADDHUS);")
+
+(define_expand "mqsubhss"
+  [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+                    (match_operand:DI 2 "even_fpr_operand" "h")
+                   (match_dup 3)]
+                  UNSPEC_MQADDH))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MQSUBHSS);")
+
+(define_expand "mqsubhus"
+  [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+                    (match_operand:DI 2 "even_fpr_operand" "h")
+                   (match_dup 3)]
+                  UNSPEC_MQADDH))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MQSUBHUS);")
+
+(define_insn "*mqaddh"
+  [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+                    (match_operand:DI 2 "even_fpr_operand" "h")
+                   (match_operand:SI 3 "const_int_operand" "n")]
+                  UNSPEC_MQADDH))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:                  break;
+  case FRV_BUILTIN_MQADDHSS: return \"mqaddhss %1, %2, %0\";
+  case FRV_BUILTIN_MQADDHUS: return \"mqaddhus %1, %2, %0\";
+  case FRV_BUILTIN_MQSUBHSS: return \"mqsubhss %1, %2, %0\";
+  case FRV_BUILTIN_MQSUBHUS: return \"mqsubhus %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mqaddh\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mqaddh")])
+
+(define_insn "*cond_exec_mqaddh"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:DI 2 "even_fpr_operand" "=h")
+         (unspec:DI [(match_operand:DI 3 "even_fpr_operand" "h")
+                     (match_operand:DI 4 "even_fpr_operand" "h")
+                    (match_operand:SI 5 "const_int_operand" "n")]
+                   UNSPEC_MQADDH)))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[5]))
+  {
+  default:                  break;
+  case FRV_BUILTIN_MQADDHSS: return \"cmqaddhss %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MQADDHUS: return \"cmqaddhus %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MQSUBHSS: return \"cmqsubhss %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MQSUBHUS: return \"cmqsubhus %3, %4, %2, %1, %e0\";
+  }
+
+  fatal_insn (\"Bad media insn, cond_exec_mqaddh\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mqaddh")])
+
+;; Pack halfword: type "mpackh"
+
+(define_insn "mpackh"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:HI 1 "fpr_operand" "f")
+                    (match_operand:HI 2 "fpr_operand" "f")]
+                  UNSPEC_MPACKH))]
+  "TARGET_MEDIA"
+  "mpackh %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mpackh")])
+
+;; Unpack halfword: type "mpackh"
+
+(define_insn "munpackh"
+  [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:SI 1 "fpr_operand" "f")]
+                  UNSPEC_MUNPACKH))]
+  "TARGET_MEDIA"
+  "munpackh %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "munpackh")])
+
+;; Dual pack halfword: type "mdpackh"
+
+(define_insn "mdpackh"
+    [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+         (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+                     (match_operand:DI 2 "even_fpr_operand" "h")]
+                    UNSPEC_MDPACKH))]
+  "TARGET_MEDIA"
+  "mdpackh %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mdpackh")])
+
+;; Byte-halfword conversion: type "mbhconv"
+
+(define_insn "mbtoh"
+  [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:SI 1 "fpr_operand" "f")]
+                  UNSPEC_MBTOH))]
+  "TARGET_MEDIA"
+  "mbtoh %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mbhconv")])
+
+(define_insn "*cond_exec_mbtoh"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:DI 2 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:SI 3 "fpr_operand" "f")]
+                   UNSPEC_MBTOH)))]
+  "TARGET_MEDIA"
+  "cmbtoh %3, %2, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mbhconv")])
+
+(define_insn "mhtob"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:DI 1 "even_fpr_operand" "h")]
+                  UNSPEC_MHTOB))]
+  "TARGET_MEDIA"
+  "mhtob %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mbhconv")])
+
+(define_insn "*cond_exec_mhtob"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SI 2 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:DI 3 "even_fpr_operand" "h")]
+                   UNSPEC_MHTOB)))]
+  "TARGET_MEDIA"
+  "cmhtob %3, %2, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mbhconv")])
+
+;; Rotate: type "mrot"
+
+(define_expand "mrotli"
+  [(set (match_operand:SI 0 "fpr_operand" "")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "")
+                    (match_operand:SI 2 "uint5_operand" "")
+                   (match_dup 3)]
+                  UNSPEC_MROT))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MROTLI);")
+
+(define_expand "mrotri"
+  [(set (match_operand:SI 0 "fpr_operand" "")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "")
+                    (match_operand:SI 2 "uint5_operand" "")
+                   (match_dup 3)]
+                  UNSPEC_MROT))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MROTRI);")
+
+(define_insn "*mrot"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "uint5_operand" "I")
+                   (match_operand:SI 3 "const_int_operand" "n")]
+                  UNSPEC_MROT))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:                break;
+  case FRV_BUILTIN_MROTLI: return \"mrotli %1, %2, %0\";
+  case FRV_BUILTIN_MROTRI: return \"mrotri %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mrot\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mrot")])
+
+;; Dual shift halfword: type "msh"
+
+(define_expand "msllhi"
+  [(set (match_operand:SI 0 "fpr_operand" "")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "")
+                    (match_operand:SI 2 "uint4_operand" "")
+                   (match_dup 3)]
+                  UNSPEC_MSHIFT))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MSLLHI);")
+
+(define_expand "msrlhi"
+  [(set (match_operand:SI 0 "fpr_operand" "")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "")
+                    (match_operand:SI 2 "uint4_operand" "")
+                   (match_dup 3)]
+                  UNSPEC_MSHIFT))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MSRLHI);")
+
+(define_expand "msrahi"
+  [(set (match_operand:SI 0 "fpr_operand" "")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "")
+                    (match_operand:SI 2 "uint4_operand" "")
+                   (match_dup 3)]
+                  UNSPEC_MSHIFT))]
+  "TARGET_MEDIA"
+  "operands[3] = GEN_INT (FRV_BUILTIN_MSRAHI);")
+
+(define_insn "*mshift"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "uint4_operand" "I")
+                   (match_operand:SI 3 "const_int_operand" "n")]
+                  UNSPEC_MSHIFT))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:                break;
+  case FRV_BUILTIN_MSLLHI: return \"msllhi %1, %2, %0\";
+  case FRV_BUILTIN_MSRLHI: return \"msrlhi %1, %2, %0\";
+  case FRV_BUILTIN_MSRAHI: return \"msrahi %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mshift\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mshift")])
+
+;; Expand halfword to word: type "mexpdhw"
+
+(define_insn "mexpdhw"
+  [(set (match_operand:SI 0 "even_fpr_operand" "=h")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "uint1_operand" "I")]
+                  UNSPEC_MEXPDHW))]
+  "TARGET_MEDIA"
+  "mexpdhw %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mexpdhw")])
+
+(define_insn "*cond_exec_mexpdhw"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:SI 2 "even_fpr_operand" "=h")
+        (unspec:SI [(match_operand:SI 3 "fpr_operand" "f")
+                    (match_operand:SI 4 "uint1_operand" "I")]
+                   UNSPEC_MEXPDHW)))]
+  "TARGET_MEDIA"
+  "cmexpdhw %3, %4, %2, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mexpdhw")])
+
+;; Expand halfword to double: type "mexpdhd"
+
+(define_insn "mexpdhd"
+  [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "uint1_operand" "I")]
+                  UNSPEC_MEXPDHD))]
+  "TARGET_MEDIA"
+  "mexpdhd %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mexpdhd")])
+
+(define_insn "*cond_exec_mexpdhd"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (set (match_operand:DI 2 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:SI 3 "fpr_operand" "f")
+                    (match_operand:SI 4 "uint1_operand" "I")]
+                   UNSPEC_MEXPDHD)))]
+  "TARGET_MEDIA"
+  "cmexpdhd %3, %4, %2, %1, %e0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mexpdhd")])
+
+;; FR cut: type "mwcut"
+
+(define_insn "mwcut"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:DI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_or_int6_operand" "fI")]
+                  UNSPEC_MWCUT))]
+  "TARGET_MEDIA"
+  "mwcut%i2 %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mwcut")])
+
+;; Dual multiplication (halfword): type "mmulh"
+
+(define_expand "mmulhs"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b")
+                  (unspec:DI [(match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MMULH))
+             (set (match_operand:HI 3 "accg_operand" "=B")
+                  (unspec:HI [(const_int 0)] UNSPEC_MMULH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MMULHS);")
+
+(define_expand "mmulhu"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b")
+                  (unspec:DI [(match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MMULH))
+             (set (match_operand:HI 3 "accg_operand" "=B")
+                  (unspec:HI [(const_int 0)] UNSPEC_MMULH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MMULHU);")
+
+(define_insn "*mmulh"
+  [(set (match_operand:DI 0 "even_acc_operand" "=b")
+        (unspec:DI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_operand:SI 3 "const_int_operand" "n")]
+                  UNSPEC_MMULH))
+   (set (match_operand:HI 4 "accg_operand" "=B")
+       (unspec:HI [(const_int 0)] UNSPEC_MMULH))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:                 break;
+  case FRV_BUILTIN_MMULHS:  return \"mmulhs %1, %2, %0\";
+  case FRV_BUILTIN_MMULHU:  return \"mmulhu %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mmulh\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mmulh")])
+
+(define_insn "*cond_exec_mmulh"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (parallel [(set (match_operand:DI 2 "even_acc_operand" "=b")
+                   (unspec:DI [(match_operand:SI 3 "fpr_operand" "f")
+                               (match_operand:SI 4 "fpr_operand" "f")
+                               (match_operand:SI 5 "const_int_operand" "n")]
+                              UNSPEC_MMULH))
+              (set (match_operand:HI 6 "accg_operand" "=B")
+                   (unspec:HI [(const_int 0)] UNSPEC_MMULH))]))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[5]))
+  {
+  default:                 break;
+  case FRV_BUILTIN_MMULHS:  return \"cmmulhs %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MMULHU:  return \"cmmulhu %3, %4, %2, %1, %e0\";
+  }
+
+  fatal_insn (\"Bad media insn, cond_exec_mmulh\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mmulh")])
+
+;; Dual cross multiplication (halfword): type "mmulxh"
+
+(define_expand "mmulxhs"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b")
+                  (unspec:DI [(match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MMULXH))
+             (set (match_operand:HI 3 "accg_operand" "=B")
+                  (unspec:HI [(const_int 0)] UNSPEC_MMULXH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MMULXHS);")
+
+(define_expand "mmulxhu"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b")
+                  (unspec:DI [(match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MMULXH))
+             (set (match_operand:HI 3 "accg_operand" "=B")
+                  (unspec:HI [(const_int 0)] UNSPEC_MMULXH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MMULXHU);")
+
+(define_insn "*mmulxh"
+  [(set (match_operand:DI 0 "even_acc_operand" "=b")
+        (unspec:DI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_operand:SI 3 "const_int_operand" "n")]
+                  UNSPEC_MMULXH))
+   (set (match_operand:HI 4 "accg_operand" "=B")
+       (unspec:HI [(const_int 0)] UNSPEC_MMULXH))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:                 break;
+  case FRV_BUILTIN_MMULXHS: return \"mmulxhs %1, %2, %0\";
+  case FRV_BUILTIN_MMULXHU: return \"mmulxhu %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mmulxh\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mmulxh")])
+
+;; Dual product-sum (halfword): type "mmach"
+
+(define_expand "mmachs"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "+b")
+                  (unspec:DI [(match_dup 0)
+                              (match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_operand:HI 3 "accg_operand" "+B")
+                              (match_dup 4)]
+                             UNSPEC_MMACH))
+             (set (match_dup 3)
+                  (unspec:HI [(const_int 0)] UNSPEC_MMACH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MMACHS);")
+
+(define_expand "mmachu"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "+b")
+                  (unspec:DI [(match_dup 0)
+                              (match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_operand:HI 3 "accg_operand" "+B")
+                              (match_dup 4)]
+                             UNSPEC_MMACH))
+             (set (match_dup 3)
+                  (unspec:HI [(const_int 0)] UNSPEC_MMACH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MMACHU);")
+
+(define_insn "*mmach"
+  [(set (match_operand:DI 0 "even_acc_operand" "+b")
+        (unspec:DI [(match_dup 0)
+                   (match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_operand:HI 3 "accg_operand" "+B")
+                   (match_operand:SI 4 "const_int_operand" "n")]
+                  UNSPEC_MMACH))
+   (set (match_dup 3) (unspec:HI [(const_int 0)] UNSPEC_MMACH))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[4]))
+  {
+  default:                break;
+  case FRV_BUILTIN_MMACHS: return \"mmachs %1, %2, %0\";
+  case FRV_BUILTIN_MMACHU: return \"mmachu %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mmach\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mmach")])
+
+(define_insn "*cond_exec_mmach"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (parallel [(set (match_operand:DI 2 "even_acc_operand" "+b")
+                   (unspec:DI [(match_dup 2)
+                               (match_operand:SI 3 "fpr_operand" "f")
+                               (match_operand:SI 4 "fpr_operand" "f")
+                               (match_operand:HI 5 "accg_operand" "+B")
+                               (match_operand:SI 6 "const_int_operand" "n")]
+                              UNSPEC_MMACH))
+              (set (match_dup 5)
+                   (unspec:HI [(const_int 0)] UNSPEC_MMACH))]))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[6]))
+  {
+  default:                break;
+  case FRV_BUILTIN_MMACHS: return \"cmmachs %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MMACHU: return \"cmmachu %3, %4, %2, %1, %e0\";
+  }
+
+  fatal_insn (\"Bad media insn, cond_exec_mmach\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mmach")])
+
+;; Dual product-difference: type "mmrdh"
+
+(define_expand "mmrdhs"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "+b")
+                  (unspec:DI [(match_dup 0)
+                              (match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_operand:HI 3 "accg_operand" "+B")
+                              (match_dup 4)]
+                             UNSPEC_MMRDH))
+             (set (match_dup 3)
+                  (unspec:HI [(const_int 0)] UNSPEC_MMRDH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MMRDHS);")
+
+(define_expand "mmrdhu"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "+b")
+                  (unspec:DI [(match_dup 0)
+                              (match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_operand:HI 3 "accg_operand" "+B")
+                              (match_dup 4)]
+                             UNSPEC_MMRDH))
+             (set (match_dup 3)
+                  (unspec:HI [(const_int 0)] UNSPEC_MMRDH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MMRDHU);")
+
+(define_insn "*mmrdh"
+  [(set (match_operand:DI 0 "even_acc_operand" "+b")
+        (unspec:DI [(match_dup 0)
+                   (match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")
+                   (match_operand:HI 3 "accg_operand" "+B")
+                   (match_operand:SI 4 "const_int_operand" "n")]
+                  UNSPEC_MMRDH))
+   (set (match_dup 3)
+       (unspec:HI [(const_int 0)] UNSPEC_MMRDH))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[4]))
+  {
+  default:                break;
+  case FRV_BUILTIN_MMRDHS: return \"mmrdhs %1, %2, %0\";
+  case FRV_BUILTIN_MMRDHU: return \"mmrdhu %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mrdh\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mmrdh")])
+
+;; Quad multiply (halfword): type "mqmulh"
+
+(define_expand "mqmulhs"
+  [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "=A")
+                  (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h")
+                                (match_operand:DI 2 "even_fpr_operand" "h")
+                                (match_dup 4)]
+                               UNSPEC_MQMULH))
+             (set (match_operand:V4QI 3 "accg_operand" "=B")
+                  (unspec:V4QI [(const_int 0)] UNSPEC_MQMULH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQMULHS);")
+
+(define_expand "mqmulhu"
+  [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "=A")
+                  (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h")
+                                (match_operand:DI 2 "even_fpr_operand" "h")
+                                (match_dup 4)]
+                               UNSPEC_MQMULH))
+             (set (match_operand:V4QI 3 "accg_operand" "=B")
+                  (unspec:V4QI [(const_int 0)] UNSPEC_MQMULH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQMULHU);")
+
+(define_insn "*mqmulh"
+  [(set (match_operand:V4SI 0 "quad_acc_operand" "=A")
+        (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h")
+                     (match_operand:DI 2 "even_fpr_operand" "h")
+                     (match_operand:SI 3 "const_int_operand" "n")]
+                    UNSPEC_MQMULH))
+   (set (match_operand:V4QI 4 "accg_operand" "=B")
+       (unspec:V4QI [(const_int 0)] UNSPEC_MQMULH))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:                  break;
+  case FRV_BUILTIN_MQMULHS:  return \"mqmulhs %1, %2, %0\";
+  case FRV_BUILTIN_MQMULHU:  return \"mqmulhu %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mqmulh\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mqmulh")])
+
+(define_insn "*cond_exec_mqmulh"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (parallel [(set (match_operand:V4SI 2 "quad_acc_operand" "=A")
+                   (unspec:V4SI [(match_operand:DI 3 "even_fpr_operand" "h")
+                                 (match_operand:DI 4 "even_fpr_operand" "h")
+                                 (match_operand:SI 5 "const_int_operand" "n")]
+                                UNSPEC_MQMULH))
+              (set (match_operand:V4QI 6 "accg_operand" "=B")
+                   (unspec:V4QI [(const_int 0)] UNSPEC_MQMULH))]))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[5]))
+  {
+  default:                  break;
+  case FRV_BUILTIN_MQMULHS:  return \"cmqmulhs %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MQMULHU:  return \"cmqmulhu %3, %4, %2, %1, %e0\";
+  }
+
+  fatal_insn (\"Bad media insn, cond_exec_mqmulh\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mqmulh")])
+
+;; Quad cross multiply (halfword): type "mqmulxh"
+
+(define_expand "mqmulxhs"
+  [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "=A")
+                  (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h")
+                                (match_operand:DI 2 "even_fpr_operand" "h")
+                                (match_dup 4)]
+                               UNSPEC_MQMULXH))
+             (set (match_operand:V4QI 3 "accg_operand" "=B")
+                  (unspec:V4QI [(const_int 0)] UNSPEC_MQMULXH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQMULXHS);")
+
+(define_expand "mqmulxhu"
+  [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "=A")
+                  (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h")
+                                (match_operand:DI 2 "even_fpr_operand" "h")
+                                (match_dup 4)]
+                               UNSPEC_MQMULXH))
+             (set (match_operand:V4QI 3 "accg_operand" "=B")
+                  (unspec:V4QI [(const_int 0)] UNSPEC_MQMULXH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQMULXHU);")
+
+(define_insn "*mqmulxh"
+  [(set (match_operand:V4SI 0 "quad_acc_operand" "=A")
+        (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h")
+                     (match_operand:DI 2 "even_fpr_operand" "h")
+                     (match_operand:SI 3 "const_int_operand" "n")]
+                    UNSPEC_MQMULXH))
+   (set (match_operand:V4QI 4 "accg_operand" "=B")
+       (unspec:V4QI [(const_int 0)] UNSPEC_MQMULXH))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:                  break;
+  case FRV_BUILTIN_MQMULXHS: return \"mqmulxhs %1, %2, %0\";
+  case FRV_BUILTIN_MQMULXHU: return \"mqmulxhu %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mqmulxh\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mqmulxh")])
+
+;; Quad product-sum (halfword): type "mqmach"
+
+(define_expand "mqmachs"
+  [(parallel [(set (match_operand:V4SI 0 "even_acc_operand" "+A")
+                  (unspec:V4SI [(match_dup 0)
+                                (match_operand:DI 1 "even_fpr_operand" "h")
+                                (match_operand:DI 2 "even_fpr_operand" "h")
+                                (match_operand:V4QI 3 "accg_operand" "+B")
+                                (match_dup 4)]
+                               UNSPEC_MQMACH))
+             (set (match_dup 3)
+                  (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQMACHS);")
+
+(define_expand "mqmachu"
+  [(parallel [(set (match_operand:V4SI 0 "even_acc_operand" "+A")
+                  (unspec:V4SI [(match_dup 0)
+                                (match_operand:DI 1 "even_fpr_operand" "h")
+                                (match_operand:DI 2 "even_fpr_operand" "h")
+                                (match_operand:V4QI 3 "accg_operand" "+B")
+                                (match_dup 4)]
+                               UNSPEC_MQMACH))
+             (set (match_dup 3)
+                  (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQMACHU);")
+
+(define_insn "*mqmach"
+  [(set (match_operand:V4SI 0 "even_acc_operand" "+A")
+        (unspec:V4SI [(match_dup 0)
+                     (match_operand:DI 1 "even_fpr_operand" "h")
+                     (match_operand:DI 2 "even_fpr_operand" "h")
+                     (match_operand:V4QI 3 "accg_operand" "+B")
+                     (match_operand:SI 4 "const_int_operand" "n")]
+                    UNSPEC_MQMACH))
+   (set (match_dup 3)
+       (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[4]))
+  {
+  default:                 break;
+  case FRV_BUILTIN_MQMACHS: return \"mqmachs %1, %2, %0\";
+  case FRV_BUILTIN_MQMACHU: return \"mqmachu %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mqmach\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mqmach")])
+
+(define_insn "*cond_exec_mqmach"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (parallel [(set (match_operand:V4SI 2 "even_acc_operand" "+A")
+                   (unspec:V4SI [(match_dup 2)
+                                 (match_operand:DI 3 "even_fpr_operand" "h")
+                                 (match_operand:DI 4 "even_fpr_operand" "h")
+                                 (match_operand:V4QI 5 "accg_operand" "+B")
+                                 (match_operand:SI 6 "const_int_operand" "n")]
+                                UNSPEC_MQMACH))
+              (set (match_dup 5)
+                   (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH))]))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[6]))
+  {
+  default:                 break;
+  case FRV_BUILTIN_MQMACHS: return \"cmqmachs %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MQMACHU: return \"cmqmachu %3, %4, %2, %1, %e0\";
+  }
+
+  fatal_insn (\"Bad media insn, cond_exec_mqmach\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mqmach")])
+
+;; Dual complex number product-sum (halfword)
+
+(define_expand "mcpxrs"
+  [(parallel [(set (match_operand:SI 0 "acc_operand" "=a")
+                  (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MCPX))
+             (set (match_operand:QI 3 "accg_operand" "=B")
+                  (unspec:QI [(const_int 0)] UNSPEC_MCPX))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MCPXRS);")
+
+(define_expand "mcpxru"
+  [(parallel [(set (match_operand:SI 0 "acc_operand" "=a")
+                  (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MCPX))
+             (set (match_operand:QI 3 "accg_operand" "=B")
+                  (unspec:QI [(const_int 0)] UNSPEC_MCPX))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MCPXRU);")
+
+(define_expand "mcpxis"
+  [(parallel [(set (match_operand:SI 0 "acc_operand" "=a")
+                  (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MCPX))
+             (set (match_operand:QI 3 "accg_operand" "=B")
+                  (unspec:QI [(const_int 0)] UNSPEC_MCPX))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MCPXIS);")
+
+(define_expand "mcpxiu"
+  [(parallel [(set (match_operand:SI 0 "acc_operand" "=a")
+                  (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MCPX))
+             (set (match_operand:QI 3 "accg_operand" "=B")
+                  (unspec:QI [(const_int 0)] UNSPEC_MCPX))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MCPXIU);")
+
+(define_insn "*mcpx"
+  [(parallel [(set (match_operand:SI 0 "acc_operand" "=a")
+                  (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                              (match_operand:SI 2 "fpr_operand" "f")
+                              (match_operand:SI 3 "const_int_operand" "n")]
+                             UNSPEC_MCPX))
+             (set (match_operand:QI 4 "accg_operand" "=B")
+                  (unspec:QI [(const_int 0)] UNSPEC_MCPX))])]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:                break;
+  case FRV_BUILTIN_MCPXRS: return \"mcpxrs %1, %2, %0\";
+  case FRV_BUILTIN_MCPXRU: return \"mcpxru %1, %2, %0\";
+  case FRV_BUILTIN_MCPXIS: return \"mcpxis %1, %2, %0\";
+  case FRV_BUILTIN_MCPXIU: return \"mcpxiu %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mcpx\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mcpx")])
+
+(define_insn "*cond_exec_mcpx"
+  [(cond_exec
+    (match_operator 0 "ccr_eqne_operator"
+                   [(match_operand 1 "cr_operand" "C")
+                    (const_int 0)])
+    (parallel [(set (match_operand:SI 2 "acc_operand" "=a")
+                   (unspec:SI [(match_operand:SI 3 "fpr_operand" "f")
+                               (match_operand:SI 4 "fpr_operand" "f")
+                               (match_operand:SI 5 "const_int_operand" "n")]
+                              UNSPEC_MCPX))
+              (set (match_operand:QI 6 "accg_operand" "=B")
+                   (unspec:QI [(const_int 0)] UNSPEC_MCPX))]))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[5]))
+  {
+  default:                break;
+  case FRV_BUILTIN_MCPXRS: return \"cmcpxrs %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MCPXRU: return \"cmcpxru %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MCPXIS: return \"cmcpxis %3, %4, %2, %1, %e0\";
+  case FRV_BUILTIN_MCPXIU: return \"cmcpxiu %3, %4, %2, %1, %e0\";
+  }
+
+  fatal_insn (\"Bad media insn, cond_exec_mcpx\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mcpx")])
+
+;; Quad complex number product-sum (halfword): type "mqcpx"
+
+(define_expand "mqcpxrs"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b")
+                  (unspec:DI [(match_operand:DI 1 "fpr_operand" "f")
+                              (match_operand:DI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MQCPX))
+             (set (match_operand:HI 3 "accg_operand" "=B")
+                  (unspec:HI [(const_int 0)] UNSPEC_MQCPX))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQCPXRS);")
+
+(define_expand "mqcpxru"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b")
+                  (unspec:DI [(match_operand:DI 1 "fpr_operand" "f")
+                              (match_operand:DI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MQCPX))
+             (set (match_operand:HI 3 "accg_operand" "=B")
+                  (unspec:HI [(const_int 0)] UNSPEC_MQCPX))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQCPXRU);")
+
+(define_expand "mqcpxis"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b")
+                  (unspec:DI [(match_operand:DI 1 "fpr_operand" "f")
+                              (match_operand:DI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MQCPX))
+             (set (match_operand:HI 3 "accg_operand" "=B")
+                  (unspec:HI [(const_int 0)] UNSPEC_MQCPX))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQCPXIS);")
+
+(define_expand "mqcpxiu"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b")
+                  (unspec:DI [(match_operand:DI 1 "fpr_operand" "f")
+                              (match_operand:DI 2 "fpr_operand" "f")
+                              (match_dup 4)]
+                             UNSPEC_MQCPX))
+             (set (match_operand:HI 3 "accg_operand" "=B")
+                  (unspec:HI [(const_int 0)] UNSPEC_MQCPX))])]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQCPXIU);")
+
+(define_insn "*mqcpx"
+  [(set (match_operand:DI 0 "even_acc_operand" "=b")
+        (unspec:DI [(match_operand:DI 1 "fpr_operand" "f")
+                    (match_operand:DI 2 "fpr_operand" "f")
+                   (match_operand:SI 3 "const_int_operand" "n")]
+                  UNSPEC_MQCPX))
+   (set (match_operand:HI 4 "accg_operand" "=B")
+       (unspec:HI [(const_int 0)] UNSPEC_MQCPX))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[3]))
+  {
+  default:                 break;
+  case FRV_BUILTIN_MQCPXRS: return \"mqcpxrs %1, %2, %0\";
+  case FRV_BUILTIN_MQCPXRU: return \"mqcpxru %1, %2, %0\";
+  case FRV_BUILTIN_MQCPXIS: return \"mqcpxis %1, %2, %0\";
+  case FRV_BUILTIN_MQCPXIU: return \"mqcpxiu %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mqcpx\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mqcpx")])
+
+;; Cut: type "mcut"
+
+(define_expand "mcut"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "acc_operand" "a")
+                    (match_operand:SI 2 "fpr_or_int6_operand" "fI")
+                   (match_operand:QI 3 "accg_operand" "B")
+                   (match_dup 4)]
+                  UNSPEC_MCUT))]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MCUT);")
+
+(define_expand "mcutss"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "acc_operand" "a")
+                    (match_operand:SI 2 "fpr_or_int6_operand" "fI")
+                   (match_operand:QI 3 "accg_operand" "B")
+                   (match_dup 4)]
+                  UNSPEC_MCUT))]
+  "TARGET_MEDIA"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MCUTSS);")
+
+(define_insn "*mcut"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "acc_operand" "a")
+                    (match_operand:SI 2 "fpr_or_int6_operand" "fI")
+                   (match_operand:QI 3 "accg_operand" "B")
+                   (match_operand:SI 4 "const_int_operand" "n")]
+                  UNSPEC_MCUT))]
+  "TARGET_MEDIA"
+  "*
+{
+  switch (INTVAL (operands[4]))
+  {
+  default:                break;
+  case FRV_BUILTIN_MCUT:   return \"mcut%i2 %1, %2, %0\";
+  case FRV_BUILTIN_MCUTSS: return \"mcutss%i2 %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mcut\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mcut")])
+
+;; Accumulator read: type "mrdacc"
+
+(define_insn "mrdacc"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+       (unspec:SI [(match_operand:SI 1 "acc_operand" "a")] UNSPEC_MRDACC))]
+  "TARGET_MEDIA"
+  "mrdacc %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mrdacc")])
+
+(define_insn "mrdaccg"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+       (unspec:SI [(match_operand:QI 1 "accg_operand" "B")] UNSPEC_MRDACCG))]
+  "TARGET_MEDIA"
+  "mrdaccg %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mrdacc")])
+
+;; Accumulator write: type "mwtacc"
+
+(define_insn "mwtacc"
+  [(set (match_operand:SI 0 "acc_operand" "=a")
+       (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")] UNSPEC_MWTACC))]
+  "TARGET_MEDIA"
+  "mwtacc %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mwtacc")])
+
+(define_insn "mwtaccg"
+  [(set (match_operand:QI 0 "accg_operand" "=B")
+       (unspec:QI [(match_operand:SI 1 "fpr_operand" "f")] UNSPEC_MWTACCG))]
+  "TARGET_MEDIA"
+  "mwtaccg %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mwtacc")])
+
+;; Trap: This one executes on the control unit, not the media units.
+
+(define_insn "mtrap"
+  [(unspec_volatile [(const_int 0)] UNSPEC_MTRAP)]
+  "TARGET_MEDIA"
+  "mtrap"
+  [(set_attr "length" "4")
+   (set_attr "type" "trap")])
+
+;; Clear single accumulator: type "mclracc"
+
+(define_insn "mclracc_internal"
+  [(set (match_operand:SI 0 "acc_operand" "=a")
+       (unspec:SI [(const_int 0)] UNSPEC_MCLRACC))
+   (set (match_operand:QI 1 "accg_operand" "=B")
+       (unspec:QI [(const_int 0)] UNSPEC_MCLRACC))]
+  "TARGET_MEDIA"
+  "mclracc %0,#0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mclracc")])
+
+(define_expand "mclracc"
+  [(parallel [(set (match_operand:SI 0 "acc_operand" "=a")
+                  (unspec:SI [(const_int 0)] UNSPEC_MCLRACC))
+             (set (match_dup 1)
+                  (unspec:QI [(const_int 0)] UNSPEC_MCLRACC))])]
+  "TARGET_MEDIA"
+  "
+{
+  if (GET_CODE (operands[0]) != REG || !ACC_P (REGNO (operands[0])))
+    FAIL;
+
+  operands[1] = frv_matching_accg_for_acc (operands[0]);
+}")
+
+;; Clear all accumulators: type "mclracca"
+
+(define_insn "mclracca8_internal"
+  [(set (match_operand:V4SI 0 "quad_acc_operand" "=b")
+       (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA))
+   (set (match_operand:V4SI 1 "quad_acc_operand" "=b")
+       (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA))
+   (set (match_operand:V4QI 2 "accg_operand" "=B")
+       (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA))
+   (set (match_operand:V4QI 3 "accg_operand" "=B")
+       (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA))]
+  "TARGET_MEDIA && TARGET_ACC_8"
+  "mclracc acc0,#1"
+  [(set_attr "length" "4")
+   (set_attr "type" "mclracca")])
+
+(define_insn "mclracca4_internal"
+  [(set (match_operand:V4SI 0 "quad_acc_operand" "=b")
+       (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA))
+   (set (match_operand:V4QI 1 "accg_operand" "=B")
+       (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA))]
+  "TARGET_MEDIA && TARGET_ACC_4"
+  "mclracc acc0,#1"
+  [(set_attr "length" "4")
+   (set_attr "type" "mclracca")])
+
+(define_expand "mclracca8"
+  [(parallel [(set (match_dup 0) (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA))
+             (set (match_dup 1) (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA))
+             (set (match_dup 2) (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA))
+             (set (match_dup 3) (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA))])]
+  "TARGET_MEDIA && TARGET_ACC_8"
+  "
+{
+  operands[0] = gen_rtx_REG (V4SImode, ACC_FIRST);
+  operands[1] = gen_rtx_REG (V4SImode, ACC_FIRST + 4);
+  operands[2] = gen_rtx_REG (V4QImode, ACCG_FIRST);
+  operands[3] = gen_rtx_REG (V4QImode, ACCG_FIRST + 4);
+}")
+
+(define_expand "mclracca4"
+  [(parallel [(set (match_dup 0) (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA))
+             (set (match_dup 1) (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA))])]
+  "TARGET_MEDIA && TARGET_ACC_4"
+  "
+{
+  operands[0] = gen_rtx_REG (V4SImode, ACC_FIRST);
+  operands[1] = gen_rtx_REG (V4QImode, ACCG_FIRST);
+}")
+
+(define_insn "mcop1"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")] UNSPEC_MCOP1))]
+  "TARGET_MEDIA_REV1"
+  "mcop1 %1, %2, %0"
+  [(set_attr "length" "4")
+;; What is the class of the insn ???
+   (set_attr "type" "multi")])
+
+(define_insn "mcop2"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
+                    (match_operand:SI 2 "fpr_operand" "f")] UNSPEC_MCOP2))]
+  "TARGET_MEDIA_REV1"
+  "mcop2 %1, %2, %0"
+  [(set_attr "length" "4")
+;; What is the class of the insn ???
+   (set_attr "type" "multi")])
+
+(define_insn "*mdunpackh_internal"
+  [(set (match_operand:V4SI 0 "quad_fpr_operand" "=x")
+        (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h")]
+                    UNSPEC_MDUNPACKH_INTERNAL))]
+  "TARGET_MEDIA_REV1"
+  "mdunpackh %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mdunpackh")])
+
+(define_insn_and_split "mdunpackh"
+  [(set (match_operand:V4SI 0 "memory_operand" "=o")
+        (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h")]
+                    UNSPEC_MDUNPACKH))
+   (clobber (match_scratch:V4SI 2 "=x"))]
+  "TARGET_MEDIA_REV1"
+  "#"
+  "reload_completed"
+  [(set (match_dup 2)
+       (unspec:V4SI [(match_dup 1)] UNSPEC_MDUNPACKH_INTERNAL))
+   (set (match_dup 3)
+       (match_dup 4))
+   (set (match_dup 5)
+       (match_dup 6))]
+  "
+{
+  operands[3] = change_address (operands[0], DImode, NULL_RTX);
+  operands[4] = gen_rtx_REG (DImode, REGNO (operands[2]));
+  operands[5] = frv_index_memory (operands[0], DImode, 1);
+  operands[6] = gen_rtx_REG (DImode, REGNO (operands[2])+2);
+}"
+  [(set_attr "length" "20")
+   (set_attr "type" "multi")])
+
+(define_insn "*mbtohe_internal"
+  [(set (match_operand:V4SI 0 "quad_fpr_operand" "=x")
+        (unspec:V4SI [(match_operand:SI 1 "fpr_operand" "f")]
+                    UNSPEC_MBTOHE_INTERNAL))]
+  "TARGET_MEDIA_REV1"
+  "mbtohe %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mbhconve")])
+
+(define_insn_and_split "mbtohe"
+  [(set (match_operand:V4SI 0 "memory_operand" "=o")
+        (unspec:V4SI [(match_operand:SI 1 "fpr_operand" "f")]
+                    UNSPEC_MBTOHE))
+   (clobber (match_scratch:V4SI 2 "=x"))]
+  "TARGET_MEDIA_REV1"
+  "#"
+  "reload_completed"
+  [(set (match_dup 2)
+       (unspec:V4SI [(match_dup 1)] UNSPEC_MBTOHE_INTERNAL))
+   (set (match_dup 3)
+       (match_dup 4))
+   (set (match_dup 5)
+       (match_dup 6))]
+  "
+{
+  operands[3] = change_address (operands[0], DImode, NULL_RTX);
+  operands[4] = gen_rtx_REG (DImode, REGNO (operands[2]));
+  operands[5] = frv_index_memory (operands[0], DImode, 1);
+  operands[6] = gen_rtx_REG (DImode, REGNO (operands[2])+2);
+}"
+  [(set_attr "length" "20")
+   (set_attr "type" "multi")])
+
+;; Quad product-sum (halfword) instructions only found on the FR400.
+;; type "mqmach"
+
+(define_expand "mqxmachs"
+  [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "")
+                  (unspec:V4SI [(match_dup 0)
+                                (match_operand:DI 1 "even_fpr_operand" "")
+                                (match_operand:DI 2 "even_fpr_operand" "")
+                                (match_operand:V4QI 3 "accg_operand" "")
+                                (match_dup 4)]
+                               UNSPEC_MQMACH2))
+               (set (match_dup 3)
+                    (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH2))])]
+  "TARGET_MEDIA_REV2"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQXMACHS);")
+
+(define_expand "mqxmacxhs"
+  [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "")
+                  (unspec:V4SI [(match_dup 0)
+                                (match_operand:DI 1 "even_fpr_operand" "")
+                                (match_operand:DI 2 "even_fpr_operand" "")
+                                (match_operand:V4QI 3 "accg_operand" "")
+                                (match_dup 4)]
+                               UNSPEC_MQMACH2))
+             (set (match_dup 3)
+                  (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH2))])]
+  "TARGET_MEDIA_REV2"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQXMACXHS);")
+
+(define_expand "mqmacxhs"
+  [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "")
+                  (unspec:V4SI [(match_dup 0)
+                                (match_operand:DI 1 "even_fpr_operand" "")
+                                (match_operand:DI 2 "even_fpr_operand" "")
+                                (match_operand:V4QI 3 "accg_operand" "")
+                                (match_dup 4)]
+                               UNSPEC_MQMACH2))
+             (set (match_dup 3)
+                  (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH2))])]
+  "TARGET_MEDIA_REV2"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MQMACXHS);")
+
+(define_insn "*mqmach2"
+  [(set (match_operand:V4SI 0 "quad_acc_operand" "+A")
+        (unspec:V4SI [(match_dup 0)
+                     (match_operand:DI 1 "even_fpr_operand" "h")
+                     (match_operand:DI 2 "even_fpr_operand" "h")
+                     (match_operand:V4QI 3 "accg_operand" "+B")
+                     (match_operand:SI 4 "const_int_operand" "n")]
+                    UNSPEC_MQMACH2))
+   (set (match_dup 3)
+       (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH2))]
+  "TARGET_MEDIA_REV2"
+  "*
+{
+  switch (INTVAL (operands[4]))
+  {
+  default:                   break;
+  case FRV_BUILTIN_MQXMACHS:  return \"mqxmachs %1, %2, %0\";
+  case FRV_BUILTIN_MQXMACXHS: return \"mqxmacxhs %1, %2, %0\";
+  case FRV_BUILTIN_MQMACXHS:  return \"mqmacxhs %1, %2, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mqmach2\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mqmach")])
+
+;; Accumulator addition/subtraction: type "maddacc"
+
+(define_expand "maddaccs"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "")
+                  (unspec:DI [(match_dup 0)
+                              (match_operand:DI 1 "even_acc_operand" "")]
+                             UNSPEC_MADDACC))
+             (set (match_operand:HI 2 "accg_operand" "")
+                  (unspec:HI [(match_dup 2)
+                              (match_operand:HI 3 "accg_operand" "")
+                              (match_dup 4)]
+                             UNSPEC_MADDACC))])]
+  "TARGET_MEDIA_REV2"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MADDACCS);")
+
+(define_expand "msubaccs"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "")
+                  (unspec:DI [(match_dup 0)
+                              (match_operand:DI 1 "even_acc_operand" "")]
+                             UNSPEC_MADDACC))
+             (set (match_operand:HI 2 "accg_operand" "")
+                  (unspec:HI [(match_dup 2)
+                              (match_operand:HI 3 "accg_operand" "")
+                              (match_dup 4)]
+                             UNSPEC_MADDACC))])]
+  "TARGET_MEDIA_REV2"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MSUBACCS);")
+
+(define_expand "masaccs"
+  [(parallel [(set (match_operand:DI 0 "even_acc_operand" "")
+                  (unspec:DI [(match_dup 0)
+                              (match_operand:DI 1 "even_acc_operand" "")]
+                             UNSPEC_MADDACC))
+             (set (match_operand:HI 2 "accg_operand" "")
+                  (unspec:HI [(match_dup 2)
+                              (match_operand:HI 3 "accg_operand" "")
+                              (match_dup 4)]
+                             UNSPEC_MADDACC))])]
+  "TARGET_MEDIA_REV2"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MASACCS);")
+
+(define_insn "*maddacc"
+  [(set (match_operand:DI 0 "even_acc_operand" "+b")
+       (unspec:DI [(match_dup 0)
+                   (match_operand:DI 1 "even_acc_operand" "b")]
+                  UNSPEC_MADDACC))
+   (set (match_operand:HI 2 "accg_operand" "+B")
+       (unspec:HI [(match_dup 2)
+                   (match_operand:HI 3 "accg_operand" "B")
+                   (match_operand:SI 4 "const_int_operand" "n")]
+                  UNSPEC_MADDACC))]
+  "TARGET_MEDIA_REV2"
+  "*
+{
+  switch (INTVAL (operands[4]))
+  {
+  default:                  break;
+  case FRV_BUILTIN_MADDACCS: return \"maddaccs %1, %0\";
+  case FRV_BUILTIN_MSUBACCS: return \"msubaccs %1, %0\";
+  case FRV_BUILTIN_MASACCS:  return \"masaccs %1, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, maddacc\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "maddacc")])
+
+;; Dual accumulator addition/subtraction: type "mdaddacc"
+
+(define_expand "mdaddaccs"
+  [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "")
+                  (unspec:V4SI [(match_dup 0)
+                                (match_operand:V4SI 1 "quad_acc_operand" "")]
+                               UNSPEC_MDADDACC))
+             (set (match_operand:V4QI 2 "accg_operand" "")
+                  (unspec:V4QI [(match_dup 2)
+                                (match_operand:V4QI 3 "accg_operand" "")
+                                (match_dup 4)]
+                               UNSPEC_MDADDACC))])]
+  "TARGET_MEDIA_REV2"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MDADDACCS);")
+
+(define_expand "mdsubaccs"
+  [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "")
+                  (unspec:V4SI [(match_dup 0)
+                                (match_operand:V4SI 1 "quad_acc_operand" "")]
+                               UNSPEC_MDADDACC))
+             (set (match_operand:V4QI 2 "accg_operand" "")
+                  (unspec:V4QI [(match_dup 2)
+                                (match_operand:V4QI 3 "accg_operand" "")
+                                (match_dup 4)]
+                               UNSPEC_MDADDACC))])]
+  "TARGET_MEDIA_REV2"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MDSUBACCS);")
+
+(define_expand "mdasaccs"
+  [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "")
+                  (unspec:V4SI [(match_dup 0)
+                                (match_operand:V4SI 1 "quad_acc_operand" "")]
+                               UNSPEC_MDADDACC))
+             (set (match_operand:V4QI 2 "accg_operand" "")
+                  (unspec:V4QI [(match_dup 2)
+                                (match_operand:V4QI 3 "accg_operand" "")
+                                (match_dup 4)]
+                               UNSPEC_MDADDACC))])]
+  "TARGET_MEDIA_REV2"
+  "operands[4] = GEN_INT (FRV_BUILTIN_MDASACCS);")
+
+(define_insn "*mdaddacc"
+  [(set (match_operand:V4SI 0 "quad_acc_operand" "+A")
+       (unspec:V4SI [(match_dup 0)
+                     (match_operand:V4SI 1 "quad_acc_operand" "A")]
+                    UNSPEC_MDADDACC))
+   (set (match_operand:V4QI 2 "accg_operand" "+B")
+       (unspec:V4QI [(match_dup 2)
+                     (match_operand:V4QI 3 "accg_operand" "B")
+                     (match_operand:SI 4 "const_int_operand" "n")]
+                    UNSPEC_MDADDACC))]
+  "TARGET_MEDIA_REV2"
+  "*
+{
+  switch (INTVAL (operands[4]))
+  {
+  default:                   break;
+  case FRV_BUILTIN_MDADDACCS: return \"mdaddaccs %1, %0\";
+  case FRV_BUILTIN_MDSUBACCS: return \"mdsubaccs %1, %0\";
+  case FRV_BUILTIN_MDASACCS:  return \"mdasaccs %1, %0\";
+  }
+
+  fatal_insn (\"Bad media insn, mdaddacc\", insn);
+}"
+  [(set_attr "length" "4")
+   (set_attr "type" "mdaddacc")])
+
+;; Dual absolute (halfword): type "mabsh"
+
+(define_insn "mabshs"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")] UNSPEC_MABSHS))]
+  "TARGET_MEDIA_REV2"
+  "mabshs %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mabsh")])
+
+;; Dual rotate: type "mdrot"
+
+(define_insn "mdrotli"
+  [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+                   (match_operand:SI 2 "uint5_operand" "I")]
+                  UNSPEC_MDROTLI))]
+  "TARGET_MEDIA_REV2"
+  "mdrotli %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mdrot")])
+
+;; Dual coupling (concatenation): type "mcpl"
+
+(define_insn "mcplhi"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:DI 1 "fpr_operand" "h")
+                   (match_operand:SI 2 "uint4_operand" "I")]
+                  UNSPEC_MCPLHI))]
+  "TARGET_MEDIA_REV2"
+  "mcplhi %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mcpl")])
+
+(define_insn "mcpli"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+        (unspec:SI [(match_operand:DI 1 "fpr_operand" "h")
+                   (match_operand:SI 2 "uint5_operand" "I")]
+                  UNSPEC_MCPLI))]
+  "TARGET_MEDIA_REV2"
+  "mcpli %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mcpl")])
+
+;; Dual cut: type "mdcut"
+
+(define_insn "mdcutssi"
+  [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:DI 1 "even_acc_operand" "b")
+                   (match_operand:SI 2 "int6_operand" "I")
+                   (match_operand:HI 3 "accg_operand" "B")]
+                  UNSPEC_MDCUTSSI))]
+  "TARGET_MEDIA_REV2"
+  "mdcutssi %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mdcut")])
+
+;; Quad saturate (halfword): type "mqsath"
+
+(define_insn "mqsaths"
+  [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+        (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+                   (match_operand:DI 2 "even_fpr_operand" "h")]
+                  UNSPEC_MQSATHS))]
+  "TARGET_MEDIA_REV2"
+  "mqsaths %1, %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mqsath")])
+
+;; Set hi/lo instrctions: type "mset"
+
+(define_insn "mhsetlos"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+       (unspec:SI [(match_operand:SI 1 "fpr_operand" "0")
+                   (match_operand:SI 2 "int12_operand" "NOP")]
+                  UNSPEC_MHSETLOS))]
+  "TARGET_MEDIA_REV2"
+  "mhsetlos %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mset")])
+
+(define_insn "mhsetloh"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+       (unspec:SI [(match_operand:SI 1 "fpr_operand" "0")
+                   (match_operand:SI 2 "int5_operand" "I")]
+                  UNSPEC_MHSETLOH))]
+  "TARGET_MEDIA_REV2"
+  "mhsetloh %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mset")])
+
+(define_insn "mhsethis"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+       (unspec:SI [(match_operand:SI 1 "fpr_operand" "0")
+                   (match_operand:SI 2 "int12_operand" "NOP")]
+                  UNSPEC_MHSETHIS))]
+  "TARGET_MEDIA_REV2"
+  "mhsethis %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mset")])
+
+(define_insn "mhsethih"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+       (unspec:SI [(match_operand:SI 1 "fpr_operand" "0")
+                   (match_operand:SI 2 "int5_operand" "I")]
+                  UNSPEC_MHSETHIH))]
+  "TARGET_MEDIA_REV2"
+  "mhsethih %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mset")])
+
+(define_insn "mhdsets"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+       (unspec:SI [(match_operand:SI 1 "int12_operand" "NOP")]
+                  UNSPEC_MHDSETS))]
+  "TARGET_MEDIA_REV2"
+  "mhdsets %1, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mset")])
+
+(define_insn "mhdseth"
+  [(set (match_operand:SI 0 "fpr_operand" "=f")
+       (unspec:SI [(match_operand:SI 1 "fpr_operand" "0")
+                   (match_operand:SI 2 "int5_operand" "I")]
+                  UNSPEC_MHDSETH))]
+  "TARGET_MEDIA_REV2"
+  "mhdseth %2, %0"
+  [(set_attr "length" "4")
+   (set_attr "type" "mset")])
diff --git a/gcc/config/frv/frvbegin.c b/gcc/config/frv/frvbegin.c
new file mode 100644 (file)
index 0000000..a5f5b1f
--- /dev/null
@@ -0,0 +1,150 @@
+/* Frv initialization file linked before all user modules
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+    Contributed by Red Hat, Inc.
+  
+   This file is part of GNU CC.
+  
+   GNU CC is free software ; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation * either version 2, or (at your option)
+   any later version.
+  
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY ; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+  
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   This file was originally taken from the file crtstuff.c in the
+   main compiler directory, and simplified. */
+
+#include "defaults.h"
+#include <stddef.h>
+#include "unwind-dw2-fde.h"
+#include "gbl-ctors.h"
+
+/*  Declare a pointer to void function type.  */
+#define STATIC static
+
+#ifdef __FRV_UNDERSCORE__
+#define UNDERSCORE "_"
+#else
+#define UNDERSCORE ""
+#endif
+
+#define INIT_SECTION_NEG_ONE(SECTION, FLAGS, NAME)                     \
+__asm__ (".section " SECTION "," FLAGS "\n\t"                          \
+        ".globl   " UNDERSCORE NAME "\n\t"                             \
+        ".type    " UNDERSCORE NAME ",@object\n\t"                     \
+        ".p2align  2\n"                                                \
+        UNDERSCORE NAME ":\n\t"                                        \
+        ".word     -1\n\t"                                             \
+        ".previous")
+
+#define INIT_SECTION(SECTION, FLAGS, NAME)                             \
+__asm__ (".section " SECTION "," FLAGS "\n\t"                          \
+        ".globl   " UNDERSCORE NAME "\n\t"                             \
+        ".type    " UNDERSCORE NAME ",@object\n\t"                     \
+        ".p2align  2\n"                                                \
+        UNDERSCORE NAME ":\n\t"                                        \
+        ".previous")
+
+/* Beginning of .ctor/.dtor sections that provides a list of constructors and
+   destructors to run.  */
+
+INIT_SECTION_NEG_ONE (".ctors", "\"aw\"", "__CTOR_LIST__");
+INIT_SECTION_NEG_ONE (".dtors", "\"aw\"", "__DTOR_LIST__");
+
+/* Beginning of .eh_frame section that provides all of the exception handling
+   tables.  */
+
+INIT_SECTION (".eh_frame", "\"aw\"", "__EH_FRAME_BEGIN__");
+
+/* Beginning of .rofixup section that provides a list of pointers that we
+   need to adjust.  */
+
+INIT_SECTION (".rofixup", "\"a\"", "__ROFIXUP_LIST__");
+
+extern void __frv_register_eh(void) __attribute__((__constructor__));
+extern void __frv_deregister_eh(void) __attribute__((__destructor__));
+
+extern func_ptr __EH_FRAME_BEGIN__[];
+
+/* Register the exeception handling table as the first constructor */
+void
+__frv_register_eh (void)
+{
+  static struct object object;
+  if (__register_frame_info)
+    __register_frame_info (__EH_FRAME_BEGIN__, &object);
+}
+
+/* Note, do not declare __{,de}register_frame_info weak as it seems
+   to interfere with the pic support.  */
+
+/* Unregister the exeception handling table as a deconstructor */
+void
+__frv_deregister_eh (void)
+{
+  static int completed = 0;
+
+  if (completed)
+    return;
+
+  if (__deregister_frame_info)
+    __deregister_frame_info (__EH_FRAME_BEGIN__);
+
+  completed = 1;
+}
+
+/* Run the global destructors */
+void
+__do_global_dtors ()
+{
+  static func_ptr *p = __DTOR_LIST__ + 1;
+  while (*p)
+    {
+      p++;
+      (*(p-1)) ();
+    }
+}
+
+/* Run the global constructors */
+void
+__do_global_ctors ()
+{
+  unsigned long nptrs = (unsigned long) __CTOR_LIST__[0];
+  unsigned i;
+
+  if (nptrs == (unsigned long)-1)
+    for (nptrs = 0; __CTOR_LIST__[nptrs + 1] != 0; nptrs++);
+
+  for (i = nptrs; i >= 1; i--)
+    __CTOR_LIST__[i] ();
+
+  atexit (__do_global_dtors);
+}
+
+/* Subroutine called automatically by `main'.
+   Compiling a global function named `main'
+   produces an automatic call to this function at the beginning.
+
+   For many systems, this routine calls __do_global_ctors.
+   For systems which support a .init section we use the .init section
+   to run __do_global_ctors, so we need not do anything here.  */
+
+void
+__main ()
+{
+  /* Support recursive calls to `main': run initializers just once.  */
+  static int initialized;
+  if (! initialized)
+    {
+      initialized = 1;
+      __do_global_ctors ();
+    }
+}
diff --git a/gcc/config/frv/frvend.c b/gcc/config/frv/frvend.c
new file mode 100644 (file)
index 0000000..f1635cc
--- /dev/null
@@ -0,0 +1,63 @@
+/* Frv initialization file linked after all user modules
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+    Contributed by Red Hat, Inc.
+  
+   This file is part of GNU CC.
+  
+   GNU CC is free software ; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation * either version 2, or (at your option)
+   any later version.
+  
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY ; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+  
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#include "defaults.h"
+#include <stddef.h>
+#include "unwind-dw2-fde.h"
+
+#ifdef __FRV_UNDERSCORE__
+#define UNDERSCORE "_"
+#else
+#define UNDERSCORE ""
+#endif
+
+#define FINI_SECTION_ZERO(SECTION, FLAGS, NAME)                                \
+__asm__ (".section " SECTION "," FLAGS "\n\t"                          \
+        ".globl   " UNDERSCORE NAME "\n\t"                             \
+        ".type    " UNDERSCORE NAME ",@object\n\t"                     \
+        ".p2align  2\n"                                                \
+        UNDERSCORE NAME ":\n\t"                                        \
+        ".word     0\n\t"                                              \
+        ".previous")
+
+#define FINI_SECTION(SECTION, FLAGS, NAME)                             \
+__asm__ (".section " SECTION "," FLAGS "\n\t"                          \
+        ".globl   " UNDERSCORE NAME "\n\t"                             \
+        ".type    " UNDERSCORE NAME ",@object\n\t"                     \
+        ".p2align  2\n"                                                \
+        UNDERSCORE NAME ":\n\t"                                        \
+        ".previous")
+
+/* End of .ctor/.dtor sections that provides a list of constructors and
+   destructors to run.  */
+
+FINI_SECTION_ZERO (".ctors", "\"aw\"", "__CTOR_END__");
+FINI_SECTION_ZERO (".dtors", "\"aw\"", "__DTOR_END__");
+
+/* End of .eh_frame section that provides all of the exception handling
+   tables.  */
+
+FINI_SECTION_ZERO (".eh_frame", "\"aw\"", "__FRAME_END__");
+
+/* End of .rofixup section that provides a list of pointers that we
+   need to adjust.  */
+
+FINI_SECTION (".rofixup", "\"a\"", "__ROFIXUP_END__");
diff --git a/gcc/config/frv/lib1funcs.asm b/gcc/config/frv/lib1funcs.asm
new file mode 100644 (file)
index 0000000..18a8142
--- /dev/null
@@ -0,0 +1,275 @@
+/* Library functions.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   Contributed by Red Hat, Inc.
+  
+   This file is part of GNU CC.
+  
+   GNU CC is free software ; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation * either version 2, or (at your option)
+   any later version.
+  
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY ; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+  
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <frv-asm.h>
+
+\f
+#ifdef L_cmpll
+/* icc0 = __cmpll (long long a, long long b)  */
+
+       .file   "_cmpll.s"
+       .globl  EXT(__cmpll)
+       .type   EXT(__cmpll),@function
+       .text
+       .p2align 4
+EXT(__cmpll):
+       cmp     gr8, gr10, icc0
+       ckeq    icc0, cc4
+       P(ccmp) gr9, gr11, cc4, 1
+       ret
+.Lend:
+       .size   EXT(__cmpll),.Lend-EXT(__cmpll)
+#endif /* L_cmpll */
+\f
+#ifdef L_cmpf
+/* icc0 = __cmpf (float a, float b) */
+/* Note, because this function returns the result in ICC0, it means it can't
+   handle NaNs.  */
+
+       .file   "_cmpf.s"
+       .globl  EXT(__cmpf)
+       .type   EXT(__cmpf),@function
+       .text
+       .p2align 4
+EXT(__cmpf):
+#ifdef __FRV_HARD_FLOAT__      /* floating point instructions available */
+       movgf   gr8, fr0
+       P(movgf) gr9, fr1
+       setlos  #1, gr8
+       fcmps   fr0, fr1, fcc0
+       P(fcklt) fcc0, cc0
+       fckeq   fcc0, cc1
+       csub    gr0, gr8, gr8, cc0, 1
+       cmov    gr0, gr8, cc1, 1
+       cmpi    gr8, 0, icc0
+       ret
+#else                          /* no floating point instructions available */
+       movsg   lr, gr4
+       addi    sp, #-16, sp
+       sti     gr4, @(sp, 8)
+       st      fp, @(sp, gr0)
+       mov     sp, fp
+       call    EXT(__cmpsf2)
+       cmpi    gr8, #0, icc0
+       ldi     @(sp, 8), gr4
+       movgs   gr4, lr
+       ld      @(sp,gr0), fp
+       addi    sp, #16, sp
+       ret
+#endif
+.Lend:
+       .size   EXT(__cmpf),.Lend-EXT(__cmpf)
+#endif
+\f
+#ifdef L_cmpd
+/* icc0 = __cmpd (double a, double b) */
+/* Note, because this function returns the result in ICC0, it means it can't
+   handle NaNs.  */
+
+       .file   "_cmpd.s"
+       .globl  EXT(__cmpd)
+       .type   EXT(__cmpd),@function
+       .text
+       .p2align 4
+EXT(__cmpd):
+       movsg   lr, gr4
+       addi    sp, #-16, sp
+       sti     gr4, @(sp, 8)
+       st      fp, @(sp, gr0)
+       mov     sp, fp
+       call    EXT(__cmpdf2)
+       cmpi    gr8, #0, icc0
+       ldi     @(sp, 8), gr4
+       movgs   gr4, lr
+       ld      @(sp,gr0), fp
+       addi    sp, #16, sp
+       ret
+.Lend:
+       .size   EXT(__cmpd),.Lend-EXT(__cmpd)
+#endif
+\f
+#ifdef L_addll
+/* gr8,gr9 = __addll (long long a, long long b) */
+/* Note, gcc will never call this function, but it is present in case an
+   ABI program calls it.  */
+
+       .file   "_addll.s"
+       .globl  EXT(__addll)
+       .type   EXT(__addll),@function
+       .text
+       .p2align
+EXT(__addll):
+       addcc   gr9, gr11, gr9, icc0
+       addx    gr8, gr10, gr8, icc0
+       ret
+.Lend:
+       .size   EXT(__addll),.Lend-EXT(__addll)
+#endif
+\f
+#ifdef L_subll
+/* gr8,gr9 = __subll (long long a, long long b) */
+/* Note, gcc will never call this function, but it is present in case an
+   ABI program calls it.  */
+
+       .file   "_subll.s"
+       .globl  EXT(__subll)
+       .type   EXT(__subll),@function
+       .text
+       .p2align 4
+EXT(__subll):
+       subcc   gr9, gr11, gr9, icc0
+       subx    gr8, gr10, gr8, icc0
+       ret
+.Lend:
+       .size   EXT(__subll),.Lend-EXT(__subll)
+#endif
+\f
+#ifdef L_andll
+/* gr8,gr9 = __andll (long long a, long long b) */
+/* Note, gcc will never call this function, but it is present in case an
+   ABI program calls it.  */
+
+       .file   "_andll.s"
+       .globl  EXT(__andll)
+       .type   EXT(__andll),@function
+       .text
+       .p2align 4
+EXT(__andll):
+       P(and)  gr9, gr11, gr9
+       P2(and) gr8, gr10, gr8
+       ret
+.Lend:
+       .size   EXT(__andll),.Lend-EXT(__andll)
+#endif
+\f
+#ifdef L_orll
+/* gr8,gr9 = __orll (long long a, long long b) */
+/* Note, gcc will never call this function, but it is present in case an
+   ABI program calls it.  */
+
+       .file   "_orll.s"
+       .globl  EXT(__orll)
+       .type   EXT(__orll),@function
+       .text
+       .p2align 4
+EXT(__orll):
+       P(or)   gr9, gr11, gr9
+       P2(or)  gr8, gr10, gr8
+       ret
+.Lend:
+       .size   EXT(__orll),.Lend-EXT(__orll)
+#endif
+\f
+#ifdef L_xorll
+/* gr8,gr9 = __xorll (long long a, long long b) */
+/* Note, gcc will never call this function, but it is present in case an
+   ABI program calls it.  */
+
+       .file   "_xorll.s"
+       .globl  EXT(__xorll)
+       .type   EXT(__xorll),@function
+       .text
+       .p2align 4
+EXT(__xorll):
+       P(xor)  gr9, gr11, gr9
+       P2(xor) gr8, gr10, gr8
+       ret
+.Lend:
+       .size   EXT(__xorll),.Lend-EXT(__xorll)
+#endif
+\f
+#ifdef L_notll
+/* gr8,gr9 = __notll (long long a) */
+/* Note, gcc will never call this function, but it is present in case an
+   ABI program calls it.  */
+
+       .file   "_notll.s"
+       .globl  EXT(__notll)
+       .type   EXT(__notll),@function
+       .text
+       .p2align 4
+EXT(__notll):
+       P(not)  gr9, gr9
+       P2(not) gr8, gr8
+       ret
+.Lend:
+       .size   EXT(__notll),.Lend-EXT(__notll)
+#endif
+\f
+#ifdef L_cmov
+/* (void) __cmov (char *dest, const char *src, size_t len) */
+/*
+ * void __cmov (char *dest, const char *src, size_t len)
+ * {
+ *   size_t i;
+ * 
+ *   if (dest < src || dest > src+len)
+ *     {
+ *      for (i = 0; i < len; i++)
+ *      dest[i] = src[i];
+ *     }
+ *   else
+ *     {
+ *      while (len-- > 0)
+ *      dest[len] = src[len];
+ *     }
+ * }
+ */
+
+       .file   "_cmov.s"
+       .globl  EXT(__cmov)
+       .type   EXT(__cmov),@function
+       .text
+       .p2align 4
+EXT(__cmov):
+       P(cmp)  gr8, gr9, icc0
+       add     gr9, gr10, gr4
+       P(cmp)  gr8, gr4, icc1
+       bc      icc0, 0, .Lfwd
+       bls     icc1, 0, .Lback
+.Lfwd:
+       /* move bytes in a forward direction */
+       P(setlos) #0, gr5
+       cmp     gr0, gr10, icc0
+       P(subi) gr9, #1, gr9
+       P2(subi) gr8, #1, gr8
+       bnc     icc0, 0, .Lret
+.Lfloop:
+       /* forward byte move loop */
+       addi    gr5, #1, gr5
+       P(ldsb) @(gr9, gr5), gr4
+       cmp     gr5, gr10, icc0
+       P(stb)  gr4, @(gr8, gr5)
+       bc      icc0, 0, .Lfloop
+       ret
+.Lbloop:
+       /* backward byte move loop body */
+       ldsb    @(gr9,gr10),gr4
+       stb     gr4,@(gr8,gr10)
+.Lback:
+       P(cmpi) gr10, #0, icc0
+       addi    gr10, #-1, gr10
+       bne     icc0, 0, .Lbloop
+.Lret:
+       ret
+.Lend:
+       .size    EXT(__cmov),.Lend-EXT(__cmov)
+#endif
diff --git a/gcc/config/frv/media.h b/gcc/config/frv/media.h
new file mode 100644 (file)
index 0000000..9b0c70e
--- /dev/null
@@ -0,0 +1,256 @@
+/*      VENUS Family C Library V40L00                                   */
+/*      COPYRIGHT(C) FUJITSU LIMITED 1993-1999                          */
+
+#ifndef __MEDIA_H__
+#define __MEDIA_H__
+
+#ifdef __STDC__
+#define __MEDIA_PASTE__(A,B) __MEDIA_XPASTE__(A,B)
+#define __MEDIA_XPASTE__(A,B) A ## B
+#else
+#define __MEDIA_PASTE__(A,B) A/**/B
+#endif
+
+/* Floating Point Condition Code Field Type */
+typedef enum
+{
+  FCC0 = 0,
+  FCC1,
+  FCC2, 
+  FCC3
+} FCC_T;
+
+/* Accumulator Type */
+#define ACC0   0
+#define ACC1   1
+#define ACC2   2
+#define ACC3   3
+#define ACC4   4
+#define ACC5   5
+#define ACC6   6
+#define ACC7   7
+
+typedef unsigned char      __mubyte;
+typedef unsigned short    __muhalf;
+typedef unsigned long      __muword1;
+typedef unsigned long long __muword2;
+
+typedef signed short      __mshalf;
+typedef signed long        __msword1;
+typedef signed long long   __msword2;
+
+typedef int ACC_T;
+
+register __muword1 __acc0 __asm__("acc0");
+register __muword1 __acc1 __asm__("acc1");
+register __muword1 __acc2 __asm__("acc2");
+register __muword1 __acc3 __asm__("acc3");
+register __muword1 __acc4 __asm__("acc4");
+register __muword1 __acc5 __asm__("acc5");
+register __muword1 __acc6 __asm__("acc6");
+register __muword1 __acc7 __asm__("acc7");
+
+#define __ACC(N) __MEDIA_PASTE__(__acc,N)
+
+/* Accumulator Guard Type */
+#define ACCG0  0
+#define ACCG1  1
+#define ACCG2  2
+#define ACCG3  3
+#define ACCG4  4
+#define ACCG5  5
+#define ACCG6  6
+#define ACCG7  7
+
+typedef int ACCG_T;
+
+register __mubyte __accg0 __asm__("accg0");
+register __mubyte __accg1 __asm__("accg1");
+register __mubyte __accg2 __asm__("accg2");
+register __mubyte __accg3 __asm__("accg3");
+register __mubyte __accg4 __asm__("accg4");
+register __mubyte __accg5 __asm__("accg5");
+register __mubyte __accg6 __asm__("accg6");
+register __mubyte __accg7 __asm__("accg7");
+
+#define __ACCG(N) __MEDIA_PASTE__(__accg,N)
+
+/* 12-bit Immediate Type */
+typedef int IMM12;
+
+/* 6-bit Immediate Type */
+typedef int IMM6;
+
+/* 5-bit Immediate Type */
+typedef int IMM5;
+
+/* 5-bit Unsigned Immediate Type */
+typedef int UIMM5;
+
+/* 4-bit Unsigned Immediate Type */
+typedef int UIMM4;
+
+/* 1-bit Unsigned Immediate Type */
+typedef int UIMM1;
+
+/* Media Logical (Word) */
+extern __muword1 __MAND(__muword1, __muword1);
+extern __muword1 __MOR(__muword1, __muword1);
+extern __muword1 __MXOR(__muword1, __muword1);
+extern __muword1 __MNOT(__muword1);
+
+/* Media Rotate (Word) */
+extern __muword1 __MROTLI(__muword1, UIMM5);
+extern __muword1 __MROTRI(__muword1, UIMM5);
+
+/* Media Word Cut */
+extern __muword1 __MWCUT(__muword2, __muword1);
+
+/* Media Average (Halfword Dual) */
+extern __muword1 __MAVEH(__muword1, __muword1);
+
+/* Media Shift (Halfword Dual) */
+extern __muword1 __MSLLHI(__muword1, UIMM4);
+extern __muword1 __MSRLHI(__muword1, UIMM4);
+extern __msword1 __MSRAHI(__msword1, UIMM4);
+
+/* Media Saturation (Halfword Dual) */
+extern __msword1 __MSATHS(__msword1, __msword1);
+extern __muword1 __MSATHU(__muword1, __muword1);
+
+#if 0 /* These are not supported. */
+/* Media Dual Compare (Halfword Dual) */
+extern void __MCMPSH(FCC_T, __msword1, __msword1);
+extern void __MCMPUH(FCC_T, __muword1, __muword1);
+#endif
+
+/* Media Dual Saturation Add/Sub (Halfword Dual) */
+extern __msword1 __MADDHSS(__msword1, __msword1);
+extern __muword1 __MADDHUS(__muword1, __muword1);
+extern __msword1 __MSUBHSS(__msword1, __msword1);
+extern __muword1 __MSUBHUS(__muword1, __muword1);
+
+/* Media Dual Mult (Halfword Dual) */
+extern void __MMULHS(ACC_T, __msword1, __msword1);
+extern void __MMULHU(ACC_T, __muword1, __muword1);
+
+/* Media Dual Cross Mult (Halfword Dual) */
+extern void __MMULXHS(ACC_T, __msword1, __msword1);
+extern void __MMULXHU(ACC_T, __muword1, __muword1);
+
+/* Media Dual Mult & Add (Halfword Dual) */
+extern void __MMACHS(ACC_T, __msword1, __msword1);
+extern void __MMACHU(ACC_T, __muword1, __muword1);
+
+/* Media Dual Mult & Sub (Halfword Dual) */
+extern void __MMRDHS(ACC_T, __msword1, __msword1);
+extern void __MMRDHU(ACC_T, __muword1, __muword1);
+
+/* Media Quad Saturation Add/Sub (Halfword Quad) */
+extern __msword2 __MQADDHSS(__msword2, __msword2);
+extern __muword2 __MQADDHUS(__muword2, __muword2);
+extern __msword2 __MQSUBHSS(__msword2, __msword2);
+extern __muword2 __MQSUBHUS(__muword2, __muword2);
+
+/* Media Quad Mult (Halfword Quad) */
+extern void __MQMULHS(ACC_T, __msword2, __msword2);
+extern void __MQMULHU(ACC_T, __muword2, __muword2);
+
+/* Media Quad Cross Mult (Halfword Quad) */
+extern void __MQMULXHS(ACC_T, __msword2, __msword2);
+extern void __MQMULXHU(ACC_T, __muword2, __muword2);
+
+/* Media Quad Mult & Add (Halfword Quad) */
+extern void __MQMACHS(ACC_T, __msword2, __msword2);
+extern void __MQMACHU(ACC_T, __muword2, __muword2);
+
+/* Media Dual Mult & Add for Complex (Halfword Dual) */
+extern void __MCPXRS(ACC_T, __msword1, __msword1);
+extern void __MCPXRU(ACC_T, __muword1, __muword1);
+extern void __MCPXIS(ACC_T, __msword1, __msword1);
+extern void __MCPXIU(ACC_T, __muword1, __muword1);
+
+/* Media Quad Mult & Add for Complex (Halfword Quad) */
+extern void __MQCPXRS(ACC_T, __msword2, __msword2);
+extern void __MQCPXRU(ACC_T, __muword2, __muword2);
+extern void __MQCPXIS(ACC_T, __msword2, __msword2);
+extern void __MQCPXIU(ACC_T, __muword2, __muword2);
+
+/* Media Cut */
+extern __muword1 __MCUT(ACC_T, __muword1);
+extern __muword1 __MCUTSS(ACC_T, __msword1);
+
+/* Media Halfword Expand */
+extern __muword1 __MEXPDHW(__muword1, UIMM1);
+extern __muword2 __MEXPDHD(__muword1, UIMM1);
+
+/* Media Halfword Pack/Unpack */
+extern __muword1 __MPACKH(__muhalf, __muhalf);
+extern __muword2 __MUNPACKH(__muword1);
+
+/* Media Halfword Pack/Unpack (Dual) */
+extern __muword2 __MDPACKH(__muword2, __muword2);
+extern void __MDUNPACKH(__muword1[4], __muword2);
+
+/* Media Byte-Halfword Convert */
+extern __muword2 __MBTOH(__muword1);
+extern __muword1 __MHTOB(__muword2);
+extern void __MBTOHE(__muword1[4], __muword1);
+
+/* Media Accumulator Clear */
+extern void __MCLRACC(ACC_T);      
+extern void __MCLRACCA(void);
+
+/* Media Accumlator Read/Write */
+extern __muword1 __MRDACC(ACC_T);
+extern __muword1 __MRDACCG(ACCG_T);
+extern void __MWTACC(ACC_T, __muword1);
+extern void __MWTACCG(ACCG_T, __muword1);
+
+/* Media Custom */
+extern __muword1 __Mcop1(__muword1, __muword1);
+extern __muword1 __Mcop2(__muword1, __muword1);
+
+/* Media Trap */
+extern void __MTRAP(void);
+
+/* The following are available on the FR400.  The compiler will report an
+   error if an attempt is made to use them in FR500 code.  */
+
+/* Media Multiply And Add (Halfword) */
+extern void __MQXMACHS(ACC_T, __msword2, __msword2);
+extern void __MQXMACXHS(ACC_T, __msword2, __msword2);
+extern void __MQMACXHS(ACC_T, __msword2, __msword2);
+
+/* Media Accumulator Addition/Subtraction */
+extern void __MADDACCS(ACC_T, ACC_T);
+extern void __MSUBACCS(ACC_T, ACC_T);
+extern void __MASACCS(ACC_T, ACC_T);
+extern void __MDADDACCS(ACC_T, ACC_T);
+extern void __MDSUBACCS(ACC_T, ACC_T);
+extern void __MDASACCS(ACC_T, ACC_T);
+
+/* Media Dual Absolute (Halfword) */
+extern __muword1 __MABSHS(__msword1);
+
+/* Media Dual Rotate Left */
+extern __muword2 __MDROTLI(__muword2, UIMM5);
+
+/* Media Dual Coupling */
+extern __muword1 __MCPLHI(__muword2, UIMM4);
+extern __muword1 __MCPLI(__muword2, UIMM5);
+
+/* Media Dual Cut And Signed Saturation */
+extern __muword2 __MDCUTSSI(ACC_T, IMM6);
+
+/* Media Quad Saturation (Halfword) */
+extern __msword2 __MQSATHS(__msword2, __msword2);
+
+/* Media SETHI/SETLO */
+extern __msword1 __MHSETLOS(__msword1, IMM12);
+extern __msword1 __MHSETHIS(__msword1, IMM12);
+extern __msword1 __MHDSETS(IMM12);
+extern __muword1 __MHSETLOH(__muword1, IMM5);
+extern __muword1 __MHSETHIH(__muword1, IMM5);
+extern __muword1 __MHDSETH(__muword1, IMM5);
+#endif /* __MEDIA_H__ */
diff --git a/gcc/config/frv/modi.c b/gcc/config/frv/modi.c
new file mode 100644 (file)
index 0000000..d5a91fc
--- /dev/null
@@ -0,0 +1,4 @@
+int __modi (int a, int b)
+{
+  return a % b;
+}
diff --git a/gcc/config/frv/uitod.c b/gcc/config/frv/uitod.c
new file mode 100644 (file)
index 0000000..14290ab
--- /dev/null
@@ -0,0 +1,4 @@
+double __uitod (unsigned int a)
+{
+  return a;
+}
diff --git a/gcc/config/frv/uitof.c b/gcc/config/frv/uitof.c
new file mode 100644 (file)
index 0000000..059bc7c
--- /dev/null
@@ -0,0 +1,4 @@
+float __uitof (unsigned int a)
+{
+  return a;
+}
diff --git a/gcc/config/frv/ulltod.c b/gcc/config/frv/ulltod.c
new file mode 100644 (file)
index 0000000..e6bee12
--- /dev/null
@@ -0,0 +1,4 @@
+double __ulltod (unsigned long long a)
+{
+  return a;
+}
diff --git a/gcc/config/frv/ulltof.c b/gcc/config/frv/ulltof.c
new file mode 100644 (file)
index 0000000..29cdfd4
--- /dev/null
@@ -0,0 +1,4 @@
+float __ulltof (unsigned long long a)
+{
+  return a;
+}
diff --git a/gcc/config/frv/umodi.c b/gcc/config/frv/umodi.c
new file mode 100644 (file)
index 0000000..4ffe5ad
--- /dev/null
@@ -0,0 +1,4 @@
+unsigned int __umodi (unsigned int a, unsigned int b)
+{
+  return a % b;
+}
diff --git a/gcc/config/frv/xm-frv.h b/gcc/config/frv/xm-frv.h
new file mode 100644 (file)
index 0000000..8f2ed66
--- /dev/null
@@ -0,0 +1,38 @@
+/* Definitions for Frv target
+   Copyright (C) 1999 Free Software Foundation, Inc.
+   Contributed by Red Hat, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* #defines that need visibility everywhere.  */
+#define        FALSE   0
+#define        TRUE    1
+
+/* A C expression for the status code to be returned when the compiler exits
+   after serious errors.  */
+#define FATAL_EXIT_CODE 33
+
+/* A C expression for the status code to be returned when the compiler exits
+   without serious errors.  */
+#define SUCCESS_EXIT_CODE 0
+
+/* target machine dependencies.
+   tm.h is a symbolic link to the actual target specific file.   */
+#include "tm.h"
+
+/* end of xm-frv.h */