OSDN Git Service

* config/frv/frv.c (frv_frame_access): Do not use reg+reg
[pf3gnuchains/gcc-fork.git] / gcc / config / frv / frv.c
index 19faaa6..56c99ae 100644 (file)
@@ -1,12 +1,12 @@
-/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004
-   Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007,
+   2008  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)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -15,9 +15,8 @@ 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.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -51,6 +50,7 @@ Boston, MA 02111-1307, USA.  */
 #include "targhooks.h"
 #include "integrate.h"
 #include "langhooks.h"
+#include "df.h"
 
 #ifndef FRV_INLINE
 #define FRV_INLINE inline
@@ -109,6 +109,21 @@ static GTY(()) rtx frv_nops[NUM_NOP_PATTERNS];
 /* The number of nop instructions in frv_nops[].  */
 static unsigned int frv_num_nops;
 
+/* Information about one __builtin_read or __builtin_write access, or
+   the combination of several such accesses.  The most general value
+   is all-zeros (an unknown access to an unknown address).  */
+struct frv_io {
+  /* The type of access.  FRV_IO_UNKNOWN means the access can be either
+     a read or a write.  */
+  enum { FRV_IO_UNKNOWN, FRV_IO_READ, FRV_IO_WRITE } type;
+
+  /* The constant address being accessed, or zero if not known.  */
+  HOST_WIDE_INT const_address;
+
+  /* The run-time address, as used in operand 0 of the membar pattern.  */
+  rtx var_address;
+};
+
 /* Return true if instruction INSN should be packed with the following
    instruction.  */
 #define PACKING_FLAG_P(INSN) (GET_MODE (INSN) == TImode)
@@ -123,13 +138,14 @@ static unsigned int frv_num_nops;
        REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X));   \
        REG++)
 
