OSDN Git Service

2005-12-02 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / config / frv / frv.c
index e2e01fe..4df467a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004
+/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
    Free Software Foundation, Inc.
    Contributed by Red Hat, Inc.
 
@@ -16,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -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 machine_function GTY(())
+{
+  /* 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 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,7 +295,6 @@ 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 *);
@@ -302,6 +302,7 @@ static rtx frv_read_iacc_argument           (enum machine_mode, tree *);
 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);
@@ -375,6 +376,17 @@ static void frv_output_const_unspec                (FILE *,
 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 int frv_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+                                 tree, bool);
+static void frv_output_dwarf_dtprel            (FILE *, int, rtx)
+  ATTRIBUTE_UNUSED;
+\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 +395,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 +434,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 +453,16 @@ 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
 
+#if HAVE_AS_TLS
+#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
+#define TARGET_ASM_OUTPUT_DWARF_DTPREL frv_output_dwarf_dtprel
+#endif
+
 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 +489,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 +543,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 +603,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 +624,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 +640,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
@@ -635,7 +652,20 @@ frv_override_options (void)
       if (GPR_P (regno))
        {
          int gpr_reg = regno - GPR_FIRST;
-         if ((gpr_reg & 3) == 0)
+
+         if (gpr_reg == GR8_REG)
+           class = GR8_REGS;
+
+         else if (gpr_reg == GR9_REG)
+           class = GR9_REGS;
+
+         else if (gpr_reg == GR14_REG)
+           class = FDPIC_FPTR_REGS;
+
+         else if (gpr_reg == FDPIC_REGNO)
+           class = FDPIC_REGS;
+
+         else if ((gpr_reg & 3) == 0)
            class = QUAD_REGS;
 
          else if ((gpr_reg & 1) == 0)
@@ -751,6 +781,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 +807,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
@@ -1465,8 +1498,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 (!regs_ever_live[GPR_FIRST + 3]);
 
       /* Generate the instruction that saves the link register.  */
       fprintf (file, "\tmovsg lr,gr3\n");
@@ -1523,10 +1555,8 @@ 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;
        }
     }
 
@@ -1850,7 +1880,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
@@ -2113,7 +2143,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",
@@ -2173,8 +2203,8 @@ frv_expand_builtin_va_start (tree valist, rtx nextarg)
       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,
+             make_tree (ptr_type_node, nextarg));
   TREE_SIDE_EFFECTS (t) = 1;
 
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2227,9 +2257,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 +2326,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 +2349,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);
 
@@ -2510,7 +2538,7 @@ frv_print_operand_address (FILE * stream, rtx x)
       break;
     }
 
-  fatal_insn ("Bad insn to frv_print_operand_address:", x);
+  fatal_insn ("bad insn to frv_print_operand_address:", x);
 }
 
 \f
@@ -2521,7 +2549,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 +2588,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 +2598,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 +2607,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 +2628,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 +2655,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 +2710,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
@@ -2744,7 +2794,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 +2836,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 +2855,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 +2863,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 +2879,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 +2893,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 +2941,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 +2954,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 +2975,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 +2993,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 +3013,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 +3044,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;
 
@@ -3200,11 +3218,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 +3231,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 +3326,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:
@@ -3427,6 +3446,179 @@ 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,
+                       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
 /* Test whether a local function descriptor is canonical, i.e.,
    whether we can use FUNCDESC_GOTOFF to compute the address of the
@@ -3500,7 +3692,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 ();
     }
 }
 
@@ -3534,7 +3735,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)
@@ -3624,1707 +3825,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);
-    }
-
-  if (GET_CODE (op) != REG)
-    return FALSE;
-
-  regno = REGNO (op);
-  if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER)
-    return TRUE;
-
-  return FALSE;
-}
-
-/* Return 1 if operand is a GPR register or 12 bit signed immediate.  */
-
-int
-gpr_or_int12_operand (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;
-
-  if (GET_MODE (op) != mode && mode != VOIDmode)
-    return FALSE;
+      switch (format[j])
+       {
+       case 'e':
+         if (frv_function_symbol_referenced_p (XEXP (x, j)))
+           return TRUE;
+         break;
 
-  if (GET_CODE (op) == SUBREG)
-    {
-      if (GET_CODE (SUBREG_REG (op)) != REG)
-       return register_operand (op, mode);
+       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;
 
-      op = SUBREG_REG (op);
+       default:
+         /* Nothing to do.  */
+         break;
+       }
     }
 
-  if (GET_CODE (op) != REG)
-    return FALSE;
-
-  return GPR_OR_PSEUDO_P (REGNO (op));
+  return FALSE;
 }
 