-/* Information about a relocation unspec.  SYMBOL is the relocation symbol
-   (a SYMBOL_REF or LABEL_REF), RELOC is the type of relocation and OFFSET
-   is the constant addend.  */
-struct frv_unspec {
-  rtx symbol;
-  int reloc;
-  HOST_WIDE_INT offset;
+/* This structure contains machine specific function data.  */
+struct GTY(()) machine_function
+{
+  /* True if we have created an rtx that relies on the stack frame.  */
+  int frame_needed;
+
+  /* True if this function contains at least one __builtin_{read,write}*.  */
+  bool has_membar_p;
 };
 
 /* Temporary register allocation support structure.  */
@@ -247,35 +263,20 @@ 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 bool frv_handle_option                  (size_t, const char *, int);
 static int frv_default_flags_for_cpu           (void);
-static int frv_string_begins_with              (tree, const char *);
+static int frv_string_begins_with              (const_tree, const char *);
 static FRV_INLINE bool frv_small_data_reloc_p  (rtx, int);
-static FRV_INLINE bool frv_const_unspec_p      (rtx, struct frv_unspec *);
 static void frv_print_operand_memory_reference_reg
                                                (FILE *, rtx);
 static void frv_print_operand_memory_reference (FILE *, rtx, int);
 static int frv_print_operand_jump_hint         (rtx);
+static const char *comparison_string           (enum rtx_code, rtx);
 static FRV_INLINE int frv_regno_ok_for_base_p  (int, int);
 static rtx single_set_pattern                  (rtx);
 static int frv_function_contains_far_jump      (void);
@@ -294,14 +295,14 @@ static void frv_frame_access_multi                (frv_frame_accessor_t*,
 static void frv_frame_access_standard_regs     (enum frv_stack_op,
                                                 frv_stack_t *);
 static struct machine_function *frv_init_machine_status                (void);
-static int frv_legitimate_memory_operand       (rtx, enum machine_mode, int);
 static rtx frv_int_to_acc                      (enum insn_code, int, rtx);
 static enum machine_mode frv_matching_accg_mode        (enum machine_mode);
-static rtx frv_read_argument                   (tree *);
-static rtx frv_read_iacc_argument              (enum machine_mode, tree *);
+static rtx frv_read_argument                   (tree, unsigned int);
+static rtx frv_read_iacc_argument              (enum machine_mode, tree, unsigned int);
 static int frv_check_constant_argument         (enum insn_code, int, rtx);
 static rtx frv_legitimize_target               (enum insn_code, rtx);
 static rtx frv_legitimize_argument             (enum insn_code, int, rtx);
+static rtx frv_legitimize_tls_address          (rtx, enum tls_model);
 static rtx frv_expand_set_builtin              (enum insn_code, tree, rtx);
 static rtx frv_expand_unop_builtin             (enum insn_code, tree, rtx);
 static rtx frv_expand_binop_builtin            (enum insn_code, tree, rtx);
@@ -329,7 +330,7 @@ static int frv_cond_flags                   (rtx);
 static bool frv_regstate_conflict_p            (regstate_t, regstate_t);
 static int frv_registers_conflict_p_1          (rtx *, void *);
 static bool frv_registers_conflict_p           (rtx);
-static void frv_registers_update_1             (rtx, rtx, void *);
+static void frv_registers_update_1             (rtx, const_rtx, void *);
 static void frv_registers_update               (rtx);
 static void frv_start_packet                   (void);
 static void frv_start_packet_block             (void);
@@ -357,14 +358,15 @@ static bool frv_assemble_integer          (rtx, unsigned, int);
 static void frv_init_builtins                  (void);
 static rtx frv_expand_builtin                  (tree, rtx, rtx, enum machine_mode, int);
 static void frv_init_libfuncs                  (void);
-static bool frv_in_small_data_p                        (tree);
+static bool frv_in_small_data_p                        (const_tree);
 static void frv_asm_output_mi_thunk
   (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
 static void frv_setup_incoming_varargs         (CUMULATIVE_ARGS *,
                                                 enum machine_mode,
                                                 tree, int *, int);
 static rtx frv_expand_builtin_saveregs         (void);
-static bool frv_rtx_costs                      (rtx, int, int, int*);
+static void frv_expand_builtin_va_start                (tree, rtx);
+static bool frv_rtx_costs                      (rtx, int, int, int*, bool);
 static void frv_asm_out_constructor            (rtx, int);
 static void frv_asm_out_destructor             (rtx, int);
 static bool frv_function_symbol_referenced_p   (rtx);
@@ -374,7 +376,21 @@ static void frv_output_const_unspec                (FILE *,
                                                 const struct frv_unspec *);
 static bool frv_function_ok_for_sibcall                (tree, tree);
 static rtx frv_struct_value_rtx                        (tree, int);
-static bool frv_must_pass_in_stack (enum machine_mode mode, tree type);
+static bool frv_must_pass_in_stack (enum machine_mode mode, const_tree type);
+static int frv_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+                                 tree, bool);
+static void frv_output_dwarf_dtprel            (FILE *, int, rtx)
+  ATTRIBUTE_UNUSED;
+static bool frv_secondary_reload                (bool, rtx, enum reg_class,
+                                                enum machine_mode,
+                                                secondary_reload_info *);
+\f
+/* 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
 \f
 /* Initialize the GCC target structure.  */
 #undef  TARGET_ASM_FUNCTION_PROLOGUE
@@ -383,6 +399,17 @@ static bool frv_must_pass_in_stack (enum machine_mode mode, tree type);
 #define TARGET_ASM_FUNCTION_EPILOGUE frv_function_epilogue
 #undef  TARGET_ASM_INTEGER
 #define TARGET_ASM_INTEGER frv_assemble_integer
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS            \
+  (MASK_DEFAULT_ALLOC_CC                       \
+   | MASK_COND_MOVE                            \
+   | MASK_SCC                                  \
+   | MASK_COND_EXEC                            \
+   | MASK_VLIW_BRANCH                          \
+   | MASK_MULTI_CE                             \
+   | MASK_NESTED_CE)
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION frv_handle_option
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS frv_init_builtins
 #undef TARGET_EXPAND_BUILTIN
@@ -411,12 +438,17 @@ static bool frv_must_pass_in_stack (enum machine_mode mode, tree type);
 #undef TARGET_CANNOT_FORCE_CONST_MEM
 #define TARGET_CANNOT_FORCE_CONST_MEM frv_cannot_force_const_mem
 
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS HAVE_AS_TLS
+
 #undef TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX frv_struct_value_rtx
 #undef TARGET_MUST_PASS_IN_STACK
 #define TARGET_MUST_PASS_IN_STACK frv_must_pass_in_stack
 #undef TARGET_PASS_BY_REFERENCE
 #define TARGET_PASS_BY_REFERENCE hook_pass_by_reference_must_pass_in_stack
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES frv_arg_partial_bytes
 
 #undef TARGET_EXPAND_BUILTIN_SAVEREGS
 #define TARGET_EXPAND_BUILTIN_SAVEREGS frv_expand_builtin_saveregs
@@ -425,7 +457,22 @@ static bool frv_must_pass_in_stack (enum machine_mode mode, tree type);
 #undef TARGET_MACHINE_DEPENDENT_REORG
 #define TARGET_MACHINE_DEPENDENT_REORG frv_reorg
 
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START frv_expand_builtin_va_start
+
+#if HAVE_AS_TLS
+#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
+#define TARGET_ASM_OUTPUT_DWARF_DTPREL frv_output_dwarf_dtprel
+#endif
+
+#undef  TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD frv_secondary_reload
+
 struct gcc_target targetm = TARGET_INITIALIZER;
+
+#define FRV_SYMBOL_REF_TLS_P(RTX) \
+  (GET_CODE (RTX) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (RTX) != 0)
+
 \f
 /* Any function call that satisfies the machine-independent
    requirements is eligible on FR-V.  */
@@ -452,7 +499,7 @@ frv_small_data_reloc_p (rtx symbol, int reloc)
 /* Return true if X is a valid relocation unspec.  If it is, fill in UNSPEC
    appropriately.  */
 
-static FRV_INLINE bool
+bool
 frv_const_unspec_p (rtx x, struct frv_unspec *unspec)
 {
   if (GET_CODE (x) == CONST)
@@ -506,6 +553,41 @@ frv_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
   return TARGET_FDPIC;
 }
 \f
+/* Implement TARGET_HANDLE_OPTION.  */
+
+static bool
+frv_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+{
+  switch (code)
+    {
+    case OPT_mcpu_:
+      if (strcmp (arg, "simple") == 0)
+       frv_cpu_type = FRV_CPU_SIMPLE;
+      else if (strcmp (arg, "tomcat") == 0)
+       frv_cpu_type = FRV_CPU_TOMCAT;
+      else if (strcmp (arg, "fr550") == 0)
+       frv_cpu_type = FRV_CPU_FR550;
+      else if (strcmp (arg, "fr500") == 0)
+       frv_cpu_type = FRV_CPU_FR500;
+      else if (strcmp (arg, "fr450") == 0)
+       frv_cpu_type = FRV_CPU_FR450;
+      else if (strcmp (arg, "fr405") == 0)
+       frv_cpu_type = FRV_CPU_FR405;
+      else if (strcmp (arg, "fr400") == 0)
+       frv_cpu_type = FRV_CPU_FR400;
+      else if (strcmp (arg, "fr300") == 0)
+       frv_cpu_type = FRV_CPU_FR300;
+      else if (strcmp (arg, "frv") == 0)
+       frv_cpu_type = FRV_CPU_GENERIC;
+      else
+       return false;
+      return true;
+
+    default:
+      return true;
+    }
+}
+
 static int
 frv_default_flags_for_cpu (void)
 {
@@ -531,8 +613,10 @@ frv_default_flags_for_cpu (void)
     case FRV_CPU_FR300:
     case FRV_CPU_SIMPLE:
       return MASK_DEFAULT_SIMPLE;
+
+    default:
+      gcc_unreachable ();
     }
-  abort ();
 }
 
 /* Sometimes certain combinations of command options do not make
@@ -550,47 +634,6 @@ frv_override_options (void)
   int regno;
   unsigned int 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, "550") == 0)
-           frv_cpu_type = FRV_CPU_FR550;
-
-         else if (strcmp (p, "500") == 0)
-           frv_cpu_type = FRV_CPU_FR500;
-
-         else if (strcmp (p, "450") == 0)
-           frv_cpu_type = FRV_CPU_FR450;
-
-         else if (strcmp (p, "405") == 0)
-           frv_cpu_type = FRV_CPU_FR405;
-
-         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
@@ -607,22 +650,6 @@ frv_override_options (void)
        }
     }
 
-  /* 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
@@ -630,70 +657,83 @@ frv_override_options (void)
 
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
     {
-      enum reg_class class;
+      enum reg_class rclass;
 
       if (GPR_P (regno))
        {
          int gpr_reg = regno - GPR_FIRST;
-         if ((gpr_reg & 3) == 0)
-           class = QUAD_REGS;
+
+         if (gpr_reg == GR8_REG)
+           rclass = GR8_REGS;
+
+         else if (gpr_reg == GR9_REG)
+           rclass = GR9_REGS;
+
+         else if (gpr_reg == GR14_REG)
+           rclass = FDPIC_FPTR_REGS;
+
+         else if (gpr_reg == FDPIC_REGNO)
+           rclass = FDPIC_REGS;
+
+         else if ((gpr_reg & 3) == 0)
+           rclass = QUAD_REGS;
 
          else if ((gpr_reg & 1) == 0)
-           class = EVEN_REGS;
+           rclass = EVEN_REGS;
 
          else
-           class = GPR_REGS;
+           rclass = GPR_REGS;
        }
 
       else if (FPR_P (regno))
        {
          int fpr_reg = regno - GPR_FIRST;
          if ((fpr_reg & 3) == 0)
-           class = QUAD_FPR_REGS;
+           rclass = QUAD_FPR_REGS;
 
          else if ((fpr_reg & 1) == 0)
-           class = FEVEN_REGS;
+           rclass = FEVEN_REGS;
 
          else
-           class = FPR_REGS;
+           rclass = FPR_REGS;
        }
 
       else if (regno == LR_REGNO)
-       class = LR_REG;
+       rclass = LR_REG;
 
       else if (regno == LCR_REGNO)
-       class = LCR_REG;
+       rclass = LCR_REG;
 
       else if (ICC_P (regno))
-       class = ICC_REGS;
+       rclass = ICC_REGS;
 
       else if (FCC_P (regno))
-       class = FCC_REGS;
+       rclass = FCC_REGS;
 
       else if (ICR_P (regno))
-       class = ICR_REGS;
+       rclass = ICR_REGS;
 
       else if (FCR_P (regno))
-       class = FCR_REGS;
+       rclass = FCR_REGS;
 
       else if (ACC_P (regno))
        {
          int r = regno - ACC_FIRST;
          if ((r & 3) == 0)
-           class = QUAD_ACC_REGS;
+           rclass = QUAD_ACC_REGS;
          else if ((r & 1) == 0)
-           class = EVEN_ACC_REGS;
+           rclass = EVEN_ACC_REGS;
          else
-           class = ACC_REGS;
+           rclass = ACC_REGS;
        }
 
       else if (ACCG_P (regno))
-       class = ACCG_REGS;
+       rclass = ACCG_REGS;
 
       else
-       class = NO_REGS;
+       rclass = NO_REGS;
 
-      regno_reg_class[regno] = class;
+      regno_reg_class[regno] = rclass;
     }
 
   /* Check for small data option */
@@ -751,6 +791,9 @@ frv_override_options (void)
   if ((target_flags_explicit & MASK_LINKED_FP) == 0)
     target_flags |= MASK_LINKED_FP;
 
+  if ((target_flags_explicit & MASK_OPTIMIZE_MEMBAR) == 0)
+    target_flags |= MASK_OPTIMIZE_MEMBAR;
+
   for (i = 0; i < ARRAY_SIZE (frv_unit_names); i++)
     frv_unit_codes[i] = get_cpu_unit_code (frv_unit_names[i]);
 
@@ -774,7 +817,7 @@ frv_override_options (void)
 
    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
+   level on all supported machines.  Use this macro to enable machine-specific
    optimizations.
 
    *Do not examine `write_symbols' in this macro!* The debugging options are
@@ -800,9 +843,9 @@ frv_optimization_options (int level, int size ATTRIBUTE_UNUSED)
 /* Return true if NAME (a STRING_CST node) begins with PREFIX.  */
 
 static int
-frv_string_begins_with (tree name, const char *prefix)
+frv_string_begins_with (const_tree name, const char *prefix)
 {
-  int prefix_len = strlen (prefix);
+  const int prefix_len = strlen (prefix);
 
   /* Remember: NAME's length includes the null terminator.  */
   return (TREE_STRING_LENGTH (name) > prefix_len
@@ -1134,11 +1177,11 @@ frv_stack_info (void)
        default:
          for (regno = first; regno <= last; regno++)
            {
-             if ((regs_ever_live[regno] && !call_used_regs[regno])
-                 || (current_function_calls_eh_return
+             if ((df_regs_ever_live_p (regno) && !call_used_regs[regno])
+                 || (crtl->calls_eh_return
                      && (regno >= FIRST_EH_REGNUM && regno <= LAST_EH_REGNUM))
                  || (!TARGET_FDPIC && flag_pic
-                     && cfun->uses_pic_offset_table && regno == PIC_REGNO))
+                     && crtl->uses_pic_offset_table && regno == PIC_REGNO))
                {
                  info_ptr->save_p[regno] = REG_SAVE_1WORD;
                  size_1word += UNITS_PER_WORD;
@@ -1152,13 +1195,13 @@ frv_stack_info (void)
          break;
 
        case STACK_REGS_LR:
-         if (regs_ever_live[LR_REGNO]
+         if (df_regs_ever_live_p (LR_REGNO)
               || profile_flag
              /* This is set for __builtin_return_address, etc.  */
              || cfun->machine->frame_needed
               || (TARGET_LINKED_FP && frame_pointer_needed)
               || (!TARGET_FDPIC && flag_pic
-                 && cfun->uses_pic_offset_table))
+                 && crtl->uses_pic_offset_table))
            {
              info_ptr->save_p[LR_REGNO] = REG_SAVE_1WORD;
              size_1word += UNITS_PER_WORD;
@@ -1171,7 +1214,7 @@ frv_stack_info (void)
              /* If this is a stdarg function with a non varardic
                 argument split between registers and the stack,
                 adjust the saved registers downward.  */
-             last -= (ADDR_ALIGN (cfun->pretend_args_size, UNITS_PER_WORD)
+             last -= (ADDR_ALIGN (crtl->args.pretend_args_size, UNITS_PER_WORD)
                       / UNITS_PER_WORD);
 
              for (regno = first; regno <= last; regno++)
@@ -1231,13 +1274,13 @@ frv_stack_info (void)
      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->parameter_size = ADDR_ALIGN (crtl->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;
+  info_ptr->pretend_size = crtl->args.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.  */
@@ -1465,8 +1508,7 @@ frv_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
       rtx insn;
 
       /* Just to check that the above comment is true.  */
-      if (regs_ever_live[GPR_FIRST + 3])
-       abort ();
+      gcc_assert (!df_regs_ever_live_p (GPR_FIRST + 3));
 
       /* Generate the instruction that saves the link register.  */
       fprintf (file, "\tmovsg lr,gr3\n");
@@ -1486,7 +1528,7 @@ frv_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
              {
                rtx address = XEXP (XVECEXP (pattern, 0, 1), 0);
                if (GET_CODE (address) == REG && REGNO (address) == LR_REGNO)
-                 REGNO (address) = GPR_FIRST + 3;
+                 SET_REGNO (address, GPR_FIRST + 3);
              }
          }
     }
@@ -1503,14 +1545,14 @@ frv_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 static rtx
 frv_alloc_temp_reg (
      frv_tmp_reg_t *info,      /* which registers are available */
-     enum reg_class class,     /* register class desired */
+     enum reg_class rclass,    /* 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 regno = info->next_reg[ (int)rclass ];
   int orig_regno = regno;
-  HARD_REG_SET *reg_in_class = &reg_class_contents[ (int)class ];
+  HARD_REG_SET *reg_in_class = &reg_class_contents[ (int)rclass ];
   int i, nr;
 
   for (;;)
@@ -1523,15 +1565,13 @@ frv_alloc_temp_reg (
        regno = 0;
       if (regno == orig_regno)
        {
-         if (no_abort)
-           return NULL_RTX;
-         else
-           abort ();
+         gcc_assert (no_abort);
+         return NULL_RTX;
        }
     }
 
   nr = HARD_REGNO_NREGS (regno, mode);
-  info->next_reg[ (int)class ] = regno + nr;
+  info->next_reg[ (int)rclass ] = regno + nr;
 
   if (mark_as_used)
     for (i = 0; i < nr; i++)
@@ -1647,8 +1687,22 @@ frv_frame_access (frv_frame_accessor_t *accessor, rtx reg, int stack_offset)
          emit_insn (gen_rtx_SET (VOIDmode, reg, temp));
        }
       else
-       emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
-      emit_insn (gen_rtx_USE (VOIDmode, reg));
+       {
+         /* We cannot use reg+reg addressing for DImode access.  */
+         if (mode == DImode
+             && GET_CODE (XEXP (mem, 0)) == PLUS
+             && GET_CODE (XEXP (XEXP (mem, 0), 0)) == REG
+             && GET_CODE (XEXP (XEXP (mem, 0), 1)) == REG)
+           {
+             rtx temp = gen_rtx_REG (SImode, TEMP_REGNO);
+             rtx insn = emit_move_insn (temp,
+                                        gen_rtx_PLUS (SImode, XEXP (XEXP (mem, 0), 0),
+                                                      XEXP (XEXP (mem, 0), 1)));
+             mem = gen_rtx_MEM (DImode, temp);
+           }
+         emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
+       }
+      emit_use (reg);
     }
   else
     {
@@ -1659,7 +1713,7 @@ frv_frame_access (frv_frame_accessor_t *accessor, rtx reg, int stack_offset)
          frv_frame_insn (gen_rtx_SET (Pmode, mem, temp),
                          frv_dwarf_store (reg, stack_offset));
        }
-      else if (GET_MODE (reg) == DImode)
+      else if (mode == DImode)
        {
          /* For DImode saves, the dwarf2 version needs to be a SEQUENCE
             with a separate save for each register.  */
@@ -1667,6 +1721,19 @@ frv_frame_access (frv_frame_accessor_t *accessor, rtx reg, int stack_offset)
          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);
+
+         /* Also we cannot use reg+reg addressing.  */
+         if (GET_CODE (XEXP (mem, 0)) == PLUS
+             && GET_CODE (XEXP (XEXP (mem, 0), 0)) == REG
+             && GET_CODE (XEXP (XEXP (mem, 0), 1)) == REG)
+           {
+             rtx temp = gen_rtx_REG (SImode, TEMP_REGNO);
+             rtx insn = emit_move_insn (temp,
+                                        gen_rtx_PLUS (SImode, XEXP (XEXP (mem, 0), 0),
+                                                      XEXP (XEXP (mem, 0), 1)));
+             mem = gen_rtx_MEM (DImode, temp);
+           }
+
          frv_frame_insn (gen_rtx_SET (Pmode, mem, reg),
                          gen_rtx_PARALLEL (VOIDmode,
                                            gen_rtvec (2, set1, set2)));
@@ -1830,7 +1897,7 @@ frv_expand_prologue (void)
     emit_insn (gen_blockage ());
 
   /* Set up pic register/small data register for this function.  */
-  if (!TARGET_FDPIC && flag_pic && cfun->uses_pic_offset_table)
+  if (!TARGET_FDPIC && flag_pic && crtl->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)));
@@ -1850,7 +1917,7 @@ frv_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
   memset (&frv_ifcvt.tmp_reg, 0, sizeof (frv_ifcvt.tmp_reg));
 
   /* Release the bitmap of created insns.  */
-  BITMAP_XFREE (frv_ifcvt.scratch_insns_bitmap);
+  BITMAP_FREE (frv_ifcvt.scratch_insns_bitmap);
 }
 
 \f
@@ -1912,7 +1979,7 @@ frv_expand_epilogue (bool emit_return)
   if (frame_pointer_needed)
     {
       emit_insn (gen_rtx_SET (VOIDmode, fp, gen_rtx_MEM (Pmode, fp)));
-      emit_insn (gen_rtx_USE (VOIDmode, fp));
+      emit_use (fp);
     }
 
   /* Deallocate the stack frame.  */
@@ -1923,7 +1990,7 @@ frv_expand_epilogue (bool emit_return)
     }
 
   /* If this function uses eh_return, add the final stack adjustment now.  */
-  if (current_function_calls_eh_return)
+  if (crtl->calls_eh_return)
     emit_insn (gen_stack_adjust (sp, sp, EH_RETURN_STACKADJ_RTX));
 
   if (emit_return)
@@ -1938,7 +2005,7 @@ frv_expand_epilogue (bool emit_return)
          emit_move_insn (lr, return_addr);
        }
 
-      emit_insn (gen_rtx_USE (VOIDmode, lr));
+      emit_use (lr);
     }
 }
 
@@ -2076,7 +2143,7 @@ frv_frame_pointer_required (void)
   if (!current_function_sp_is_unchanging)
     return TRUE;
 
-  if (!TARGET_FDPIC && flag_pic && cfun->uses_pic_offset_table)
+  if (!TARGET_FDPIC && flag_pic && crtl->uses_pic_offset_table)
     return TRUE;
 
   if (profile_flag)
@@ -2113,7 +2180,7 @@ frv_initial_elimination_offset (int from, int to)
           - info->pretend_size);
 
   else
-    abort ();
+    gcc_unreachable ();
 
   if (TARGET_DEBUG_STACK)
     fprintf (stderr, "Eliminate %s to %s by adding %d\n",
@@ -2156,11 +2223,11 @@ frv_expand_builtin_saveregs (void)
 \f
 /* Expand __builtin_va_start to do the va_start macro.  */
 
-void
+static void
 frv_expand_builtin_va_start (tree valist, rtx nextarg)
 {
   tree t;
-  int num = cfun->args_info - FIRST_ARG_REGNUM - FRV_NUM_ARG_REGS;
+  int num = crtl->args.info - FIRST_ARG_REGNUM - FRV_NUM_ARG_REGS;
 
   nextarg = gen_rtx_PLUS (Pmode, virtual_incoming_args_rtx,
                          GEN_INT (UNITS_PER_WORD * num));
@@ -2168,13 +2235,14 @@ frv_expand_builtin_va_start (tree valist, rtx nextarg)
   if (TARGET_DEBUG_ARG)
     {
       fprintf (stderr, "va_start: args_info = %d, num = %d\n",
-              cfun->args_info, num);
+              crtl->args.info, num);
 
       debug_rtx (nextarg);
     }
 
-  t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-            make_tree (ptr_type_node, nextarg));
+  t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
+             fold_convert (TREE_TYPE (valist),
+                           make_tree (sizetype, nextarg)));
   TREE_SIDE_EFFECTS (t) = 1;
 
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2227,9 +2295,8 @@ frv_expand_block_move (rtx operands[])
   if (! constp)
     return FALSE;
 
-  /* If this is not a fixed size alignment, abort.  */
-  if (GET_CODE (align_rtx) != CONST_INT)
-    abort ();
+  /* This should be a fixed size alignment.  */
+  gcc_assert (GET_CODE (align_rtx) == CONST_INT);
 
   align = INTVAL (align_rtx);
 
@@ -2297,14 +2364,14 @@ frv_expand_block_move (rtx operands[])
 
    operands[0] is the destination
    operands[1] is the length
-   operands[2] is the alignment */
+   operands[3] is the alignment */
 
 int
 frv_expand_block_clear (rtx operands[])
 {
   rtx orig_dest = operands[0];
   rtx bytes_rtx        = operands[1];
-  rtx align_rtx = operands[2];
+  rtx align_rtx = operands[3];
   int constp   = (GET_CODE (bytes_rtx) == CONST_INT);
   int align;
   int bytes;
@@ -2320,9 +2387,8 @@ frv_expand_block_clear (rtx operands[])
   if (! constp)
     return FALSE;
 
-  /* If this is not a fixed size alignment, abort.  */
-  if (GET_CODE (align_rtx) != CONST_INT)
-    abort ();
+  /* This should be a fixed size alignment.  */
+  gcc_assert (GET_CODE (align_rtx) == CONST_INT);
 
   align = INTVAL (align_rtx);
 
@@ -2506,11 +2572,17 @@ frv_print_operand_address (FILE * stream, rtx x)
       output_addr_const (stream, x);
       return;
 
+    case PLUS:
+      /* Poorly constructed asm statements can trigger this alternative.
+        See gcc/testsuite/gcc.dg/asm-4.c for an example.  */
+      frv_print_operand_memory_reference (stream, x, 0);
+      return;
+      
     default:
       break;
     }
 
-  fatal_insn ("Bad insn to frv_print_operand_address:", x);
+  fatal_insn ("bad insn to frv_print_operand_address:", x);
 }
 
 \f
@@ -2521,7 +2593,7 @@ frv_print_operand_memory_reference_reg (FILE * stream, rtx x)
   if (GPR_P (regno))
     fputs (reg_names[regno], stream);
   else
-    fatal_insn ("Bad register to frv_print_operand_memory_reference_reg:", x);
+    fatal_insn ("bad register to frv_print_operand_memory_reference_reg:", x);
 }
 
 /* Print a memory reference suitable for the ld/st instructions.  */
@@ -2560,7 +2632,7 @@ frv_print_operand_memory_reference (FILE * stream, rtx x, int addr_offset)
       break;
 
     default:
-      fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
+      fatal_insn ("bad insn to frv_print_operand_memory_reference:", x);
       break;
 
     }
@@ -2570,7 +2642,7 @@ frv_print_operand_memory_reference (FILE * stream, rtx x, int 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);
+       fatal_insn ("bad insn to frv_print_operand_memory_reference:", x);
     }
 
   fputs ("@(", stream);
@@ -2579,7 +2651,7 @@ frv_print_operand_memory_reference (FILE * stream, rtx x, int addr_offset)
   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);
+    fatal_insn ("bad insn to frv_print_operand_memory_reference:", x);
 
   fputs (",", stream);
   if (!x1)
@@ -2600,12 +2672,12 @@ frv_print_operand_memory_reference (FILE * stream, rtx x, int addr_offset)
 
        case CONST:
          if (!frv_const_unspec_p (x1, &unspec))
-           fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x1);
+           fatal_insn ("bad insn to frv_print_operand_memory_reference:", x1);
          frv_output_const_unspec (stream, &unspec);
          break;
 
        default:
-         fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
+         fatal_insn ("bad insn to frv_print_operand_memory_reference:", x);
        }
     }
 
@@ -2627,8 +2699,7 @@ frv_print_operand_jump_hint (rtx insn)
   HOST_WIDE_INT prob = -1;
   enum { UNKNOWN, BACKWARD, FORWARD } jump_type = UNKNOWN;
 
-  if (GET_CODE (insn) != JUMP_INSN)
-    abort ();
+  gcc_assert (GET_CODE (insn) == JUMP_INSN);
 
   /* Assume any non-conditional jump is likely.  */
   if (! any_condjump_p (insn))
@@ -2683,6 +2754,29 @@ frv_print_operand_jump_hint (rtx insn)
 }
 
 \f
+/* Return the comparison operator to use for CODE given that the ICC
+   register is OP0.  */
+
+static const char *
+comparison_string (enum rtx_code code, rtx op0)
+{
+  bool is_nz_p = GET_MODE (op0) == CC_NZmode;
+  switch (code)
+    {
+    default:  output_operand_lossage ("bad condition code");
+    case EQ:  return "eq";
+    case NE:  return "ne";
+    case LT:  return is_nz_p ? "n" : "lt";
+    case LE:  return "le";
+    case GT:  return "gt";
+    case GE:  return is_nz_p ? "p" : "ge";
+    case LTU: return is_nz_p ? "no" : "c";
+    case LEU: return is_nz_p ? "eq" : "ls";
+    case GTU: return is_nz_p ? "ne" : "hi";
+    case GEU: return is_nz_p ? "ra" : "nc";
+    }
+}
+
 /* Print an operand to an assembler instruction.
 
    `%' followed by a letter and a digit says to output an operand in an
@@ -2722,7 +2816,7 @@ frv_print_operand (FILE * file, rtx x, int code)
   HOST_WIDE_INT value;
   int offset;
 
-  if (code != 0 && !isalpha (code))
+  if (code != 0 && !ISALPHA (code))
     value = 0;
 
   else if (GET_CODE (x) == CONST_INT)
@@ -2744,7 +2838,7 @@ frv_print_operand (FILE * file, rtx x, int code)
        value = CONST_DOUBLE_LOW (x);
 
       else
-        fatal_insn ("Bad insn in frv_print_operand, bad const_double", x);
+        fatal_insn ("bad insn in frv_print_operand, bad const_double", x);
     }
 
   else