-/* Return 1 if operand is a GPR register, or a FPR register, or a 12 bit
-   signed immediate.  */
+/* Return true if the memory operand is one that can be conditionally
+   executed.  */
 
 int
-gpr_fpr_or_int12_operand (rtx op, enum machine_mode mode)
+condexec_memory_operand (rtx op, enum machine_mode mode)
 {
-  int regno;
-
-  if (GET_CODE (op) == CONST_INT)
-    return IN_RANGE_P (INTVAL (op), -2048, 2047);
+  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;
-
-  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;
+    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.  */
-
-int
-quad_acc_operand (rtx op, enum machine_mode mode)
-{
-  return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 3) == 0;
-}
+      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.  */
@@ -5342,6 +3920,42 @@ direct_return_p (void)
 }
 
 \f
+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:
+      if (frv_emit_movsi (dest, src))
+       return;
+      break;
+
+    case QImode:
+    case HImode:
+    case DImode:
+    case SFmode:
+    case DFmode:
+      if (!reload_in_progress
+         && !reload_completed
+         && !register_operand (dest, mode)
+         && !reg_or_0_operand (src, mode))
+       src = copy_to_mode_reg (mode, src);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  emit_insn (gen_rtx_SET (VOIDmode, dest, src));
+}
+
 /* Emit code to handle a MOVSI, adding in the small data register or pic
    register if needed to load up addresses.  Return TRUE if the appropriate
    instructions are emitted.  */
@@ -5449,6 +4063,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))
@@ -5542,8 +4165,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)
        {
@@ -5796,7 +4418,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 "";
 }
 
@@ -5923,7 +4545,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 "";
 }
 
@@ -6065,7 +4687,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 "";
 }
 
@@ -6341,7 +4963,7 @@ frv_split_cond_move (rtx operands[])
        }
 
       else
-       abort ();
+       gcc_unreachable ();
     }
   else
     {
@@ -6443,7 +5065,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;
@@ -6469,8 +5091,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,
@@ -6643,12 +5264,13 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
   enum reg_class cr_class;
   int cc_first;
   int cc_last;
+  reg_set_iterator rsi;
 
   /* 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
@@ -6671,13 +5293,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 (then_bb->il.rtl->global_live_at_start, j))
              continue;
 
-           if (else_bb && REGNO_REG_SET_P (else_bb->global_live_at_start, j))
+           if (else_bb
+               && REGNO_REG_SET_P (else_bb->il.rtl->global_live_at_start, j))
              continue;
 
-           if (join_bb && REGNO_REG_SET_P (join_bb->global_live_at_start, j))
+           if (join_bb
+               && REGNO_REG_SET_P (join_bb->il.rtl->global_live_at_start, j))
              continue;
 
            SET_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite, j);
@@ -6695,15 +5319,15 @@ 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,
-                                {
-                                  if (regno < FIRST_PSEUDO_REGISTER)
-                                    CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
-                                });
+      EXECUTE_IF_SET_IN_REG_SET (join_bb->il.rtl->global_live_at_start, 0, regno, rsi)
+       {
+         if (regno < FIRST_PSEUDO_REGISTER)
+           CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
+       }
     }
 
   /* Add in all of the blocks in multiple &&/|| blocks to be scanned.  */
@@ -6715,7 +5339,7 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
       while (multiple_test_bb != test_bb)
        {
          bb[num_bb++] = multiple_test_bb;
-         multiple_test_bb = multiple_test_bb->pred->src;
+         multiple_test_bb = EDGE_PRED (multiple_test_bb, 0)->src;
        }
     }
 
@@ -6732,7 +5356,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",
@@ -6743,11 +5367,11 @@ 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,
-                                {
-                                  if (regno < FIRST_PSEUDO_REGISTER)
-                                    CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
-                                });
+      EXECUTE_IF_SET_IN_REG_SET (bb[j]->il.rtl->global_live_at_start, 0, regno, rsi)
+       {
+         if (regno < FIRST_PSEUDO_REGISTER)
+           CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
+       }
 
       /* Loop through the insns in the block.  */
       for (;;)
@@ -6858,7 +5482,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;
@@ -7007,13 +5631,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;
@@ -7277,8 +5901,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)
@@ -7381,14 +6004,32 @@ 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
+                    (ce_info->join_bb->il.rtl->global_live_at_start,
+                     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,
+                        (ce_info->else_bb->il.rtl->global_live_at_start,
                          REGNO (SET_DEST (set))))))
        pattern = set;
 
@@ -7526,8 +6167,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
     {
@@ -7558,7 +6198,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;
     }