@@ -2786,45 +2880,13 @@ frv_print_operand (FILE * file, rtx x, int code)
 
     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;
-       }
+      fputs (comparison_string (reverse_condition (GET_CODE (x)),
+                               XEXP (x, 0)), file);
       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;
-       }
+      fputs (comparison_string (GET_CODE (x), XEXP (x, 0)), file);
       break;
 
     case 'e':
@@ -2837,7 +2899,7 @@ frv_print_operand (FILE * file, rtx x, int code)
        fputs ("0", file);
 
       else
-       fatal_insn ("Bad insn to frv_print_operand, 'e' modifier:", x);
+       fatal_insn ("bad insn to frv_print_operand, 'e' modifier:", x);
       break;
 
     case 'F':
@@ -2845,7 +2907,7 @@ frv_print_operand (FILE * file, rtx x, int code)
       switch (GET_CODE (x))
        {
        default:
-         fatal_insn ("Bad insn to frv_print_operand, 'F' modifier:", x);
+         fatal_insn ("bad insn to frv_print_operand, 'F' modifier:", x);
 
        case EQ:  fputs ("ne",  file); break;
        case NE:  fputs ("eq",  file); break;
@@ -2861,7 +2923,7 @@ frv_print_operand (FILE * file, rtx x, int code)
       switch (GET_CODE (x))
        {
        default:
-         fatal_insn ("Bad insn to frv_print_operand, 'f' modifier:", x);
+         fatal_insn ("bad insn to frv_print_operand, 'f' modifier:", x);
 
        case EQ:  fputs ("eq",  file); break;
        case NE:  fputs ("ne",  file); break;
@@ -2875,7 +2937,7 @@ frv_print_operand (FILE * file, rtx x, int code)
     case 'g':
       /* Print appropriate GOT function.  */
       if (GET_CODE (x) != CONST_INT)
-       fatal_insn ("Bad insn to frv_print_operand, 'g' modifier:", x);
+       fatal_insn ("bad insn to frv_print_operand, 'g' modifier:", x);
       fputs (unspec_got_name (INTVAL (x)), file);
       break;
 
@@ -2923,7 +2985,7 @@ frv_print_operand (FILE * file, rtx x, int code)
       if (GET_CODE (x) == REG)
        fputs (reg_names[ REGNO (x)+1 ], file);
       else
-       fatal_insn ("Bad insn to frv_print_operand, 'L' modifier:", x);
+       fatal_insn ("bad insn to frv_print_operand, 'L' modifier:", x);
       break;
 
     /* case 'l': print a LABEL_REF.  */
@@ -2936,7 +2998,7 @@ frv_print_operand (FILE * file, rtx x, int code)
       switch (GET_CODE (x))
        {
        default:
-         fatal_insn ("Bad insn to frv_print_operand, 'M/N' modifier:", x);
+         fatal_insn ("bad insn to frv_print_operand, 'M/N' modifier:", x);
 
        case MEM:
          frv_print_operand_memory_reference (file, XEXP (x, 0), offset);
@@ -2957,7 +3019,7 @@ frv_print_operand (FILE * file, rtx x, int code)
       switch (GET_CODE (x))
        {
        default:
-         fatal_insn ("Bad insn to frv_print_operand, 'O' modifier:", x);
+         fatal_insn ("bad insn to frv_print_operand, 'O' modifier:", x);
 
        case PLUS:     fputs ("add", file); break;
        case MINUS:    fputs ("sub", file); break;
@@ -2975,7 +3037,7 @@ frv_print_operand (FILE * file, rtx x, int code)
     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);
+       fatal_insn ("bad insn to frv_print_operand, P modifier:", x);
 
       fprintf (file, ".LCF%ld", (long)INTVAL (x));
       break;
@@ -2995,7 +3057,7 @@ frv_print_operand (FILE * file, rtx x, int code)
         fputs (reg_names [REGNO (x)], file);
 
       else
-        fatal_insn ("Bad insn in frv_print_operand, z case", x);
+        fatal_insn ("bad insn in frv_print_operand, z case", x);
       break;
 
     case 'x':
@@ -3026,7 +3088,7 @@ frv_print_operand (FILE * file, rtx x, int code)
         frv_print_operand_address (file, x);
 
       else
-        fatal_insn ("Bad insn in frv_print_operand, 0 case", x);
+        fatal_insn ("bad insn in frv_print_operand, 0 case", x);
 
       break;
 
@@ -3095,7 +3157,7 @@ frv_init_cumulative_args (CUMULATIVE_ARGS *cum,
    in registers.  */
 
 static bool
-frv_must_pass_in_stack (enum machine_mode mode, tree type)
+frv_must_pass_in_stack (enum machine_mode mode, const_tree type)
 {
   if (mode == BLKmode)
     return true;
@@ -3200,11 +3262,9 @@ frv_function_arg_advance (CUMULATIVE_ARGS *cum,
    used by the caller for this argument; likewise `FUNCTION_INCOMING_ARG', for
    the called function.  */
 
-int
-frv_function_arg_partial_nregs (CUMULATIVE_ARGS *cum,
-                                enum machine_mode mode,
-                                tree type ATTRIBUTE_UNUSED,
-                                int named ATTRIBUTE_UNUSED)
+static int
+frv_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                      tree type ATTRIBUTE_UNUSED, bool named ATTRIBUTE_UNUSED)
 {
   enum machine_mode xmode = (mode == BLKmode) ? SImode : mode;
   int bytes = GET_MODE_SIZE (xmode);
@@ -3215,12 +3275,12 @@ frv_function_arg_partial_nregs (CUMULATIVE_ARGS *cum,
   ret = ((arg_num <= LAST_ARG_REGNUM && arg_num + words > LAST_ARG_REGNUM+1)
         ? LAST_ARG_REGNUM - arg_num + 1
         : 0);
+  ret *= UNITS_PER_WORD;
 
   if (TARGET_DEBUG_ARG && ret)
-    fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
+    fprintf (stderr, "frv_arg_partial_bytes: %d\n", ret);
 
   return ret;
-
 }
 
 \f
@@ -3310,6 +3370,9 @@ frv_legitimate_address_p (enum machine_mode mode,
   HOST_WIDE_INT value;
   unsigned regno0;
 
+  if (FRV_SYMBOL_REF_TLS_P (x))
+    return 0;
+
   switch (GET_CODE (x))
     {
     default:
@@ -3341,7 +3404,7 @@ frv_legitimate_address_p (enum machine_mode mode,
       break;
 
     case CONST_INT:
-      /* 12 bit immediate */
+      /* 12-bit immediate */
       if (condexec_p)
        ret = FALSE;
       else
@@ -3392,7 +3455,7 @@ frv_legitimate_address_p (enum machine_mode mode,
          break;
 
        case CONST_INT:
-          /* 12 bit immediate */
+          /* 12-bit immediate */
          if (condexec_p)
            ret = FALSE;
          else
@@ -3427,11 +3490,177 @@ frv_legitimate_address_p (enum machine_mode mode,
   return ret;
 }
 
+/* Given an ADDR, generate code to inline the PLT.  */
+static rtx
+gen_inlined_tls_plt (rtx addr)
+{
+  rtx retval, dest;
+  rtx picreg = get_hard_reg_initial_val (Pmode, FDPIC_REG);
+
+
+  dest = gen_reg_rtx (DImode);
+
+  if (flag_pic == 1)
+    {
+      /*
+       -fpic version:
+
+       lddi.p  @(gr15, #gottlsdesc12(ADDR)), gr8
+       calll    #gettlsoff(ADDR)@(gr8, gr0)
+      */
+      emit_insn (gen_tls_lddi (dest, addr, picreg));
+    }
+  else
+    {
+      /*
+       -fPIC version:
+
+       sethi.p #gottlsdeschi(ADDR), gr8
+       setlo   #gottlsdesclo(ADDR), gr8
+       ldd     #tlsdesc(ADDR)@(gr15, gr8), gr8
+       calll   #gettlsoff(ADDR)@(gr8, gr0)
+      */
+      rtx reguse = gen_reg_rtx (Pmode);
+      emit_insn (gen_tlsoff_hilo (reguse, addr, GEN_INT (R_FRV_GOTTLSDESCHI)));
+      emit_insn (gen_tls_tlsdesc_ldd (dest, picreg, reguse, addr));
+    }
+
+  retval = gen_reg_rtx (Pmode);
+  emit_insn (gen_tls_indirect_call (retval, addr, dest, picreg));
+  return retval;
+}
+
+/* Emit a TLSMOFF or TLSMOFF12 offset, depending on -mTLS.  Returns
+   the destination address.  */
+static rtx
+gen_tlsmoff (rtx addr, rtx reg)
+{
+  rtx dest = gen_reg_rtx (Pmode);
+
+  if (TARGET_BIG_TLS)
+    {
+      /* sethi.p #tlsmoffhi(x), grA
+        setlo   #tlsmofflo(x), grA
+      */
+      dest = gen_reg_rtx (Pmode);
+      emit_insn (gen_tlsoff_hilo (dest, addr,
+                                 GEN_INT (R_FRV_TLSMOFFHI)));
+      dest = gen_rtx_PLUS (Pmode, dest, reg);
+    }
+  else
+    {
+      /* addi grB, #tlsmoff12(x), grC
+          -or-
+        ld/st @(grB, #tlsmoff12(x)), grC
+      */
+      dest = gen_reg_rtx (Pmode);
+      emit_insn (gen_symGOTOFF2reg_i (dest, addr, reg,
+                                     GEN_INT (R_FRV_TLSMOFF12)));
+    }
+  return dest;
+}
+
+/* Generate code for a TLS address.  */
+static rtx
+frv_legitimize_tls_address (rtx addr, enum tls_model model)
+{
+  rtx dest, tp = gen_rtx_REG (Pmode, 29);
+  rtx picreg = get_hard_reg_initial_val (Pmode, 15);
+
+  switch (model)
+    {
+    case TLS_MODEL_INITIAL_EXEC:
+      if (flag_pic == 1)
+       {
+         /* -fpic version.
+            ldi @(gr15, #gottlsoff12(x)), gr5
+          */
+         dest = gen_reg_rtx (Pmode);
+         emit_insn (gen_tls_load_gottlsoff12 (dest, addr, picreg));
+         dest = gen_rtx_PLUS (Pmode, tp, dest);
+       }
+      else
+       {
+         /* -fPIC or anything else.
+
+           sethi.p #gottlsoffhi(x), gr14
+           setlo   #gottlsofflo(x), gr14
+           ld      #tlsoff(x)@(gr15, gr14), gr9
+         */
+         rtx tmp = gen_reg_rtx (Pmode);
+         dest = gen_reg_rtx (Pmode);
+         emit_insn (gen_tlsoff_hilo (tmp, addr,
+                                     GEN_INT (R_FRV_GOTTLSOFF_HI)));
+
+         emit_insn (gen_tls_tlsoff_ld (dest, picreg, tmp, addr));
+         dest = gen_rtx_PLUS (Pmode, tp, dest);
+       }
+      break;
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      {
+       rtx reg, retval;
+
+       if (TARGET_INLINE_PLT)
+         retval = gen_inlined_tls_plt (GEN_INT (0));
+       else
+         {
+           /* call #gettlsoff(0) */
+           retval = gen_reg_rtx (Pmode);
+           emit_insn (gen_call_gettlsoff (retval, GEN_INT (0), picreg));
+         }
+
+       reg = gen_reg_rtx (Pmode);
+       emit_insn (gen_rtx_SET (VOIDmode, reg,
+                               gen_rtx_PLUS (Pmode,
+                                             retval, tp)));
+
+       dest = gen_tlsmoff (addr, reg);
+
+       /*
+       dest = gen_reg_rtx (Pmode);
+       emit_insn (gen_tlsoff_hilo (dest, addr,
+                                   GEN_INT (R_FRV_TLSMOFFHI)));
+       dest = gen_rtx_PLUS (Pmode, dest, reg);
+       */
+       break;
+      }
+    case TLS_MODEL_LOCAL_EXEC:
+      dest = gen_tlsmoff (addr, gen_rtx_REG (Pmode, 29));
+      break;
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      {
+       rtx retval;
+
+       if (TARGET_INLINE_PLT)
+         retval = gen_inlined_tls_plt (addr);
+       else
+         {
+           /* call #gettlsoff(x) */
+           retval = gen_reg_rtx (Pmode);
+           emit_insn (gen_call_gettlsoff (retval, addr, picreg));
+         }
+       dest = gen_rtx_PLUS (Pmode, retval, tp);
+       break;
+      }
+    default:
+      gcc_unreachable ();
+    }
+
+  return dest;
+}
+
 rtx
-frv_legitimize_address (rtx x ATTRIBUTE_UNUSED,
+frv_legitimize_address (rtx x,
                        rtx oldx ATTRIBUTE_UNUSED,
                        enum machine_mode mode ATTRIBUTE_UNUSED)
 {
+  if (GET_CODE (x) == SYMBOL_REF)
+    {
+      enum tls_model model = SYMBOL_REF_TLS_MODEL (x);
+      if (model != 0)
+        return frv_legitimize_tls_address (x, model);
+    }
+
   return NULL_RTX;
 }
 \f
@@ -3507,7 +3736,16 @@ unspec_got_name (int i)
     case R_FRV_GPREL12: return "gprel12";
     case R_FRV_GPRELHI: return "gprelhi";
     case R_FRV_GPRELLO: return "gprello";
-    default: abort ();
+    case R_FRV_GOTTLSOFF_HI: return "gottlsoffhi";
+    case R_FRV_GOTTLSOFF_LO: return "gottlsofflo";
+    case R_FRV_TLSMOFFHI: return "tlsmoffhi";
+    case R_FRV_TLSMOFFLO: return "tlsmofflo";
+    case R_FRV_TLSMOFF12: return "tlsmoff12";
+    case R_FRV_TLSDESCHI: return "tlsdeschi";
+    case R_FRV_TLSDESCLO: return "tlsdesclo";
+    case R_FRV_GOTTLSDESCHI: return "gottlsdeschi";
+    case R_FRV_GOTTLSDESCLO: return "gottlsdesclo";
+    default: gcc_unreachable ();
     }
 }
 
@@ -3541,7 +3779,7 @@ frv_find_base_term (rtx x)
 /* Return 1 if operand is a valid FRV address.  CONDEXEC_P is true if
    the operand is used by a predicated instruction.  */
 
-static int
+int
 frv_legitimate_memory_operand (rtx op, enum machine_mode mode, int condexec_p)
 {
   return ((GET_MODE (op) == mode || mode == VOIDmode)
@@ -3600,9 +3838,9 @@ frv_expand_fdpic_call (rtx *operands, bool ret_value, bool sibcall)
        x = gen_symGOTOFF2reg (dest, addr, OUR_FDPIC_REG,
                               GEN_INT (R_FRV_FUNCDESC_GOTOFF12));
       emit_insn (x);
-      cfun->uses_pic_offset_table = TRUE;
+      crtl->uses_pic_offset_table = TRUE;
       addr = dest;
-    }    
+    }
   else if (GET_CODE (addr) == SYMBOL_REF)
     {
       /* These are always either local, or handled through a local
@@ -3631,1707 +3869,84 @@ frv_expand_fdpic_call (rtx *operands, bool ret_value, bool sibcall)
     c = gen_call_fdpicdi (picreg, const0_rtx, lr);
   emit_call_insn (c);
 }
-
-/* An address operand that may use a pair of registers, an addressing
-   mode that we reject in general.  */
-
-int
-ldd_address_operand (rtx x, enum machine_mode mode)
-{
-  if (GET_MODE (x) != mode && GET_MODE (x) != VOIDmode)
-    return FALSE;
-
-  return frv_legitimate_address_p (DImode, x, reload_completed, FALSE, TRUE);
-}
-
-int
-fdpic_fptr_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_MODE (op) != mode && mode != VOIDmode)
-    return FALSE;
-  if (GET_CODE (op) != REG)
-    return FALSE;
-  if (REGNO (op) != FDPIC_FPTR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
-    return FALSE;
-  return TRUE;
-}
 \f
-/* Return 1 is OP is a memory operand, or will be turned into one by
-   reload.  */
+/* Look for a SYMBOL_REF of a function in an rtx.  We always want to
+   process these separately from any offsets, such that we add any
+   offsets to the function descriptor (the actual pointer), not to the
+   function address.  */
 
-int
-frv_load_operand (rtx op, enum machine_mode mode)
+static bool
+frv_function_symbol_referenced_p (rtx x)
 {
-  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.  */
+  const char *format;
+  int length;
+  int j;
 
-int
-gpr_or_fpr_operand (rtx op, enum machine_mode mode)
-{
-  int regno;
+  if (GET_CODE (x) == SYMBOL_REF)
+    return SYMBOL_REF_FUNCTION_P (x);
 
-  if (GET_MODE (op) != mode && mode != VOIDmode)
-    return FALSE;
+  length = GET_RTX_LENGTH (GET_CODE (x));
+  format = GET_RTX_FORMAT (GET_CODE (x));
 
-  if (GET_CODE (op) == SUBREG)
+  for (j = 0; j < length; ++j)
     {
-      if (GET_CODE (SUBREG_REG (op)) != REG)
-       return register_operand (op, mode);
-
-      op = SUBREG_REG (op);
-    }
+      switch (format[j])
+       {
+       case 'e':
+         if (frv_function_symbol_referenced_p (XEXP (x, j)))
+           return TRUE;
+         break;
 
-  if (GET_CODE (op) != REG)
-    return FALSE;
+       case 'V':
+       case 'E':
+         if (XVEC (x, j) != 0)
+           {
+             int k;
+             for (k = 0; k < XVECLEN (x, j); ++k)
+               if (frv_function_symbol_referenced_p (XVECEXP (x, j, k)))
+                 return TRUE;
+           }
+         break;
 
-  regno = REGNO (op);
-  if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER)
-    return TRUE;
+       default:
+         /* Nothing to do.  */
+         break;
+       }
+    }
 
   return FALSE;
 }
 
-/* Return 1 if operand is a GPR register or 12 bit signed immediate.  */
+/* Return true if the memory operand is one that can be conditionally
+   executed.  */
 
 int
-gpr_or_int12_operand (rtx op, enum machine_mode mode)
+condexec_memory_operand (rtx op, enum machine_mode mode)
 {
-  if (GET_CODE (op) == CONST_INT)
-    return IN_RANGE_P (INTVAL (op), -2048, 2047);
-
-  if (got12_operand (op, mode))
-    return true;
+  enum machine_mode op_mode = GET_MODE (op);
+  rtx addr;
 
-  if (GET_MODE (op) != mode && mode != VOIDmode)
+  if (mode != VOIDmode && op_mode != mode)
     return FALSE;
 
-  if (GET_CODE (op) == SUBREG)
+  switch (op_mode)
     {
-      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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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:
-      if (TARGET_FDPIC)
-       return FALSE;
-      
-      return (flag_pic == 0);
-
-    case CONST:
-      if (flag_pic || TARGET_FDPIC)
-       return FALSE;
-
-      op = XEXP (op, 0);
-      if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
-       op = XEXP (op, 0);
-      return GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF;
-
-    case SYMBOL_REF:
-      if (TARGET_FDPIC)
-       return FALSE;
-      
-      /* small data references are already 1 word */
-      return (flag_pic == 0) && (! SYMBOL_REF_SMALL_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 a 16 bit unsigned immediate.  */
-
-int
-uint16_operand (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (got12_operand (addr1, VOIDmode))
-       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 (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 (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, FALSE);
-
-      return (code == REG);
-
-    case REG:
-      if (GET_MODE (op) != mode && mode != VOIDmode)
-        return FALSE;
-
-      return TRUE;
-
-    case MEM:
-      return frv_legitimate_memory_operand (op, mode, FALSE);
-    }
-
-  return FALSE;
-}
-
-/* Look for a SYMBOL_REF of a function in an rtx.  We always want to
-   process these separately from any offsets, such that we add any
-   offsets to the function descriptor (the actual pointer), not to the
-   function address.  */
-
-static bool
-frv_function_symbol_referenced_p (rtx x)
-{
-  const char *format;
-  int length;
-  int j;
-
-  if (GET_CODE (x) == SYMBOL_REF)
-    return SYMBOL_REF_FUNCTION_P (x);
-
-  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_function_symbol_referenced_p (XEXP (x, j)))
-           return TRUE;
-         break;
-
-       case 'V':
-       case 'E':
-         if (XVEC (x, j) != 0)
-           {
-             int k;
-             for (k = 0; k < XVECLEN (x, j); ++k)
-               if (frv_function_symbol_referenced_p (XVECEXP (x, j, k)))
-                 return TRUE;
-           }
-         break;
-
-       default:
-         /* Nothing to do.  */
-         break;
-       }
-    }
-
-  return FALSE;
-}
-
-/* Return true if operand is something that can be an input for a move
-   operation.  */
-
-int
-move_source_operand (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 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, FALSE);
-
-      return (code == REG);
-
-    case REG:
-      if (GET_MODE (op) != mode && mode != VOIDmode)
-        return FALSE;
-
-      return TRUE;
-
-    case MEM:
-      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 (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, FALSE);
-
-      return (code == REG);
-
-    case REG:
-      if (GET_MODE (op) != mode && mode != VOIDmode)
-        return FALSE;
-
-      return TRUE;
-
-    case MEM:
-      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 (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, FALSE);
-
-      return (code == REG);
-
-    case REG:
-      if (GET_MODE (op) != mode && mode != VOIDmode)
-        return FALSE;
-
-      return TRUE;
-
-    case MEM:
-      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 (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 (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 the uClinux PIC register.  */
-
-int
-fdpic_operand (rtx op, enum machine_mode mode)
-{
-  if (!TARGET_FDPIC)
-    return FALSE;
-
-  if (GET_CODE (op) != REG)
-    return FALSE;
-
-  if (GET_MODE (op) != mode && mode != VOIDmode)
-    return FALSE;
-
-  if (REGNO (op) != FDPIC_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
-    return FALSE;
-
-  return TRUE;
-}
-
-int
-got12_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  struct frv_unspec unspec;
-
-  if (frv_const_unspec_p (op, &unspec))
-    switch (unspec.reloc)
-      {
-      case R_FRV_GOT12:
-      case R_FRV_GOTOFF12:
-      case R_FRV_FUNCDESC_GOT12:
-      case R_FRV_FUNCDESC_GOTOFF12:
-      case R_FRV_GPREL12:
-       return true;
-      }
-  return false;
-}
-
-/* Return true if OP is a valid const-unspec expression.  */
-
-int
-const_unspec_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  struct frv_unspec unspec;
-
-  return frv_const_unspec_p (op, &unspec);
-}
-/* Return true if operand is a gpr register or a valid memory operation.  */
-
-int
-gpr_or_memory_operand (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 (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 (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 (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 (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 (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 (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 (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 (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 !TARGET_LONG_CALLS || SYMBOL_REF_LOCAL_P (op);
-
-  /* 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 operand is a memory reference suitable for a sibcall.  */
-
-int
-sibcall_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT)
-    return FALSE;
-
-  /* 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 a kind of relational operator.  */
-
-int
-relational_operator (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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);
-  return frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE);
-}
-
-/* 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 (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 (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 (rtx op, enum machine_mode mode)
-{
-  return ((mode == VOIDmode || mode == GET_MODE (op))
-         && REG_P (op) && ACC_P (REGNO (op))
-         && ((REGNO (op) - ACC_FIRST) & ~ACC_MASK) == 0);
-}
-
-/* Return 1 if operand is a valid even ACC register number.  */
-
-int
-even_acc_operand (rtx op, enum machine_mode mode)
-{
-  return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 1) == 0;
-}
-
-/* Return 1 if operand is zero or four.  */
+    default:
+      return FALSE;
 
-int
-quad_acc_operand (rtx op, enum machine_mode mode)
-{
-  return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 3) == 0;
-}
+    case QImode:
+    case HImode:
+    case SImode:
+    case SFmode:
+      break;
+    }
 
-/* Return 1 if operand is a valid ACCG register number.  */
+  if (GET_CODE (op) != MEM)
+    return FALSE;
 
-int
-accg_operand (rtx op, enum machine_mode mode)
-{
-  return ((mode == VOIDmode || mode == GET_MODE (op))
-         && REG_P (op) && ACCG_P (REGNO (op))
-         && ((REGNO (op) - ACCG_FIRST) & ~ACC_MASK) == 0);
+  addr = XEXP (op, 0);
+  return frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE);
 }
-
 \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.  */
@@ -5352,6 +3967,13 @@ direct_return_p (void)
 void
 frv_emit_move (enum machine_mode mode, rtx dest, rtx src)
 {
+  if (GET_CODE (src) == SYMBOL_REF)
+    {
+      enum tls_model model = SYMBOL_REF_TLS_MODEL (src);
+      if (model != 0)
+       src = frv_legitimize_tls_address (src, model);
+    }
+
   switch (mode)
     {
     case SImode:
@@ -5372,7 +3994,7 @@ frv_emit_move (enum machine_mode mode, rtx dest, rtx src)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   emit_insn (gen_rtx_SET (VOIDmode, dest, src));
@@ -5439,7 +4061,7 @@ frv_emit_movsi (rtx dest, rtx src)
             (read-write) for code size (read-only, shareable), as
             long as the symbol is not used in more than two different
             locations.
-            
+
             With -fpie/-fpic, we'd be trading a single load for a
             sequence of 4 instructions, because the offset of the
             label can't be assumed to be addressable with 12 bits, so
@@ -5485,6 +4107,15 @@ frv_emit_movsi (rtx dest, rtx src)
     handle_sym:
       if (TARGET_FDPIC)
        {
+         enum tls_model model = SYMBOL_REF_TLS_MODEL (sym);
+
+         if (model != 0)
+           {
+             src = frv_legitimize_tls_address (src, model);
+             emit_move_insn (dest, src);
+             return TRUE;
+           }
+
          if (SYMBOL_REF_FUNCTION_P (sym))
            {
              if (frv_local_funcdesc_p (sym))
@@ -5529,11 +4160,11 @@ frv_emit_movsi (rtx dest, rtx src)
 
                  if (init && init != error_mark_node)
                    reloc = compute_reloc_for_constant (init);
-                 
+
                  named_section = TREE_CODE (decl) == VAR_DECL
                    && lookup_attribute ("section", DECL_ATTRIBUTES (decl));
                  readonly = decl_readonly_section (decl, reloc);
-                 
+
                  if (named_section)
                    unspec = R_FRV_GOT12;
                  else if (!readonly)
@@ -5568,7 +4199,7 @@ frv_emit_movsi (rtx dest, rtx src)
                                           gen_rtx_REG (Pmode, base_regno),
                                           GEN_INT (R_FRV_GPREL12)));
       if (base_regno == PIC_REGNO)
-       cfun->uses_pic_offset_table = TRUE;
+       crtl->uses_pic_offset_table = TRUE;
       return TRUE;
     }
 
@@ -5578,8 +4209,7 @@ frv_emit_movsi (rtx dest, rtx src)
 
       /* Since OUR_FDPIC_REG is a pseudo register, we can't safely introduce
         new uses of it once reload has begun.  */
-      if (reload_in_progress || reload_completed)
-       abort ();
+      gcc_assert (!reload_in_progress && !reload_completed);
 
       switch (unspec)
        {
@@ -5613,7 +4243,7 @@ frv_emit_movsi (rtx dest, rtx src)
          break;
        }
       emit_insn (x);
-      cfun->uses_pic_offset_table = TRUE;
+      crtl->uses_pic_offset_table = TRUE;
       return TRUE;
     }
 
@@ -5832,7 +4462,7 @@ output_move_single (rtx operands[], rtx insn)
        }
     }
 
-  fatal_insn ("Bad output_move_single operand", insn);
+  fatal_insn ("bad output_move_single operand", insn);
   return "";
 }
 
@@ -5959,7 +4589,7 @@ output_move_double (rtx operands[], rtx insn)
        }
     }
 
-  fatal_insn ("Bad output_move_double operand", insn);
+  fatal_insn ("bad output_move_double operand", insn);
   return "";
 }
 
@@ -6101,7 +4731,7 @@ output_condmove_single (rtx operands[], rtx insn)
        }
     }
 
-  fatal_insn ("Bad output_condmove_single operand", insn);
+  fatal_insn ("bad output_condmove_single operand", insn);
   return "";
 }
 
@@ -6377,7 +5007,7 @@ frv_split_cond_move (rtx operands[])
        }
 
       else
-       abort ();
+       gcc_unreachable ();
     }
   else
     {
@@ -6479,7 +5109,7 @@ frv_split_minmax (rtx operands[])
   switch (GET_CODE (minmax))
     {
     default:
-      abort ();
+      gcc_unreachable ();
 
     case SMIN: test_code = LT;  break;
     case SMAX: test_code = GT;  break;
@@ -6505,8 +5135,7 @@ frv_split_minmax (rtx operands[])
      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 ();
+      gcc_assert (!rtx_equal_p (dest, src1));
 
       emit_move_insn (dest, src2);
       emit_insn (gen_rtx_COND_EXEC (VOIDmode,
@@ -6684,8 +5313,8 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
   /* 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))
+  if (!reload_completed || !TARGET_COND_EXEC
+      || (!TARGET_NESTED_CE && ce_info->pass > 1))
     goto fail;
 
   /* Figure out which registers we can allocate for our own purposes.  Only
@@ -6708,13 +5337,15 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
       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))
+           if (REGNO_REG_SET_P (df_get_live_in (then_bb), j))
              continue;
 
-           if (else_bb && REGNO_REG_SET_P (else_bb->global_live_at_start, j))
+           if (else_bb
+               && REGNO_REG_SET_P (df_get_live_in (else_bb), j))
              continue;
 
-           if (join_bb && REGNO_REG_SET_P (join_bb->global_live_at_start, j))
+           if (join_bb
+               && REGNO_REG_SET_P (df_get_live_in (join_bb), j))
              continue;
 
            SET_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite, j);
@@ -6732,11 +5363,11 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
 
   if (join_bb)
     {
-      int regno;
+      unsigned 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, rsi)
+      EXECUTE_IF_SET_IN_REG_SET (df_get_live_in (join_bb), 0, regno, rsi)
        {
          if (regno < FIRST_PSEUDO_REGISTER)
            CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
@@ -6769,7 +5400,7 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
     {
       rtx last_insn = BB_END (bb[j]);
       rtx insn = BB_HEAD (bb[j]);
-      int regno;
+      unsigned int regno;
 
       if (dump_file)
        fprintf (dump_file, "Scanning %s block %d, start %d, end %d\n",
@@ -6780,7 +5411,7 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
 
       /* 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, rsi)
+      EXECUTE_IF_SET_IN_REG_SET (df_get_live_in (bb[j]), 0, regno, rsi)
        {
          if (regno < FIRST_PSEUDO_REGISTER)
            CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
@@ -6895,7 +5526,7 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
   /* 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)
+  if (mode == CCmode || mode == CC_UNSmode || mode == CC_NZmode)
     {
       cr_class = ICR_REGS;
       cc_class = ICC_REGS;
@@ -7044,13 +5675,13 @@ frv_ifcvt_modify_multiple_tests (ce_if_block_t *ce_info,
       debug_rtx (*p_false);
     }
 
-  if (TARGET_NO_MULTI_CE)
+  if (!TARGET_MULTI_CE)
     goto fail;
 
   if (GET_CODE (cr) != REG)
     goto fail;
 
-  if (mode == CCmode || mode == CC_UNSmode)
+  if (mode == CCmode || mode == CC_UNSmode || mode == CC_NZmode)
     {
       cr_class = ICR_REGS;
       p_new_cr = &frv_ifcvt.extra_int_cr;
@@ -7314,8 +5945,7 @@ frv_ifcvt_modify_insn (ce_if_block_t *ce_info,
   rtx op1;
   rtx test;
 
-  if (GET_CODE (pattern) != COND_EXEC)
-    abort ();
+  gcc_assert (GET_CODE (pattern) == COND_EXEC);
 
   test = COND_EXEC_TEST (pattern);
   if (GET_CODE (test) == AND)
@@ -7408,7 +6038,7 @@ frv_ifcvt_modify_insn (ce_if_block_t *ce_info,
                goto fail;
            }
 
-         frv_ifcvt_add_insn (gen_rtx_USE (VOIDmode, dest), insn, FALSE);
+         frv_ifcvt_add_insn (gen_use (dest), insn, FALSE);
        }
 
       /* If we are just loading a constant created for a nested conditional
@@ -7418,15 +6048,31 @@ frv_ifcvt_modify_insn (ce_if_block_t *ce_info,
       else if (frv_ifcvt.scratch_insns_bitmap
               && bitmap_bit_p (frv_ifcvt.scratch_insns_bitmap,
                                INSN_UID (insn))
-              /* We must not unconditionally set a reg set used as
-                 scratch in the THEN branch if the same reg is live
-                 in the ELSE branch.  */
               && REG_P (SET_DEST (set))
+              /* We must not unconditionally set a scratch reg chosen
+                 for a nested if-converted block if its incoming
+                 value from the TEST block (or the result of the THEN
+                 branch) could/should propagate to the JOIN block.
+                 It suffices to test whether the register is live at
+                 the JOIN point: if it's live there, we can infer
+                 that we set it in the former JOIN block of the
+                 nested if-converted block (otherwise it wouldn't
+                 have been available as a scratch register), and it
+                 is either propagated through or set in the other
+                 conditional block.  It's probably not worth trying
+                 to catch the latter case, and it could actually
+                 limit scheduling of the combined block quite
+                 severely.  */
+              && ce_info->join_bb
+              && ! (REGNO_REG_SET_P (df_get_live_in (ce_info->join_bb),
+                                     REGNO (SET_DEST (set))))
+              /* Similarly, we must not unconditionally set a reg
+                 used as scratch in the THEN branch if the same reg
+                 is live in the ELSE branch.  */
               && (! ce_info->else_bb
                   || BLOCK_FOR_INSN (insn) == ce_info->else_bb
-                  || ! (REGNO_REG_SET_P
-                        (ce_info->else_bb->global_live_at_start,
-                         REGNO (SET_DEST (set))))))
+                  || ! (REGNO_REG_SET_P (df_get_live_in (ce_info->else_bb),
+                                         REGNO (SET_DEST (set))))))
        pattern = set;
 
       else if (mode == QImode || mode == HImode || mode == SImode
@@ -7563,8 +6209,7 @@ frv_ifcvt_modify_final (ce_if_block_t *ce_info ATTRIBUTE_UNUSED)
 
   /* Loop inserting the check insns.  The last check insn is the first test,
      and is the appropriate place to insert constants.  */
-  if (! p)
-    abort ();
+  gcc_assert (p);
 
   do
     {
@@ -7595,7 +6240,7 @@ frv_ifcvt_modify_final (ce_if_block_t *ce_info ATTRIBUTE_UNUSED)
     {
       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 ();
+       frv_ifcvt.scratch_insns_bitmap = BITMAP_ALLOC (NULL);
       bitmap_set_bit (frv_ifcvt.scratch_insns_bitmap, INSN_UID (insn));
       frv_ifcvt.scratch_regs[i] = NULL_RTX;
     }
@@ -7694,11 +6339,11 @@ frv_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
    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
+   RCLASS 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
+   If copying a register RCLASS 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
@@ -7706,7 +6351,7 @@ frv_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
 
    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.
+   to or from a register of RCLASS 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
@@ -7717,7 +6362,7 @@ frv_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
 
    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
+   RCLASS) 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.
@@ -7735,14 +6380,13 @@ frv_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
    This case often occurs between floating-point and general registers.  */
 
 enum reg_class
-frv_secondary_reload_class (enum reg_class class,
+frv_secondary_reload_class (enum reg_class rclass,
                             enum machine_mode mode ATTRIBUTE_UNUSED,
-                            rtx x,
-                            int in_p ATTRIBUTE_UNUSED)
+                            rtx x)
 {
   enum reg_class ret;
 
-  switch (class)
+  switch (rclass)
     {
     default:
       ret = NO_REGS;
@@ -7785,7 +6429,7 @@ frv_secondary_reload_class (enum reg_class class,
       ret = GPR_REGS;
       break;
 
-      /* The accumulators need fpr registers */
+      /* The accumulators need fpr registers */
     case ACC_REGS:
     case EVEN_ACC_REGS:
     case QUAD_ACC_REGS:
@@ -7797,12 +6441,48 @@ frv_secondary_reload_class (enum reg_class class,
   return ret;
 }
 
+/* This hook exists to catch the case where secondary_reload_class() is
+   called from init_reg_autoinc() in regclass.c - before the reload optabs
+   have been initialised.  */
+   
+static bool
+frv_secondary_reload (bool in_p, rtx x, enum reg_class reload_class,
+                     enum machine_mode reload_mode,
+                     secondary_reload_info * sri)
+{
+  enum reg_class rclass = NO_REGS;
+
+  if (sri->prev_sri && sri->prev_sri->t_icode != CODE_FOR_nothing)
+    {
+      sri->icode = sri->prev_sri->t_icode;
+      return NO_REGS;
+    }
+
+  rclass = frv_secondary_reload_class (reload_class, reload_mode, x);
+
+  if (rclass != NO_REGS)
+    {
+      enum insn_code icode = (in_p ? reload_in_optab[(int) reload_mode]
+                             : reload_out_optab[(int) reload_mode]);
+      if (icode == 0)
+       {
+         /* This happens when then the reload_[in|out]_optabs have
+            not been initialised.  */
+         sri->t_icode = CODE_FOR_nothing;
+         return rclass;
+       }
+    }
+
+  /* Fall back to the default secondary reload handler.  */
+  return default_secondary_reload (in_p, x, reload_class, reload_mode, sri);
+
+}
 \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
+   registers of class RCLASS would likely be spilled because registers of RCLASS
    are needed for spill registers.
 
-   The default value of this macro returns 1 if CLASS has exactly one register
+   The default value of this macro returns 1 if RCLASS 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
@@ -7814,13 +6494,18 @@ frv_secondary_reload_class (enum reg_class class,
    register allocation.  */
 
 int
-frv_class_likely_spilled_p (enum reg_class class)
+frv_class_likely_spilled_p (enum reg_class rclass)
 {
-  switch (class)
+  switch (rclass)
     {
     default:
       break;
 
+    case GR8_REGS:
+    case GR9_REGS:
+    case GR89_REGS:
+    case FDPIC_FPTR_REGS:
+    case FDPIC_REGS:
     case ICC_REGS:
     case FCC_REGS:
     case CC_REGS:
@@ -7907,8 +6592,7 @@ frv_adjust_field_align (tree field, int computed)
          prev = cur;
        }
 
-      if (!cur)
-       abort ();
+      gcc_assert (cur);
 
       /* 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
@@ -7992,6 +6676,7 @@ frv_hard_regno_mode_ok (int regno, enum machine_mode mode)
     {
     case CCmode:
     case CC_UNSmode:
+    case CC_NZmode:
       return ICC_P (regno) || GPR_P (regno);
 
     case CC_CCRmode:
@@ -8075,11 +6760,11 @@ frv_hard_regno_nregs (int regno, enum machine_mode mode)
 
 \f
 /* A C expression for the maximum number of consecutive registers of
-   class CLASS needed to hold a value of mode MODE.
+   class RCLASS 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.
+   of the macro `CLASS_MAX_NREGS (RCLASS, MODE)' should be the maximum value of
+   `HARD_REGNO_NREGS (REGNO, MODE)' for all REGNO values in the class RCLASS.
 
    This macro helps control the handling of multiple-word values in
    the reload pass.
@@ -8087,9 +6772,9 @@ frv_hard_regno_nregs (int regno, enum machine_mode mode)
    This declaration is required.  */
 
 int
-frv_class_max_nregs (enum reg_class class, enum machine_mode mode)
+frv_class_max_nregs (enum reg_class rclass, enum machine_mode mode)
 {
-  if (class == ACCG_REGS)
+  if (rclass == ACCG_REGS)
     /* An N-byte value requires N accumulator guards.  */
     return GET_MODE_SIZE (mode);
   else
@@ -8146,6 +6831,36 @@ frv_legitimate_constant_p (rtx x)
   /* Otherwise store the constant away and do a load.  */
   return FALSE;
 }
+
+/* Implement SELECT_CC_MODE.  Choose CC_FP for floating-point comparisons,
+   CC_NZ for comparisons against zero in which a single Z or N flag test
+   is enough, CC_UNS for other unsigned comparisons, and CC for other
+   signed comparisons.  */
+
+enum machine_mode
+frv_select_cc_mode (enum rtx_code code, rtx x, rtx y)
+{
+  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+    return CC_FPmode;
+
+  switch (code)
+    {
+    case EQ:
+    case NE:
+    case LT:
+    case GE:
+      return y == const0_rtx ? CC_NZmode : CCmode;
+
+    case GTU:
+    case GEU:
+    case LTU:
+    case LEU:
+      return y == const0_rtx ? CC_NZmode : CC_UNSmode;
+
+    default:
+      return CCmode;
+    }
+}
 \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
@@ -8309,7 +7024,7 @@ frv_assemble_integer (rtx value, unsigned int size, int aligned_p)
 static struct machine_function *
 frv_init_machine_status (void)
 {
-  return ggc_alloc_cleared (sizeof (struct machine_function));
+  return GGC_CNEW (struct machine_function);
 }
 \f
 /* Implement TARGET_SCHED_ISSUE_RATE.  */
@@ -8397,8 +7112,7 @@ frv_insn_unit (rtx insn)
        if (cpu_unit_reservation_p (state, frv_unit_codes[unit]))
          break;
 
-      if (unit == ARRAY_SIZE (frv_unit_codes))
-       abort ();
+      gcc_assert (unit != ARRAY_SIZE (frv_unit_codes));
 
       frv_type_to_unit[type] = unit;
     }
@@ -8466,15 +7180,14 @@ static struct {
 static int
 frv_cond_flags (rtx cond)
 {
-  if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
-      && GET_CODE (XEXP (cond, 0)) == REG
-      && CR_P (REGNO (XEXP (cond, 0)))
-      && XEXP (cond, 1) == const0_rtx)
-    return ((REGNO (XEXP (cond, 0)) - CR_FIRST)
-           | (GET_CODE (cond) == NE
-              ? REGSTATE_IF_TRUE
-              : REGSTATE_IF_FALSE));
-  abort ();
+  gcc_assert ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
+             && GET_CODE (XEXP (cond, 0)) == REG
+             && CR_P (REGNO (XEXP (cond, 0)))
+             && XEXP (cond, 1) == const0_rtx);
+  return ((REGNO (XEXP (cond, 0)) - CR_FIRST)
+         | (GET_CODE (cond) == NE
+            ? REGSTATE_IF_TRUE
+            : REGSTATE_IF_FALSE));
 }
 
 
@@ -8579,7 +7292,7 @@ frv_registers_conflict_p (rtx x)
    under which X is modified.  Update FRV_PACKET accordingly.  */
 
 static void
-frv_registers_update_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
+frv_registers_update_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
 {
   unsigned int regno;
 
@@ -8757,7 +7470,7 @@ frv_for_each_packet (void (*handle_packet) (void))
   /* Early exit if we don't want to pack insns.  */
   if (!optimize
       || !flag_schedule_insns_after_reload
-      || TARGET_NO_VLIW_BRANCH
+      || !TARGET_VLIW_BRANCH
       || frv_packet.issue_rate == 1)
     return false;
 
@@ -8886,7 +7599,8 @@ frv_sort_insn_group_1 (enum frv_insn_group group,
 static int
 frv_compare_insns (const void *first, const void *second)
 {
-  const rtx *insn1 = first, *insn2 = second;
+  const rtx *const insn1 = (rtx const *) first,
+    *const insn2 = (rtx const *) second;
   return frv_insn_unit (*insn1) - frv_insn_unit (*insn2);
 }
 
@@ -8903,6 +7617,10 @@ frv_sort_insn_group (enum frv_insn_group group)
   size_t dfa_size;
 
   packet_group = &frv_packet.groups[group];
+
+  /* Assume no nop is needed.  */
+  packet_group->nop = 0;
+
   if (packet_group->num_insns == 0)
     return;
 
@@ -8955,7 +7673,7 @@ frv_sort_insn_group (enum frv_insn_group group)
            return;
        }
     }
-  abort ();
+  gcc_unreachable ();
 }
 \f
 /* Sort the current packet into assembly-language order.  Set packing
@@ -8987,14 +7705,13 @@ frv_reorder_packet (void)
       if (cursor[group] < packet_group->num_insns)
        {
          /* frv_reorg should have added nops for us.  */
-         if (packet_group->sorted[cursor[group]] == packet_group->nop)
-           abort ();
+         gcc_assert (packet_group->sorted[cursor[group]]
+                     != packet_group->nop);
          insns[to++] = packet_group->sorted[cursor[group]++];
        }
     }
 
-  if (to != frv_packet.num_insns)
-    abort ();
+  gcc_assert (to == frv_packet.num_insns);
 
   /* Clear the last instruction's packing flag, thus marking the end of
      a packet.  Reorder the other instructions relative to it.  */
@@ -9002,7 +7719,7 @@ frv_reorder_packet (void)
   for (from = 0; from < to - 1; from++)
     {
       remove_insn (insns[from]);
-      add_insn_before (insns[from], insns[to - 1]);
+      add_insn_before (insns[from], insns[to - 1], NULL);
       SET_PACKING_FLAG (insns[from]);
     }
 }
@@ -9050,6 +7767,334 @@ frv_fill_unused_units (enum frv_insn_group group)
     frv_insert_nop_in_packet (packet_group->nop);
 }
 
+/* Return true if accesses IO1 and IO2 refer to the same doubleword.  */
+
+static bool
+frv_same_doubleword_p (const struct frv_io *io1, const struct frv_io *io2)
+{
+  if (io1->const_address != 0 && io2->const_address != 0)
+    return io1->const_address == io2->const_address;
+
+  if (io1->var_address != 0 && io2->var_address != 0)
+    return rtx_equal_p (io1->var_address, io2->var_address);
+
+  return false;
+}
+
+/* Return true if operations IO1 and IO2 are guaranteed to complete
+   in order.  */
+
+static bool
+frv_io_fixed_order_p (const struct frv_io *io1, const struct frv_io *io2)
+{
+  /* The order of writes is always preserved.  */
+  if (io1->type == FRV_IO_WRITE && io2->type == FRV_IO_WRITE)
+    return true;
+
+  /* The order of reads isn't preserved.  */
+  if (io1->type != FRV_IO_WRITE && io2->type != FRV_IO_WRITE)
+    return false;
+
+  /* One operation is a write and the other is (or could be) a read.
+     The order is only guaranteed if the accesses are to the same
+     doubleword.  */
+  return frv_same_doubleword_p (io1, io2);
+}
+
+/* Generalize I/O operation X so that it covers both X and Y. */
+
+static void
+frv_io_union (struct frv_io *x, const struct frv_io *y)
+{
+  if (x->type != y->type)
+    x->type = FRV_IO_UNKNOWN;
+  if (!frv_same_doubleword_p (x, y))
+    {
+      x->const_address = 0;
+      x->var_address = 0;
+    }
+}
+
+/* Fill IO with information about the load or store associated with
+   membar instruction INSN.  */
+
+static void
+frv_extract_membar (struct frv_io *io, rtx insn)
+{
+  extract_insn (insn);
+  io->type = INTVAL (recog_data.operand[2]);
+  io->const_address = INTVAL (recog_data.operand[1]);
+  io->var_address = XEXP (recog_data.operand[0], 0);
+}
+
+/* A note_stores callback for which DATA points to an rtx.  Nullify *DATA
+   if X is a register and *DATA depends on X.  */
+
+static void
+frv_io_check_address (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
+{
+  rtx *other = (rtx *) data;
+
+  if (REG_P (x) && *other != 0 && reg_overlap_mentioned_p (x, *other))
+    *other = 0;
+}
+
+/* A note_stores callback for which DATA points to a HARD_REG_SET.
+   Remove every modified register from the set.  */
+
+static void
+frv_io_handle_set (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
+{
+  HARD_REG_SET *set = (HARD_REG_SET *) data;
+  unsigned int regno;
+
+  if (REG_P (x))
+    FOR_EACH_REGNO (regno, x)
+      CLEAR_HARD_REG_BIT (*set, regno);
+}
+
+/* A for_each_rtx callback for which DATA points to a HARD_REG_SET.
+   Add every register in *X to the set.  */
+
+static int
+frv_io_handle_use_1 (rtx *x, void *data)
+{
+  HARD_REG_SET *set = (HARD_REG_SET *) data;
+  unsigned int regno;
+
+  if (REG_P (*x))
+    FOR_EACH_REGNO (regno, *x)
+      SET_HARD_REG_BIT (*set, regno);
+
+  return 0;
+}
+
+/* A note_stores callback that applies frv_io_handle_use_1 to an
+   entire rhs value.  */
+
+static void
+frv_io_handle_use (rtx *x, void *data)
+{
+  for_each_rtx (x, frv_io_handle_use_1, data);
+}
+
+/* Go through block BB looking for membars to remove.  There are two
+   cases where intra-block analysis is enough:
+
+   - a membar is redundant if it occurs between two consecutive I/O
+   operations and if those operations are guaranteed to complete
+   in order.
+
+   - a membar for a __builtin_read is redundant if the result is
+   used before the next I/O operation is issued.
+
+   If the last membar in the block could not be removed, and there
+   are guaranteed to be no I/O operations between that membar and
+   the end of the block, store the membar in *LAST_MEMBAR, otherwise
+   store null.
+
+   Describe the block's first I/O operation in *NEXT_IO.  Describe
+   an unknown operation if the block doesn't do any I/O.  */
+
+static void
+frv_optimize_membar_local (basic_block bb, struct frv_io *next_io,
+                          rtx *last_membar)
+{
+  HARD_REG_SET used_regs;
+  rtx next_membar, set, insn;
+  bool next_is_end_p;
+
+  /* NEXT_IO is the next I/O operation to be performed after the current
+     instruction.  It starts off as being an unknown operation.  */
+  memset (next_io, 0, sizeof (*next_io));
+
+  /* NEXT_IS_END_P is true if NEXT_IO describes the end of the block.  */
+  next_is_end_p = true;
+
+  /* If the current instruction is a __builtin_read or __builtin_write,
+     NEXT_MEMBAR is the membar instruction associated with it.  NEXT_MEMBAR
+     is null if the membar has already been deleted.
+
+     Note that the initialization here should only be needed to
+     suppress warnings.  */
+  next_membar = 0;
+
+  /* USED_REGS is the set of registers that are used before the
+     next I/O instruction.  */
+  CLEAR_HARD_REG_SET (used_regs);
+
+  for (insn = BB_END (bb); insn != BB_HEAD (bb); insn = PREV_INSN (insn))
+    if (GET_CODE (insn) == CALL_INSN)
+      {
+       /* We can't predict what a call will do to volatile memory.  */
+       memset (next_io, 0, sizeof (struct frv_io));
+       next_is_end_p = false;
+       CLEAR_HARD_REG_SET (used_regs);
+      }
+    else if (INSN_P (insn))
+      switch (recog_memoized (insn))
+       {
+       case CODE_FOR_optional_membar_qi:
+       case CODE_FOR_optional_membar_hi:
+       case CODE_FOR_optional_membar_si:
+       case CODE_FOR_optional_membar_di:
+         next_membar = insn;
+         if (next_is_end_p)
+           {
+             /* Local information isn't enough to decide whether this
+                membar is needed.  Stash it away for later.  */
+             *last_membar = insn;
+             frv_extract_membar (next_io, insn);
+             next_is_end_p = false;
+           }
+         else
+           {
+             /* Check whether the I/O operation before INSN could be
+                reordered with one described by NEXT_IO.  If it can't,
+                INSN will not be needed.  */
+             struct frv_io prev_io;
+
+             frv_extract_membar (&prev_io, insn);
+             if (frv_io_fixed_order_p (&prev_io, next_io))
+               {
+                 if (dump_file)
+                   fprintf (dump_file,
+                            ";; [Local] Removing membar %d since order"
+                            " of accesses is guaranteed\n",
+                            INSN_UID (next_membar));
+
+                 insn = NEXT_INSN (insn);
+                 delete_insn (next_membar);
+                 next_membar = 0;
+               }
+             *next_io = prev_io;
+           }
+         break;
+
+       default:
+         /* Invalidate NEXT_IO's address if it depends on something that
+            is clobbered by INSN.  */
+         if (next_io->var_address)
+           note_stores (PATTERN (insn), frv_io_check_address,
+                        &next_io->var_address);
+
+         /* If the next membar is associated with a __builtin_read,
+            see if INSN reads from that address.  If it does, and if
+            the destination register is used before the next I/O access,
+            there is no need for the membar.  */
+         set = PATTERN (insn);
+         if (next_io->type == FRV_IO_READ
+             && next_io->var_address != 0
+             && next_membar != 0
+             && GET_CODE (set) == SET
+             && GET_CODE (SET_DEST (set)) == REG
+             && TEST_HARD_REG_BIT (used_regs, REGNO (SET_DEST (set))))
+           {
+             rtx src;
+
+             src = SET_SRC (set);
+             if (GET_CODE (src) == ZERO_EXTEND)
+               src = XEXP (src, 0);
+
+             if (GET_CODE (src) == MEM
+                 && rtx_equal_p (XEXP (src, 0), next_io->var_address))
+               {
+                 if (dump_file)
+                   fprintf (dump_file,
+                            ";; [Local] Removing membar %d since the target"
+                            " of %d is used before the I/O operation\n",
+                            INSN_UID (next_membar), INSN_UID (insn));
+
+                 if (next_membar == *last_membar)
+                   *last_membar = 0;
+
+                 delete_insn (next_membar);
+                 next_membar = 0;
+               }
+           }
+
+         /* If INSN has volatile references, forget about any registers
+            that are used after it.  Otherwise forget about uses that
+            are (or might be) defined by INSN.  */
+         if (volatile_refs_p (PATTERN (insn)))
+           CLEAR_HARD_REG_SET (used_regs);
+         else
+           note_stores (PATTERN (insn), frv_io_handle_set, &used_regs);
+
+         note_uses (&PATTERN (insn), frv_io_handle_use, &used_regs);
+         break;
+       }
+}
+
+/* See if MEMBAR, the last membar instruction in BB, can be removed.
+   FIRST_IO[X] describes the first operation performed by basic block X.  */
+
+static void
+frv_optimize_membar_global (basic_block bb, struct frv_io *first_io,
+                           rtx membar)
+{
+  struct frv_io this_io, next_io;
+  edge succ;
+  edge_iterator ei;
+
+  /* We need to keep the membar if there is an edge to the exit block.  */
+  FOR_EACH_EDGE (succ, ei, bb->succs)
+  /* for (succ = bb->succ; succ != 0; succ = succ->succ_next) */
+    if (succ->dest == EXIT_BLOCK_PTR)
+      return;
+
+  /* Work out the union of all successor blocks.  */
+  ei = ei_start (bb->succs);
+  ei_cond (ei, &succ);
+  /* next_io = first_io[bb->succ->dest->index]; */
+  next_io = first_io[succ->dest->index];
+  ei = ei_start (bb->succs);
+  if (ei_cond (ei, &succ))
+    {
+      for (ei_next (&ei); ei_cond (ei, &succ); ei_next (&ei))
+       /*for (succ = bb->succ->succ_next; succ != 0; succ = succ->succ_next)*/
+       frv_io_union (&next_io, &first_io[succ->dest->index]);
+    }
+  else
+    gcc_unreachable ();
+
+  frv_extract_membar (&this_io, membar);
+  if (frv_io_fixed_order_p (&this_io, &next_io))
+    {
+      if (dump_file)
+       fprintf (dump_file,
+                ";; [Global] Removing membar %d since order of accesses"
+                " is guaranteed\n", INSN_UID (membar));
+
+      delete_insn (membar);
+    }
+}
+
+/* Remove redundant membars from the current function.  */
+
+static void
+frv_optimize_membar (void)
+{
+  basic_block bb;
+  struct frv_io *first_io;
+  rtx *last_membar;
+
+  compute_bb_for_insn ();
+  first_io = XCNEWVEC (struct frv_io, last_basic_block);
+  last_membar = XCNEWVEC (rtx, last_basic_block);
+
+  FOR_EACH_BB (bb)
+    frv_optimize_membar_local (bb, &first_io[bb->index],
+                              &last_membar[bb->index]);
+
+  FOR_EACH_BB (bb)
+    if (last_membar[bb->index] != 0)
+      frv_optimize_membar_global (bb, first_io, last_membar[bb->index]);
+
+  free (first_io);
+  free (last_membar);
+}
+\f
 /* Used by frv_reorg to keep track of the current packet's address.  */
 static unsigned int frv_packet_address;
 
@@ -9162,6 +8207,9 @@ frv_register_nop (rtx nop)
 static void
 frv_reorg (void)
 {
+  if (optimize > 0 && TARGET_OPTIMIZE_MEMBAR && cfun->machine->has_membar_p)
+    frv_optimize_membar ();
+
   frv_num_nops = 0;
   frv_register_nop (gen_nop ());
   if (TARGET_MEDIA)
@@ -9178,7 +8226,7 @@ frv_reorg (void)
 }
 \f
 #define def_builtin(name, type, code) \
-  lang_hooks.builtin_function ((name), (type), (code), BUILT_IN_MD, NULL, NULL)
+  add_builtin_function ((name), (type), (code), BUILT_IN_MD, NULL, NULL)
 
 struct builtin_description
 {
@@ -9227,7 +8275,6 @@ static struct builtin_description bdesc_2arg[] =
   { 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 },
@@ -9343,6 +8390,35 @@ static struct builtin_description bdesc_voidacc[] =
   { CODE_FOR_mdasaccs, "__MDASACCS", FRV_BUILTIN_MDASACCS, 0, 0 }
 };
 
+/* Intrinsics that load a value and then issue a MEMBAR.  The load is
+   a normal move and the ICODE is for the membar.  */
+
+static struct builtin_description bdesc_loads[] =
+{
+  { CODE_FOR_optional_membar_qi, "__builtin_read8",
+    FRV_BUILTIN_READ8, 0, 0 },
+  { CODE_FOR_optional_membar_hi, "__builtin_read16",
+    FRV_BUILTIN_READ16, 0, 0 },
+  { CODE_FOR_optional_membar_si, "__builtin_read32",
+    FRV_BUILTIN_READ32, 0, 0 },
+  { CODE_FOR_optional_membar_di, "__builtin_read64",
+    FRV_BUILTIN_READ64, 0, 0 }
+};
+
+/* Likewise stores.  */
+
+static struct builtin_description bdesc_stores[] =
+{
+  { CODE_FOR_optional_membar_qi, "__builtin_write8",
+    FRV_BUILTIN_WRITE8, 0, 0 },
+  { CODE_FOR_optional_membar_hi, "__builtin_write16",
+    FRV_BUILTIN_WRITE16, 0, 0 },
+  { CODE_FOR_optional_membar_si, "__builtin_write32",
+    FRV_BUILTIN_WRITE32, 0, 0 },
+  { CODE_FOR_optional_membar_di, "__builtin_write64",
+    FRV_BUILTIN_WRITE64, 0, 0 },
+};
+
 /* Initialize media builtins.  */
 
 static void
@@ -9358,6 +8434,8 @@ frv_init_builtins (void)
   tree sword2 = long_long_integer_type_node;
   tree uword2 = long_long_unsigned_type_node;
   tree uword4 = build_pointer_type (uword1);
+  tree vptr   = build_pointer_type (build_type_variant (void_type_node, 0, 1));
+  tree ubyte  = unsigned_char_type_node;
   tree iacc   = integer_type_node;
 
 #define UNARY(RET, T1) \
@@ -9372,6 +8450,12 @@ frv_init_builtins (void)
                            tree_cons (NULL_TREE, T2, \
                            tree_cons (NULL_TREE, T3, endlink))))
 
+#define QUAD(RET, T1, T2, T3, T4) \
+  build_function_type (RET, tree_cons (NULL_TREE, T1, \
+                           tree_cons (NULL_TREE, T2, \
+                           tree_cons (NULL_TREE, T3, \
+                           tree_cons (NULL_TREE, T4, endlink)))))
+
   tree void_ftype_void = build_function_type (voidt, endlink);
 
   tree void_ftype_acc = UNARY (voidt, accumulator);
@@ -9405,6 +8489,7 @@ frv_init_builtins (void)
   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 uw2_ftype_uh_uh_uh_uh = QUAD (uword2, uhalf, uhalf, uhalf, uhalf);
 
   tree sw2_ftype_sw2_sw2 = BINARY (sword2, sword2, sword2);
   tree sw2_ftype_sw2_int   = BINARY (sword2, sword2, integer);
@@ -9417,6 +8502,12 @@ frv_init_builtins (void)
   tree sw2_ftype_iacc      = UNARY (sword2, iacc);
   tree sw1_ftype_iacc      = UNARY (sword1, iacc);
   tree void_ftype_ptr      = UNARY (voidt, const_ptr_type_node);
+  tree uw1_ftype_vptr      = UNARY (uword1, vptr);
+  tree uw2_ftype_vptr      = UNARY (uword2, vptr);
+  tree void_ftype_vptr_ub  = BINARY (voidt, vptr, ubyte);
+  tree void_ftype_vptr_uh  = BINARY (voidt, vptr, uhalf);
+  tree void_ftype_vptr_uw1 = BINARY (voidt, vptr, uword1);
+  tree void_ftype_vptr_uw2 = BINARY (voidt, vptr, uword2);
 
   def_builtin ("__MAND", uw1_ftype_uw1_uw1, FRV_BUILTIN_MAND);
   def_builtin ("__MOR", uw1_ftype_uw1_uw1, FRV_BUILTIN_MOR);
@@ -9467,7 +8558,7 @@ frv_init_builtins (void)
   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 ("__MDPACKH", uw2_ftype_uh_uh_uh_uh, 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);
@@ -9522,10 +8613,20 @@ frv_init_builtins (void)
   def_builtin ("__IACCsetl", void_ftype_iacc_sw1, FRV_BUILTIN_IACCsetl);
   def_builtin ("__data_prefetch0", void_ftype_ptr, FRV_BUILTIN_PREFETCH0);
   def_builtin ("__data_prefetch", void_ftype_ptr, FRV_BUILTIN_PREFETCH);
+  def_builtin ("__builtin_read8", uw1_ftype_vptr, FRV_BUILTIN_READ8);
+  def_builtin ("__builtin_read16", uw1_ftype_vptr, FRV_BUILTIN_READ16);
+  def_builtin ("__builtin_read32", uw1_ftype_vptr, FRV_BUILTIN_READ32);
+  def_builtin ("__builtin_read64", uw2_ftype_vptr, FRV_BUILTIN_READ64);
+
+  def_builtin ("__builtin_write8", void_ftype_vptr_ub, FRV_BUILTIN_WRITE8);
+  def_builtin ("__builtin_write16", void_ftype_vptr_uh, FRV_BUILTIN_WRITE16);
+  def_builtin ("__builtin_write32", void_ftype_vptr_uw1, FRV_BUILTIN_WRITE32);
+  def_builtin ("__builtin_write64", void_ftype_vptr_uw2, FRV_BUILTIN_WRITE64);
 
 #undef UNARY
 #undef BINARY
 #undef TRINARY
+#undef QUAD
 }
 
 /* Set the names for various arithmetic operations according to the
@@ -9588,7 +8689,7 @@ frv_int_to_acc (enum insn_code icode, int opnum, rtx opval)
   rtx reg;
   int i;
 
-  /* ACCs and ACCGs are implicity global registers if media intrinsics
+  /* ACCs and ACCGs are implicit global registers if media intrinsics
      are being used.  We set up this lazily to avoid creating lots of
      unnecessary call_insn rtl in non-media code.  */
   for (i = 0; i <= ACC_MASK; i++)
@@ -9609,7 +8710,7 @@ frv_int_to_acc (enum insn_code icode, int opnum, rtx opval)
   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);
+    SET_REGNO (reg, ACCG_FIRST + INTVAL (opval));
 
   if (! (*insn_data[icode].operand[opnum].predicate) (reg, VOIDmode))
     {
@@ -9637,10 +8738,22 @@ frv_matching_accg_mode (enum machine_mode mode)
       return QImode;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
+/* Given that a __builtin_read or __builtin_write function is accessing
+   address ADDRESS, return the value that should be used as operand 1
+   of the membar.  */
+
+static rtx
+frv_io_address_cookie (rtx address)
+{
+  return (GET_CODE (address) == CONST_INT
+         ? GEN_INT (INTVAL (address) / 8 * 8)
+         : const0_rtx);
+}
+
 /* 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.  */
@@ -9652,28 +8765,27 @@ frv_matching_accg_for_acc (rtx 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.  */
+/* Read the requested argument from the call EXP given by INDEX.
+   Return the value as an rtx.  */
 
 static rtx
-frv_read_argument (tree *arglistptr)
+frv_read_argument (tree exp, unsigned int index)
 {
-  tree next = TREE_VALUE (*arglistptr);
-  *arglistptr = TREE_CHAIN (*arglistptr);
-  return expand_expr (next, NULL_RTX, VOIDmode, 0);
+  return expand_expr (CALL_EXPR_ARG (exp, index),
+                     NULL_RTX, VOIDmode, 0);
 }
 
 /* Like frv_read_argument, but interpret the argument as the number
    of an IACC register and return a (reg:MODE ...) rtx for it.  */
 
 static rtx
-frv_read_iacc_argument (enum machine_mode mode, tree *arglistptr)
+frv_read_iacc_argument (enum machine_mode mode, tree call,
+                       unsigned int index)
 {
   int i, regno;
   rtx op;
 
-  op = frv_read_argument (arglistptr);
+  op = frv_read_argument (call, index);
   if (GET_CODE (op) != CONST_INT
       || INTVAL (op) < 0
       || INTVAL (op) > IACC_LAST - IACC_FIRST
@@ -9683,7 +8795,7 @@ frv_read_iacc_argument (enum machine_mode mode, tree *arglistptr)
       op = const0_rtx;
     }
 
-  /* IACCs are implicity global registers.  We set up this lazily to
+  /* IACCs are implicit global registers.  We set up this lazily to
      avoid creating lots of unnecessary call_insn rtl when IACCs aren't
      being used.  */
   regno = INTVAL (op) + IACC_FIRST;
@@ -9746,14 +8858,26 @@ frv_legitimize_argument (enum insn_code icode, int opnum, rtx arg)
     return copy_to_mode_reg (mode, arg);
 }
 
+/* Return a volatile memory reference of mode MODE whose address is ARG.  */
+
+static rtx
+frv_volatile_memref (enum machine_mode mode, rtx arg)
+{
+  rtx mem;
+
+  mem = gen_rtx_MEM (mode, memory_address (mode, arg));
+  MEM_VOLATILE_P (mem) = 1;
+  return mem;
+}
+
 /* Expand builtins that take a single, constant argument.  At the moment,
    only MHDSETS falls into this category.  */
 
 static rtx
-frv_expand_set_builtin (enum insn_code icode, tree arglist, rtx target)
+frv_expand_set_builtin (enum insn_code icode, tree call, rtx target)
 {
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
 
   if (! frv_check_constant_argument (icode, 1, op0))
     return NULL_RTX;
@@ -9770,10 +8894,10 @@ frv_expand_set_builtin (enum insn_code icode, tree arglist, rtx target)
 /* Expand builtins that take one operand.  */
 
 static rtx
-frv_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
+frv_expand_unop_builtin (enum insn_code icode, tree call, rtx target)
 {
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
 
   target = frv_legitimize_target (icode, target);
   op0 = frv_legitimize_argument (icode, 1, op0);
@@ -9788,11 +8912,11 @@ frv_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
 /* Expand builtins that take two operands.  */
 
 static rtx
-frv_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
+frv_expand_binop_builtin (enum insn_code icode, tree call, rtx target)
 {
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
-  rtx op1 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
+  rtx op1 = frv_read_argument (call, 1);
 
   target = frv_legitimize_target (icode, target);
   op0 = frv_legitimize_argument (icode, 1, op0);
@@ -9809,11 +8933,11 @@ frv_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
    one.  */
 
 static rtx
-frv_expand_cut_builtin (enum insn_code icode, tree arglist, rtx target)
+frv_expand_cut_builtin (enum insn_code icode, tree call, rtx target)
 {
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
-  rtx op1 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
+  rtx op1 = frv_read_argument (call, 1);
   rtx op2;
 
   target = frv_legitimize_target (icode, target);
@@ -9841,11 +8965,11 @@ frv_expand_cut_builtin (enum insn_code icode, tree arglist, rtx target)
 /* Expand builtins that take two operands and the second is immediate.  */
 
 static rtx
-frv_expand_binopimm_builtin (enum insn_code icode, tree arglist, rtx target)
+frv_expand_binopimm_builtin (enum insn_code icode, tree call, rtx target)
 {
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
-  rtx op1 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
+  rtx op1 = frv_read_argument (call, 1);
 
   if (! frv_check_constant_argument (icode, 2, op1))
     return NULL_RTX;
@@ -9864,11 +8988,11 @@ frv_expand_binopimm_builtin (enum insn_code icode, tree arglist, rtx target)
    ints and return void.  */
 
 static rtx
-frv_expand_voidbinop_builtin (enum insn_code icode, tree arglist)
+frv_expand_voidbinop_builtin (enum insn_code icode, tree call)
 {
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
-  rtx op1 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
+  rtx op1 = frv_read_argument (call, 1);
   enum machine_mode mode0 = insn_data[icode].operand[0].mode;
   rtx addr;
 
@@ -9902,11 +9026,11 @@ frv_expand_voidbinop_builtin (enum insn_code icode, tree arglist)
 /* Expand builtins that take two long operands and return void.  */
 
 static rtx
-frv_expand_int_void2arg (enum insn_code icode, tree arglist)
+frv_expand_int_void2arg (enum insn_code icode, tree call)
 {
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
-  rtx op1 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
+  rtx op1 = frv_read_argument (call, 1);
 
   op0 = frv_legitimize_argument (icode, 1, op0);
   op1 = frv_legitimize_argument (icode, 1, op1);
@@ -9921,10 +9045,10 @@ frv_expand_int_void2arg (enum insn_code icode, tree arglist)
 /* Expand prefetch builtins.  These take a single address as argument.  */
 
 static rtx
-frv_expand_prefetches (enum insn_code icode, tree arglist)
+frv_expand_prefetches (enum insn_code icode, tree call)
 {
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
 
   pat = GEN_FCN (icode) (force_reg (Pmode, op0));
   if (! pat)
@@ -9940,12 +9064,12 @@ frv_expand_prefetches (enum insn_code icode, tree arglist)
    corresponds to the accumulator.  */
 
 static rtx
-frv_expand_voidtriop_builtin (enum insn_code icode, tree arglist)
+frv_expand_voidtriop_builtin (enum insn_code icode, tree call)
 {
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
-  rtx op1 = frv_read_argument (&arglist);
-  rtx op2 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
+  rtx op1 = frv_read_argument (call, 1);
+  rtx op2 = frv_read_argument (call, 2);
   rtx op3;
 
   op0 = frv_int_to_acc (icode, 0, op0);
@@ -9968,11 +9092,11 @@ frv_expand_voidtriop_builtin (enum insn_code icode, tree arglist)
    void.  */
 
 static rtx
-frv_expand_voidaccop_builtin (enum insn_code icode, tree arglist)
+frv_expand_voidaccop_builtin (enum insn_code icode, tree call)
 {
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
-  rtx op1 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
+  rtx op1 = frv_read_argument (call, 1);
   rtx op2;
   rtx op3;
 
@@ -9994,15 +9118,88 @@ frv_expand_voidaccop_builtin (enum insn_code icode, tree arglist)
   return NULL_RTX;
 }
 
+/* Expand a __builtin_read* function.  ICODE is the instruction code for the
+   membar and TARGET_MODE is the mode that the loaded value should have.  */
+
+static rtx
+frv_expand_load_builtin (enum insn_code icode, enum machine_mode target_mode,
+                         tree call, rtx target)
+{
+  rtx op0 = frv_read_argument (call, 0);
+  rtx cookie = frv_io_address_cookie (op0);
+
+  if (target == 0 || !REG_P (target))
+    target = gen_reg_rtx (target_mode);
+  op0 = frv_volatile_memref (insn_data[icode].operand[0].mode, op0);
+  convert_move (target, op0, 1);
+  emit_insn (GEN_FCN (icode) (copy_rtx (op0), cookie, GEN_INT (FRV_IO_READ)));
+  cfun->machine->has_membar_p = 1;
+  return target;
+}
+
+/* Likewise __builtin_write* functions.  */
+
+static rtx
+frv_expand_store_builtin (enum insn_code icode, tree call)
+{
+  rtx op0 = frv_read_argument (call, 0);
+  rtx op1 = frv_read_argument (call, 1);
+  rtx cookie = frv_io_address_cookie (op0);
+
+  op0 = frv_volatile_memref (insn_data[icode].operand[0].mode, op0);
+  convert_move (op0, force_reg (insn_data[icode].operand[0].mode, op1), 1);
+  emit_insn (GEN_FCN (icode) (copy_rtx (op0), cookie, GEN_INT (FRV_IO_WRITE)));
+  cfun->machine->has_membar_p = 1;
+  return NULL_RTX;
+}
+
+/* Expand the MDPACKH builtin.  It takes four unsigned short arguments and
+   each argument forms one word of the two double-word input registers.
+   CALL is the tree for the call and TARGET, if nonnull, suggests a good place
+   to put the return value.  */
+
+static rtx
+frv_expand_mdpackh_builtin (tree call, rtx target)
+{
+  enum insn_code icode = CODE_FOR_mdpackh;
+  rtx pat, op0, op1;
+  rtx arg1 = frv_read_argument (call, 0);
+  rtx arg2 = frv_read_argument (call, 1);
+  rtx arg3 = frv_read_argument (call, 2);
+  rtx arg4 = frv_read_argument (call, 3);
+
+  target = frv_legitimize_target (icode, target);
+  op0 = gen_reg_rtx (DImode);
+  op1 = gen_reg_rtx (DImode);
+
+  /* The high half of each word is not explicitly initialized, so indicate
+     that the input operands are not live before this point.  */
+  emit_clobber (op0);
+  emit_clobber (op1);
+
+  /* Move each argument into the low half of its associated input word.  */
+  emit_move_insn (simplify_gen_subreg (HImode, op0, DImode, 2), arg1);
+  emit_move_insn (simplify_gen_subreg (HImode, op0, DImode, 6), arg2);
+  emit_move_insn (simplify_gen_subreg (HImode, op1, DImode, 2), arg3);
+  emit_move_insn (simplify_gen_subreg (HImode, op1, DImode, 6), arg4);
+
+  pat = GEN_FCN (icode) (target, op0, op1);
+  if (! pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+  return target;
+}
+
 /* Expand the MCLRACC builtin.  This builtin takes a single accumulator
    number as argument.  */
 
 static rtx
-frv_expand_mclracc_builtin (tree arglist)
+frv_expand_mclracc_builtin (tree call)
 {
   enum insn_code icode = CODE_FOR_mclracc;
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
 
   op0 = frv_int_to_acc (icode, 0, op0);
   if (! op0)
@@ -10031,11 +9228,11 @@ frv_expand_noargs_builtin (enum insn_code icode)
    number or accumulator guard number as argument and return an SI integer.  */
 
 static rtx
-frv_expand_mrdacc_builtin (enum insn_code icode, tree arglist)
+frv_expand_mrdacc_builtin (enum insn_code icode, tree call)
 {
   rtx pat;
   rtx target = gen_reg_rtx (SImode);
-  rtx op0 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
 
   op0 = frv_int_to_acc (icode, 1, op0);
   if (! op0)
@@ -10054,11 +9251,11 @@ frv_expand_mrdacc_builtin (enum insn_code icode, tree arglist)
    second.  */
 
 static rtx
-frv_expand_mwtacc_builtin (enum insn_code icode, tree arglist)
+frv_expand_mwtacc_builtin (enum insn_code icode, tree call)
 {
   rtx pat;
-  rtx op0 = frv_read_argument (&arglist);
-  rtx op1 = frv_read_argument (&arglist);
+  rtx op0 = frv_read_argument (call, 0);
+  rtx op1 = frv_read_argument (call, 1);
 
   op0 = frv_int_to_acc (icode, 0, op0);
   if (! op0)
@@ -10096,8 +9293,7 @@ frv_expand_builtin (tree exp,
                     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);
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   unsigned fcode = (unsigned)DECL_FUNCTION_CODE (fndecl);
   unsigned i;
   struct builtin_description *d;
@@ -10201,7 +9397,7 @@ frv_expand_builtin (tree exp,
       return frv_expand_noargs_builtin (CODE_FOR_mtrap);
 
     case FRV_BUILTIN_MCLRACC:
-      return frv_expand_mclracc_builtin (arglist);
+      return frv_expand_mclracc_builtin (exp);
 
     case FRV_BUILTIN_MCLRACCA:
       if (TARGET_ACC_8)
@@ -10210,20 +9406,23 @@ frv_expand_builtin (tree exp,
        return frv_expand_noargs_builtin (CODE_FOR_mclracca4);
 
     case FRV_BUILTIN_MRDACC:
-      return frv_expand_mrdacc_builtin (CODE_FOR_mrdacc, arglist);
+      return frv_expand_mrdacc_builtin (CODE_FOR_mrdacc, exp);
 
     case FRV_BUILTIN_MRDACCG:
-      return frv_expand_mrdacc_builtin (CODE_FOR_mrdaccg, arglist);
+      return frv_expand_mrdacc_builtin (CODE_FOR_mrdaccg, exp);
 
     case FRV_BUILTIN_MWTACC:
-      return frv_expand_mwtacc_builtin (CODE_FOR_mwtacc, arglist);
+      return frv_expand_mwtacc_builtin (CODE_FOR_mwtacc, exp);
 
     case FRV_BUILTIN_MWTACCG:
-      return frv_expand_mwtacc_builtin (CODE_FOR_mwtaccg, arglist);
+      return frv_expand_mwtacc_builtin (CODE_FOR_mwtaccg, exp);
+
+    case FRV_BUILTIN_MDPACKH:
+      return frv_expand_mdpackh_builtin (exp, target);
 
     case FRV_BUILTIN_IACCreadll:
       {
-       rtx src = frv_read_iacc_argument (DImode, &arglist);
+       rtx src = frv_read_iacc_argument (DImode, exp, 0);
        if (target == 0 || !REG_P (target))
          target = gen_reg_rtx (DImode);
        frv_split_iacc_move (target, src);
@@ -10231,20 +9430,20 @@ frv_expand_builtin (tree exp,
       }
 
     case FRV_BUILTIN_IACCreadl:
-      return frv_read_iacc_argument (SImode, &arglist);
+      return frv_read_iacc_argument (SImode, exp, 0);
 
     case FRV_BUILTIN_IACCsetll:
       {
-       rtx dest = frv_read_iacc_argument (DImode, &arglist);
-       rtx src = frv_read_argument (&arglist);
+       rtx dest = frv_read_iacc_argument (DImode, exp, 0);
+       rtx src = frv_read_argument (exp, 1);
        frv_split_iacc_move (dest, force_reg (DImode, src));
        return 0;
       }
 
     case FRV_BUILTIN_IACCsetl:
       {
-       rtx dest = frv_read_iacc_argument (SImode, &arglist);
-       rtx src = frv_read_argument (&arglist);
+       rtx dest = frv_read_iacc_argument (SImode, exp, 0);
+       rtx src = frv_read_argument (exp, 1);
        emit_move_insn (dest, force_reg (SImode, src));
        return 0;
       }
@@ -10257,54 +9456,63 @@ frv_expand_builtin (tree exp,
 
   for (i = 0, d = bdesc_set; i < ARRAY_SIZE (bdesc_set); i++, d++)
     if (d->code == fcode)
-      return frv_expand_set_builtin (d->icode, arglist, target);
+      return frv_expand_set_builtin (d->icode, exp, target);
 
   for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
     if (d->code == fcode)
-      return frv_expand_unop_builtin (d->icode, arglist, target);
+      return frv_expand_unop_builtin (d->icode, exp, target);
 
   for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
     if (d->code == fcode)
-      return frv_expand_binop_builtin (d->icode, arglist, target);
+      return frv_expand_binop_builtin (d->icode, exp, target);
 
   for (i = 0, d = bdesc_cut; i < ARRAY_SIZE (bdesc_cut); i++, d++)
     if (d->code == fcode)
-      return frv_expand_cut_builtin (d->icode, arglist, target);
+      return frv_expand_cut_builtin (d->icode, exp, target);
 
   for (i = 0, d = bdesc_2argimm; i < ARRAY_SIZE (bdesc_2argimm); i++, d++)
     if (d->code == fcode)
-      return frv_expand_binopimm_builtin (d->icode, arglist, target);
+      return frv_expand_binopimm_builtin (d->icode, exp, target);
 
   for (i = 0, d = bdesc_void2arg; i < ARRAY_SIZE (bdesc_void2arg); i++, d++)
     if (d->code == fcode)
-      return frv_expand_voidbinop_builtin (d->icode, arglist);
+      return frv_expand_voidbinop_builtin (d->icode, exp);
 
   for (i = 0, d = bdesc_void3arg; i < ARRAY_SIZE (bdesc_void3arg); i++, d++)
     if (d->code == fcode)
-      return frv_expand_voidtriop_builtin (d->icode, arglist);
+      return frv_expand_voidtriop_builtin (d->icode, exp);
 
   for (i = 0, d = bdesc_voidacc; i < ARRAY_SIZE (bdesc_voidacc); i++, d++)
     if (d->code == fcode)
-      return frv_expand_voidaccop_builtin (d->icode, arglist);
+      return frv_expand_voidaccop_builtin (d->icode, exp);
 
   for (i = 0, d = bdesc_int_void2arg;
        i < ARRAY_SIZE (bdesc_int_void2arg); i++, d++)
     if (d->code == fcode)
-      return frv_expand_int_void2arg (d->icode, arglist);
+      return frv_expand_int_void2arg (d->icode, exp);
 
   for (i = 0, d = bdesc_prefetches;
        i < ARRAY_SIZE (bdesc_prefetches); i++, d++)
     if (d->code == fcode)
-      return frv_expand_prefetches (d->icode, arglist);
+      return frv_expand_prefetches (d->icode, exp);
+
+  for (i = 0, d = bdesc_loads; i < ARRAY_SIZE (bdesc_loads); i++, d++)
+    if (d->code == fcode)
+      return frv_expand_load_builtin (d->icode, TYPE_MODE (TREE_TYPE (exp)),
+                                     exp, target);
+
+  for (i = 0, d = bdesc_stores; i < ARRAY_SIZE (bdesc_stores); i++, d++)
+    if (d->code == fcode)
+      return frv_expand_store_builtin (d->icode, exp);
 
   return 0;
 }
 
 static bool
-frv_in_small_data_p (tree decl)
+frv_in_small_data_p (const_tree decl)
 {
   HOST_WIDE_INT size;
-  tree section_name;
+  const_tree section_name;
 
   /* Don't apply the -G flag to internal compiler structures.  We
      should leave such structures in the main data section, partly
@@ -10318,8 +9526,7 @@ frv_in_small_data_p (tree decl)
   section_name = DECL_SECTION_NAME (decl);
   if (section_name)
     {
-      if (TREE_CODE (section_name) != STRING_CST)
-       abort ();
+      gcc_assert (TREE_CODE (section_name) == STRING_CST);
       if (frv_string_begins_with (section_name, ".sdata"))
        return true;
       if (frv_string_begins_with (section_name, ".sbss"))
@@ -10338,7 +9545,8 @@ static bool
 frv_rtx_costs (rtx x,
                int code ATTRIBUTE_UNUSED,
                int outer_code ATTRIBUTE_UNUSED,
-               int *total)
+               int *total,
+              bool speed ATTRIBUTE_UNUSED)
 {
   if (outer_code == MEM)
     {
@@ -10351,7 +9559,7 @@ frv_rtx_costs (rtx x,
   switch (code)
     {
     case CONST_INT:
-      /* Make 12 bit integers really cheap.  */
+      /* Make 12-bit integers really cheap.  */
       if (IN_RANGE_P (INTVAL (x), -2048, 2047))
        {
          *total = 0;
@@ -10411,12 +9619,13 @@ frv_rtx_costs (rtx x,
 static void
 frv_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
 {
-  ctors_section ();
+  switch_to_section (ctors_section);
   assemble_align (POINTER_SIZE);
   if (TARGET_FDPIC)
     {
-      if (!frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1))
-       abort ();
+      int ok = frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+
+      gcc_assert (ok);
       return;
     }
   assemble_integer_with_op ("\t.picptr\t", symbol);
@@ -10425,12 +9634,13 @@ frv_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
 static void
 frv_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
 {
-  dtors_section ();
+  switch_to_section (dtors_section);
   assemble_align (POINTER_SIZE);
   if (TARGET_FDPIC)
     {
-      if (!frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1))
-       abort ();
+      int ok = frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+
+      gcc_assert (ok);
       return;
     }
   assemble_integer_with_op ("\t.picptr\t", symbol);
@@ -10445,4 +9655,20 @@ frv_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
   return gen_rtx_REG (Pmode, FRV_STRUCT_VALUE_REGNUM);
 }
 
+#define TLS_BIAS (2048 - 16)
+
+/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
+   We need to emit DTP-relative relocations.  */
+
+static void
+frv_output_dwarf_dtprel (FILE *file, int size, rtx x)
+{
+  gcc_assert (size == 4);
+  fputs ("\t.picptr\ttlsmoff(", file);
+  /* We want the unbiased TLS offset, so add the bias to the
+     expression, such that the implicit biasing cancels out.  */
+  output_addr_const (file, plus_constant (x, TLS_BIAS));
+  fputs (")", file);
+}
+
 #include "gt-frv.h"