@@ -7784,6 +6424,11 @@ frv_class_likely_spilled_p (enum reg_class class)
     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:
@@ -7870,8 +6515,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
@@ -7955,6 +6599,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:
@@ -8109,6 +6754,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
@@ -8360,8 +7035,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;
     }
@@ -8429,15 +7103,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));
 }
 
 
@@ -8720,7 +7393,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;
 
@@ -8866,6 +7539,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;
 
@@ -8918,7 +7595,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
@@ -8950,14 +7627,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.  */
@@ -9013,6 +7689,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, rtx pat ATTRIBUTE_UNUSED, void *data)
+{
+  rtx *other = 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, rtx pat ATTRIBUTE_UNUSED, void *data)
+{
+  HARD_REG_SET *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 = 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 = xcalloc (last_basic_block, sizeof (struct frv_io));
+  last_membar = xcalloc (last_basic_block, sizeof (rtx));
+
+  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;
 
@@ -9125,6 +8129,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)
@@ -9190,7 +8197,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 },
@@ -9306,6 +8312,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
@@ -9321,6 +8356,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) \
@@ -9335,6 +8372,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);
@@ -9368,6 +8411,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);
@@ -9380,6 +8424,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);
@@ -9430,7 +8480,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);
@@ -9485,10 +8535,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
@@ -9551,7 +8611,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 instrinsics
+  /* 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++)
@@ -9576,7 +8636,7 @@ frv_int_to_acc (enum insn_code icode, int opnum, rtx opval)
 
   if (! (*insn_data[icode].operand[opnum].predicate) (reg, VOIDmode))
     {
-      error ("inappropriate accumulator for `%s'", insn_data[icode].name);
+      error ("inappropriate accumulator for %qs", insn_data[icode].name);
       return NULL_RTX;
     }
   return reg;
@@ -9600,10 +8660,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.  */
@@ -9646,7 +8718,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;
@@ -9665,12 +8737,12 @@ frv_check_constant_argument (enum insn_code icode, int opnum, rtx opval)
 {
   if (GET_CODE (opval) != CONST_INT)
     {
-      error ("`%s' expects a constant argument", insn_data[icode].name);
+      error ("%qs expects a constant argument", insn_data[icode].name);
       return FALSE;
     }
   if (! (*insn_data[icode].operand[opnum].predicate) (opval, VOIDmode))
     {
-      error ("constant argument out of range for `%s'", insn_data[icode].name);
+      error ("constant argument out of range for %qs", insn_data[icode].name);
       return FALSE;
     }
   return TRUE;
@@ -9709,6 +8781,18 @@ 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.  */
 
@@ -9957,6 +9041,79 @@ 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 arglist, rtx target)
+{
+  rtx op0 = frv_read_argument (&arglist);
+  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 arglist)
+{
+  rtx op0 = frv_read_argument (&arglist);
+  rtx op1 = frv_read_argument (&arglist);
+  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.
+   ARGLIST is a TREE_LIST of the arguments and TARGET, if nonnull,
+   suggests a good place to put the return value.  */
+
+static rtx
+frv_expand_mdpackh_builtin (tree arglist, rtx target)
+{
+  enum insn_code icode = CODE_FOR_mdpackh;
+  rtx pat, op0, op1;
+  rtx arg1 = frv_read_argument (&arglist);
+  rtx arg2 = frv_read_argument (&arglist);
+  rtx arg3 = frv_read_argument (&arglist);
+  rtx arg4 = frv_read_argument (&arglist);
+
+  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_insn (gen_rtx_CLOBBER (DImode, op0));
+  emit_insn (gen_rtx_CLOBBER (DImode, 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.  */
 
@@ -10184,6 +9341,9 @@ frv_expand_builtin (tree exp,
     case FRV_BUILTIN_MWTACCG:
       return frv_expand_mwtacc_builtin (CODE_FOR_mwtaccg, arglist);
 
+    case FRV_BUILTIN_MDPACKH:
+      return frv_expand_mdpackh_builtin (arglist, target);
+
     case FRV_BUILTIN_IACCreadll:
       {
        rtx src = frv_read_iacc_argument (DImode, &arglist);
@@ -10260,6 +9420,15 @@ frv_expand_builtin (tree exp,
     if (d->code == fcode)
       return frv_expand_prefetches (d->icode, arglist);
 
+  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)),
+                                     arglist, 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, arglist);
+
   return 0;
 }
 
@@ -10281,8 +9450,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"))
@@ -10378,8 +9546,9 @@ frv_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
   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);
@@ -10392,8 +9561,9 @@ frv_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
   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);
@@ -10408,4 +9578,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"