re PR target/14619 (Incorrect Dwarf 2 information in function prologue)
[gcc.git] / gcc / config / cris / cris.c
index 3be8870abd4ab8c6fa44ade96e60200ec5c3621f..3599e2dae05e2e425b45908e616541ecdd445675 100644 (file)
@@ -1,5 +1,6 @@
 /* Definitions for GCC.  Part of the machine description for CRIS.
-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
    Contributed by Axis Communications.  Written by Hans-Peter Nilsson.
 
 This file is part of GCC.
@@ -21,13 +22,14 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
 #include "tree.h"
@@ -38,8 +40,11 @@ Boston, MA 02111-1307, USA.  */
 #include "recog.h"
 #include "tm_p.h"
 #include "debug.h"
+#include "output.h"
 #include "target.h"
 #include "target-def.h"
+#include "ggc.h"
+#include "optabs.h"
 
 /* Usable when we have an amount to add or subtract, and want the
    optimal size of the insn.  */
@@ -55,15 +60,19 @@ Boston, MA 02111-1307, USA.  */
        abort ();                                               \
     } while (0)
 
+#define LOSE_AND_RETURN(msgid, x)                      \
+  do                                           \
+    {                                          \
+      cris_operand_lossage (msgid, x);         \
+      return;                                  \
+    } while (0)
+
 /* Per-function machine data.  */
-struct machine_function
+struct machine_function GTY(())
  {
    int needs_return_address_on_stack;
  };
 
-/* Fix for reg_overlap_mentioned_p.  */
-static int cris_reg_overlap_mentioned_p PARAMS ((rtx, rtx));
-
 /* This little fix suppresses the 'u' or 's' when '%e' in assembly
    pattern.  */
 static char cris_output_insn_is_bound = 0;
@@ -74,28 +83,52 @@ static char cris_output_insn_is_bound = 0;
    just the "sym:GOTOFF" part.  */
 static int cris_pic_sympart_only = 0;
 
-static void
-cris_print_base PARAMS ((rtx, FILE *));
+/* In code for output macros, this is how we know whether e.g. constant
+   goes in code or in a static initializer.  */
+static int in_code = 0;
 
-static void
-cris_print_index PARAMS ((rtx, FILE *));
+/* Fix for reg_overlap_mentioned_p.  */
+static int cris_reg_overlap_mentioned_p (rtx, rtx);
 
-static void
-cris_init_machine_status PARAMS ((struct function *));
+static void cris_print_base (rtx, FILE *);
 
-static int
-cris_initial_frame_pointer_offset PARAMS ((void));
+static void cris_print_index (rtx, FILE *);
 
-static int
-saved_regs_mentioned PARAMS ((rtx));
+static void cris_output_addr_const (FILE *, rtx);
+
+static struct machine_function * cris_init_machine_status (void);
+
+static rtx cris_struct_value_rtx (tree, int);
+
+static void cris_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
+                                        tree type, int *, int);
 
-static void cris_target_asm_function_prologue
-  PARAMS ((FILE *, HOST_WIDE_INT));
-static void cris_target_asm_function_epilogue
-  PARAMS ((FILE *, HOST_WIDE_INT));
+static int cris_initial_frame_pointer_offset (void);
+
+static int saved_regs_mentioned (rtx);
+
+static void cris_target_asm_function_prologue (FILE *, HOST_WIDE_INT);
+
+static void cris_target_asm_function_epilogue (FILE *, HOST_WIDE_INT);
+
+static void cris_operand_lossage (const char *, rtx);
+
+static void cris_asm_output_mi_thunk
+  (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
+
+static void cris_file_start (void);
+static void cris_init_libfuncs (void);
+
+static bool cris_rtx_costs (rtx, int, int, int *);
+static int cris_address_cost (rtx);
+static bool cris_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+                                   tree, bool);
+static int cris_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+                                  tree, bool);
 
 /* The function cris_target_asm_function_epilogue puts the last insn to
-   output here.  Used in delay_slots_for_epilogue and function_epilogue.  */
+   output here.  It always fits; there won't be a symbol operand.  Used in
+   delay_slots_for_epilogue and function_epilogue.  */
 static char save_last[80];
 
 /* This is the argument from the "-max-stack-stackframe=" option.  */
@@ -117,12 +150,58 @@ int cris_max_stackframe = 0;
 /* This is the parsed result of the "-march=" option, if given.  */
 int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION;
 
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.dword\t"
+#undef TARGET_ASM_ALIGNED_DI_OP
+#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
+
+/* We need to define these, since the 2byte, 4byte, 8byte op:s are only
+   available in ELF.  These "normal" pseudos do not have any alignment
+   constraints or side-effects.  */
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP
+
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP TARGET_ASM_ALIGNED_SI_OP
+
+#undef TARGET_ASM_UNALIGNED_DI_OP
+#define TARGET_ASM_UNALIGNED_DI_OP TARGET_ASM_ALIGNED_DI_OP
+
 #undef TARGET_ASM_FUNCTION_PROLOGUE
 #define TARGET_ASM_FUNCTION_PROLOGUE cris_target_asm_function_prologue
 
 #undef TARGET_ASM_FUNCTION_EPILOGUE
 #define TARGET_ASM_FUNCTION_EPILOGUE cris_target_asm_function_epilogue
 
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK cris_asm_output_mi_thunk
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
+
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START cris_file_start
+
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS cris_init_libfuncs
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS cris_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST cris_address_cost
+
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX cris_struct_value_rtx
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS cris_setup_incoming_varargs
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE cris_pass_by_reference
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES cris_arg_partial_bytes
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Predicate functions.  */
@@ -135,9 +214,7 @@ struct gcc_target targetm = TARGET_INITIALIZER;
    c) a [r] or [r+] in SImode, or sign-extend from HI or QI.  */
 
 int
-cris_bdap_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+cris_bdap_operand (rtx op, enum machine_mode mode)
 {
   register enum rtx_code code = GET_CODE (op);
 
@@ -194,9 +271,7 @@ cris_bdap_operand (op, mode)
    d) a [r] or [r+] in SImode, or sign-extend from HI or QI.  */
 
 int
-cris_bdap_biap_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+cris_bdap_biap_operand (rtx op, enum machine_mode mode)
 {
   register enum rtx_code code = GET_CODE (op);
   rtx reg;
@@ -241,9 +316,7 @@ cris_bdap_biap_operand (op, mode)
    AND or UMIN.  */
 
 int
-cris_orthogonal_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+cris_orthogonal_operator (rtx x, enum machine_mode mode)
 {
   enum rtx_code code = GET_CODE (x);
 
@@ -259,9 +332,7 @@ cris_orthogonal_operator (x, mode)
    UMIN.  */
 
 int
-cris_commutative_orth_op (x, mode)
-     rtx x;
-     enum machine_mode mode;
+cris_commutative_orth_op (rtx x, enum machine_mode mode)
 {
   enum rtx_code code = GET_CODE (x);
 
@@ -273,12 +344,13 @@ cris_commutative_orth_op (x, mode)
           || code == IOR || code == AND || code == UMIN));
 }
 
-/* Check if MODE is same as mode for X, and X is PLUS or MINUS or UMIN.  */
+/* Check if MODE is same as mode for X, and X is PLUS or MINUS or UMIN.
+   By the name, you might think we should include MULT.  We don't because
+   it doesn't accept the same addressing modes as the others (ony
+   registers) and there's also the problem of handling TARGET_MUL_BUG.  */
 
 int
-cris_operand_extend_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+cris_operand_extend_operator (rtx x, enum machine_mode mode)
 {
   enum rtx_code code = GET_CODE (x);
 
@@ -289,13 +361,25 @@ cris_operand_extend_operator (x, mode)
          && (code == PLUS || code == MINUS || code == UMIN));
 }
 
+/* Check if MODE is same as mode for X, and X is PLUS or MINUS.  */
+
+int
+cris_additive_operand_extend_operator (rtx x, enum machine_mode mode)
+{
+  enum rtx_code code = GET_CODE (x);
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (x);
+
+  return (GET_MODE (x) == mode
+         && (code == PLUS || code == MINUS));
+}
+
 /* Check to see if MODE is same as mode for X, and X is SIGN_EXTEND or
    ZERO_EXTEND.  */
 
 int
-cris_extend_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+cris_extend_operator (rtx x, enum machine_mode mode)
 {
   enum rtx_code code = GET_CODE (x);
 
@@ -309,9 +393,7 @@ cris_extend_operator (x, mode)
 /* Check to see if MODE is same as mode for X, and X is PLUS or BOUND.  */
 
 int
-cris_plus_or_bound_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+cris_plus_or_bound_operator (rtx x, enum machine_mode mode)
 {
   enum rtx_code code = GET_CODE (x);
 
@@ -322,14 +404,25 @@ cris_plus_or_bound_operator (x, mode)
     (GET_MODE (x) == mode && (code == UMIN || code == PLUS));
 }
 
+/* Used as an operator to get a handle on a already-known-valid MEM rtx:es
+   (no need to validate the address), where some address expression parts
+   have their own match_operand.  */
+
+int
+cris_mem_op (rtx x, enum machine_mode mode)
+{
+  if (mode == VOIDmode)
+    mode = GET_MODE (x);
+
+  return GET_MODE (x) == mode && GET_CODE (x) == MEM;
+}
+
 /* Since with -fPIC, not all symbols are valid PIC symbols or indeed
    general_operands, we have to have a predicate that matches it for the
    "movsi" expander.  */
 
 int
-cris_general_operand_or_symbol (op, mode)
-     rtx op;
-     enum machine_mode mode;
+cris_general_operand_or_symbol (rtx op, enum machine_mode mode)
 {
   return general_operand (op, mode)
     || (CONSTANT_P (op) && cris_symbol (op));
@@ -340,9 +433,7 @@ cris_general_operand_or_symbol (op, mode)
    "movsi" anonymous pattern for PIC symbols.  */
 
 int
-cris_general_operand_or_gotless_symbol (op, mode)
-     rtx op;
-     enum machine_mode mode;
+cris_general_operand_or_gotless_symbol (rtx op, enum machine_mode mode)
 {
   return general_operand (op, mode)
     || (CONSTANT_P (op) && cris_gotless_symbol (op));
@@ -353,9 +444,7 @@ cris_general_operand_or_gotless_symbol (op, mode)
    "call" and "call_value" anonymous patterns.  */
 
 int
-cris_general_operand_or_plt_symbol (op, mode)
-     rtx op;
-     enum machine_mode mode;
+cris_general_operand_or_plt_symbol (rtx op, enum machine_mode mode)
 {
   return general_operand (op, mode)
     || (GET_CODE (op) == CONST
@@ -370,9 +459,7 @@ cris_general_operand_or_plt_symbol (op, mode)
    UNSPEC 0).  */
 
 int
-cris_mem_call_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+cris_mem_call_operand (rtx op, enum machine_mode mode)
 {
   rtx xmem;
 
@@ -387,10 +474,10 @@ cris_mem_call_operand (op, mode)
   return cris_general_operand_or_symbol (xmem, GET_MODE (op));
 }
 
-/* The CONDITIONAL_REGISTER_USAGE worker.   */
+/* The CONDITIONAL_REGISTER_USAGE worker.  */
 
 void
-cris_conditional_register_usage ()
+cris_conditional_register_usage (void)
 {
   /* FIXME: This isn't nice.  We should be able to use that register for
      something else if the PIC table isn't needed.  */
@@ -403,7 +490,7 @@ cris_conditional_register_usage ()
    since some generated files do not include function.h.  */
 
 int
-cris_cfun_uses_pic_table ()
+cris_cfun_uses_pic_table (void)
 {
   return current_function_uses_pic_offset_table;
 }
@@ -413,8 +500,7 @@ cris_cfun_uses_pic_table ()
    define_insn.  */
 
 const char *
-cris_op_str (x)
-     rtx x;
+cris_op_str (rtx x)
 {
   cris_output_insn_is_bound = 0;
   switch (GET_CODE (x))
@@ -428,7 +514,11 @@ cris_op_str (x)
       break;
 
     case MULT:
-      return "mul";
+      /* This function is for retrieving a part of an instruction name for
+        an operator, for immediate output.  If that ever happens for
+        MULT, we need to apply TARGET_MUL_BUG in the caller.  Make sure
+        we notice.  */
+      abort ();
       break;
 
     case DIV:
@@ -476,12 +566,22 @@ cris_op_str (x)
   }
 }
 
+/* Emit an error message when we're in an asm, and a fatal error for
+   "normal" insns.  Formatted output isn't easily implemented, since we
+   use output_operand_lossage to output the actual message and handle the
+   categorization of the error.  */
+
+static void
+cris_operand_lossage (const char *msgid, rtx op)
+{
+  debug_rtx (op);
+  output_operand_lossage ("%s", msgid);
+}
+
 /* Print an index part of an address to file.  */
 
 static void
-cris_print_index (index, file)
-     rtx index;
-     FILE * file;
+cris_print_index (rtx index, FILE *file)
 {
   rtx inner = XEXP (index, 0);
 
@@ -527,29 +627,28 @@ cris_print_index (index, file)
        fprintf (file, "[$%s].d", reg_names[REGNO (inner)]);
     }
   else
-    fatal_insn ("Unexpected index-type in cris_print_index", index);
+    cris_operand_lossage ("unexpected index-type in cris_print_index",
+                         index);
 }
 
 /* Print a base rtx of an address to file.  */
 
 static void
-cris_print_base (base, file)
-     rtx base;
-     FILE *file;
+cris_print_base (rtx base, FILE *file)
 {
   if (REG_P (base))
     fprintf (file, "$%s", reg_names[REGNO (base)]);
   else if (GET_CODE (base) == POST_INC)
     fprintf (file, "$%s+", reg_names[REGNO (XEXP (base, 0))]);
   else
-    fatal_insn ("Unexpected base-type in cris_print_base", base);
+    cris_operand_lossage ("unexpected base-type in cris_print_base",
+                         base);
 }
 
 /* Usable as a guard in expressions.  */
 
 int
-cris_fatal (arg)
-     char *arg;
+cris_fatal (char *arg)
 {
   internal_error (arg);
 
@@ -557,12 +656,14 @@ cris_fatal (arg)
   return 0;
 }
 
+/* This variable belongs to cris_target_asm_function_prologue but must
+   be located outside it for GTY reasons.  */
+static GTY(()) unsigned long cfa_label_num = 0;
+
 /* Textual function prologue.  */
 
 static void
-cris_target_asm_function_prologue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
+cris_target_asm_function_prologue (FILE *file, HOST_WIDE_INT size)
 {
   int regno;
 
@@ -573,7 +674,7 @@ cris_target_asm_function_prologue (file, size)
   int framesize;
   int faked_args_size = 0;
   int cfa_write_offset = 0;
-  char *cfa_label = NULL;
+  static char cfa_label[30];
   int return_address_on_stack
     = regs_ever_live[CRIS_SRP_REGNUM]
     || cfun->machine->needs_return_address_on_stack != 0;
@@ -626,7 +727,8 @@ cris_target_asm_function_prologue (file, size)
          cfa_offset += cris_initial_frame_pointer_offset ();
        }
 
-      cfa_label = dwarf2out_cfi_label ();
+      ASM_GENERATE_INTERNAL_LABEL (cfa_label, "LCFIT",
+                                  cfa_label_num++);
       dwarf2out_def_cfa (cfa_label, cfa_reg, cfa_offset);
 
       cfa_write_offset = - faked_args_size - 4;
@@ -665,12 +767,12 @@ cris_target_asm_function_prologue (file, size)
   cfa_write_offset -= size;
 
   /* Get a contiguous sequence of registers, starting with r0, that need
-     to be saved. */
+     to be saved.  */
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
     {
       if ((((regs_ever_live[regno]
             && !call_used_regs[regno])
-           || (regno == PIC_OFFSET_TABLE_REGNUM
+           || (regno == (int) PIC_OFFSET_TABLE_REGNUM
                && (current_function_uses_pic_offset_table
                    /* It is saved anyway, if there would be a gap.  */
                    || (flag_pic
@@ -702,13 +804,13 @@ cris_target_asm_function_prologue (file, size)
                      && (last_movem_reg + 1) * 4 + size <= 128
                      && cris_cpu_version >= CRIS_CPU_SVINTO
                      && TARGET_SIDE_EFFECT_PREFIXES)
-                   fprintf (file, "\tmovem $%s,[$sp=$sp-%d]\n",
+                   fprintf (file, "\tmovem $%s,[$sp=$sp-"HOST_WIDE_INT_PRINT_DEC"]\n",
                             reg_names[last_movem_reg],
                             (last_movem_reg + 1) * 4 + size);
                  else
                    {
                      /* Avoid printing multiple subsequent sub:s for sp.  */
-                     fprintf (file, "\tsub%s %d,$sp\n",
+                     fprintf (file, "\tsub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
                               ADDITIVE_SIZE_MODIFIER ((last_movem_reg + 1)
                                                       * 4 + size),
                               (last_movem_reg + 1) * 4 + size);
@@ -720,7 +822,8 @@ cris_target_asm_function_prologue (file, size)
                  framesize += (last_movem_reg + 1) * 4 + size;
 
                  if (TARGET_PDEBUG)
-                   fprintf (file, "; frame %d, #regs %d, bytes %d args %d\n",
+                   fprintf (file, "; frame "HOST_WIDE_INT_PRINT_DEC
+                            ", #regs %d, bytes %d args %d\n",
                             size,
                             last_movem_reg + 1,
                             (last_movem_reg + 1) * 4,
@@ -733,7 +836,7 @@ cris_target_asm_function_prologue (file, size)
                {
                  /* Local vars on stack, but there are no movem:s.
                     Just allocate space.  */
-                 fprintf (file, "\tSub%s %d,$sp\n",
+                 fprintf (file, "\tSub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
                           ADDITIVE_SIZE_MODIFIER (size),
                           size);
                  framesize += size;
@@ -768,14 +871,14 @@ cris_target_asm_function_prologue (file, size)
          && (last_movem_reg + 1) * 4 + size <= 128
          && cris_cpu_version >= CRIS_CPU_SVINTO
          && TARGET_SIDE_EFFECT_PREFIXES)
-       fprintf (file, "\tmovem $%s,[$sp=$sp-%d]\n",
+       fprintf (file, "\tmovem $%s,[$sp=$sp-"HOST_WIDE_INT_PRINT_DEC"]\n",
                 reg_names[last_movem_reg],
                 (last_movem_reg+1) * 4 + size);
       else
        {
          /* Avoid printing multiple subsequent sub:s for sp.  FIXME:
-            Clean up the conditional expression. */
-         fprintf (file, "\tsub%s %d,$sp\n",
+            Clean up the conditional expression.  */
+         fprintf (file, "\tsub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
                   ADDITIVE_SIZE_MODIFIER ((last_movem_reg + 1) * 4 + size),
                   (last_movem_reg + 1) * 4 + size);
          /* To be compatible with v0..v3 means we do not use an assignment
@@ -788,7 +891,8 @@ cris_target_asm_function_prologue (file, size)
       framesize += (last_movem_reg + 1) * 4 + size;
 
       if (TARGET_PDEBUG)
-       fprintf (file, "; frame %d, #regs %d, bytes %d args %d\n",
+       fprintf (file, "; frame "HOST_WIDE_INT_PRINT_DEC
+                ", #regs %d, bytes %d args %d\n",
                 size,
                 last_movem_reg + 1,
                 (last_movem_reg + 1) * 4,
@@ -810,7 +914,7 @@ cris_target_asm_function_prologue (file, size)
       /* This does not need to be accounted for, for unwind.  */
 
       /* Local vars on stack, and we could not use movem.  Add a sub here.  */
-      fprintf (file, "\tSub%s %d,$sp\n",
+      fprintf (file, "\tSub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
               ADDITIVE_SIZE_MODIFIER (size + cfoa_size),
               cfoa_size + size);
       framesize += size + cfoa_size;
@@ -818,13 +922,17 @@ cris_target_asm_function_prologue (file, size)
 
   /* Set up the PIC register.  */
   if (current_function_uses_pic_offset_table)
-    asm_fprintf (file, "\tmove.d $pc,$%s\n\tsub.d .:GOTOFF,$%s\n",
-                reg_names[PIC_OFFSET_TABLE_REGNUM],
-                reg_names[PIC_OFFSET_TABLE_REGNUM]);
+    fprintf (file, "\tmove.d $pc,$%s\n\tsub.d .:GOTOFF,$%s\n",
+            reg_names[PIC_OFFSET_TABLE_REGNUM],
+            reg_names[PIC_OFFSET_TABLE_REGNUM]);
+
+  if (doing_dwarf)
+    ASM_OUTPUT_LABEL (file, cfa_label);
 
   if (TARGET_PDEBUG)
     fprintf (file,
-            "; parm #%d @ %d; frame %d, FP-SP is %d; leaf: %s%s; fp %s, outg: %d arg %d\n",
+            "; parm #%d @ %d; frame " HOST_WIDE_INT_PRINT_DEC
+            ", FP-SP is %d; leaf: %s%s; fp %s, outg: %d arg %d\n",
             CRIS_MAX_ARGS_IN_REGS + 1, FIRST_PARM_OFFSET (0),
             get_frame_size (),
             cris_initial_frame_pointer_offset (),
@@ -834,7 +942,7 @@ cris_target_asm_function_prologue (file, size)
             cfoa_size, current_function_args_size);
 
   if (cris_max_stackframe && framesize > cris_max_stackframe)
-    warning ("Stackframe too big: %d bytes", framesize);
+    warning ("stackframe too big: %d bytes", framesize);
 }
 
 /* Return nonzero if there are regs mentioned in the insn that are not all
@@ -842,14 +950,13 @@ cris_target_asm_function_prologue (file, size)
    can be put in the epilogue.  */
 
 static int
-saved_regs_mentioned (x)
-     rtx x;
+saved_regs_mentioned (rtx x)
 {
   int i;
   const char *fmt;
   RTX_CODE code;
 
-  /* Mainly stolen from refers_to_regno_p in rtlanal.c. */
+  /* Mainly stolen from refers_to_regno_p in rtlanal.c.  */
 
   code = GET_CODE (x);
 
@@ -892,8 +999,7 @@ saved_regs_mentioned (x)
 /* Figure out if the insn may be put in the epilogue.  */
 
 int
-cris_eligible_for_epilogue_delay (insn)
-     rtx insn;
+cris_eligible_for_epilogue_delay (rtx insn)
 {
   /* First of all, it must be as slottable as for a delayed branch insn.  */
   if (get_attr_slottable (insn) != SLOTTABLE_YES)
@@ -924,7 +1030,7 @@ cris_eligible_for_epilogue_delay (insn)
    contains "ret", else 0.  */
 
 int
-cris_delay_slots_for_epilogue ()
+cris_delay_slots_for_epilogue (void)
 {
   /* Check if we use a return insn, which we only do for leaf functions.
      Else there is no slot to fill.  */
@@ -952,9 +1058,7 @@ cris_delay_slots_for_epilogue ()
    itself by storing the delay insn in save_last.  */
 
 static void
-cris_target_asm_function_epilogue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
+cris_target_asm_function_epilogue (FILE *file, HOST_WIDE_INT size)
 {
   int regno;
   int last_movem_reg = -1;
@@ -1002,7 +1106,7 @@ cris_target_asm_function_epilogue (file, size)
        regno++)
     if ((((regs_ever_live[regno]
           && !call_used_regs[regno])
-         || (regno == PIC_OFFSET_TABLE_REGNUM
+         || (regno == (int) PIC_OFFSET_TABLE_REGNUM
              && (current_function_uses_pic_offset_table
                  /* It is saved anyway, if there would be a gap.  */
                  || (flag_pic
@@ -1028,7 +1132,7 @@ cris_target_asm_function_epilogue (file, size)
        regno--)
     if ((((regs_ever_live[regno]
           && !call_used_regs[regno])
-         || (regno == PIC_OFFSET_TABLE_REGNUM
+         || (regno == (int) PIC_OFFSET_TABLE_REGNUM
              && (current_function_uses_pic_offset_table
                  /* It is saved anyway, if there would be a gap.  */
                  || (flag_pic
@@ -1072,7 +1176,7 @@ cris_target_asm_function_epilogue (file, size)
              fprintf (file, save_last);
              *save_last = 0;
            }
-       
+
          if (file)
            fprintf (file, "\tAdd%s %d,$sp\n",
                     ADDITIVE_SIZE_MODIFIER (argspace_offset),
@@ -1111,7 +1215,7 @@ cris_target_asm_function_epilogue (file, size)
          if (*save_last && file)
            fprintf (file, save_last);
 
-         sprintf (save_last, "\tadd%s %d,$sp\n",
+         sprintf (save_last, "\tadd%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
                   ADDITIVE_SIZE_MODIFIER (size), size);
        }
 
@@ -1149,7 +1253,7 @@ cris_target_asm_function_epilogue (file, size)
 
          /* Do a sanity check to avoid generating invalid code.  */
          if (current_function_epilogue_delay_list)
-           internal_error ("Allocated but unused delay list in epilogue");
+           internal_error ("allocated but unused delay list in epilogue");
        }
       return;
     }
@@ -1159,14 +1263,14 @@ cris_target_asm_function_epilogue (file, size)
      thoroughly), assert the assumption that all usage of
      __builtin_eh_return are handled above.  */
   if (current_function_calls_eh_return)
-    internal_error ("Unexpected function type needing stack adjustment for\
+    internal_error ("unexpected function type needing stack adjustment for\
  __builtin_eh_return");
 
   /* If we pushed some register parameters, then adjust the stack for
      them.  */
   if (pretend)
     {
-      /* Since srp is stored on the way, we need to restore it first. */
+      /* Since srp is stored on the way, we need to restore it first.  */
       if (return_address_on_stack)
        {
          if (*save_last && file)
@@ -1184,7 +1288,7 @@ cris_target_asm_function_epilogue (file, size)
               ADDITIVE_SIZE_MODIFIER (pretend), pretend);
     }
 
-  /* Here's where we have a delay-slot we need to fill. */
+  /* Here's where we have a delay-slot we need to fill.  */
   if (file && current_function_epilogue_delay_list)
     {
       /* If gcc has allocated an insn for the epilogue delay slot, but
@@ -1197,7 +1301,7 @@ cris_target_asm_function_epilogue (file, size)
 
       /* Output the delay-slot-insn the mandated way.  */
       final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
-                      file, 1, -2, 1);
+                      file, 1, -2, 1, NULL);
     }
   else if (file)
     {
@@ -1215,15 +1319,12 @@ cris_target_asm_function_epilogue (file, size)
 /* The PRINT_OPERAND worker.  */
 
 void
-cris_print_operand (file, x, code)
-     FILE *file;
-     rtx x;
-     int code;
+cris_print_operand (FILE *file, rtx x, int code)
 {
   rtx operand = x;
 
   /* Size-strings corresponding to MULT expressions.  */
-  static const char *mults[] = { "BAD:0", ".b", ".w", "BAD:3", ".d" };
+  static const char *const mults[] = { "BAD:0", ".b", ".w", "BAD:3", ".d" };
 
   /* New code entries should just be added to the switch below.  If
      handling is finished, just return.  If handling was just a
@@ -1234,12 +1335,13 @@ cris_print_operand (file, x, code)
   switch (code)
     {
     case 'b':
-      /* Print the unsigned supplied integer as if it was signed
+      /* Print the unsigned supplied integer as if it were signed
         and < 0, i.e print 255 or 65535 as -1, 254, 65534 as -2, etc.  */
       if (GET_CODE (x) != CONST_INT
          || ! CONST_OK_FOR_LETTER_P (INTVAL (x), 'O'))
-       fatal_insn ("Internal: Invalid operand with 'b'", x);
-      fprintf (file, "%d", INTVAL (x)| (INTVAL (x) <= 255 ? ~255 : ~65535));
+       LOSE_AND_RETURN ("invalid operand for 'b' modifier", x);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+              INTVAL (x)| (INTVAL (x) <= 255 ? ~255 : ~65535));
       return;
 
     case 'x':
@@ -1249,8 +1351,8 @@ cris_print_operand (file, x, code)
 
     case 'v':
       /* Print the operand without the PIC register.  */
-      if (! flag_pic || ! cris_gotless_symbol (x))
-       fatal_insn ("Internal: Invalid operand with 'v'", x);
+      if (! flag_pic || ! CONSTANT_P (x) || ! cris_gotless_symbol (x))
+       LOSE_AND_RETURN ("invalid operand for 'v' modifier", x);
       cris_pic_sympart_only++;
       cris_output_addr_const (file, x);
       cris_pic_sympart_only--;
@@ -1259,15 +1361,15 @@ cris_print_operand (file, x, code)
     case 'P':
       /* Print the PIC register.  Applied to a GOT-less PIC symbol for
          sanity.  */
-      if (! flag_pic || ! cris_gotless_symbol (x))
-       fatal_insn ("Internal: Invalid operand with 'P'", x);
+      if (! flag_pic || ! CONSTANT_P (x) || ! cris_gotless_symbol (x))
+       LOSE_AND_RETURN ("invalid operand for 'P' modifier", x);
       fprintf (file, "$%s", reg_names [PIC_OFFSET_TABLE_REGNUM]);
       return;
 
     case 'p':
       /* Adjust a power of two to its log2.  */
       if (GET_CODE (x) != CONST_INT || exact_log2 (INTVAL (x)) < 0 )
-       fatal_insn ("Internal: Invalid operand with 'p'", x);
+       LOSE_AND_RETURN ("invalid operand for 'p' modifier", x);
       fprintf (file, "%d", exact_log2 (INTVAL (x)));
       return;
 
@@ -1306,7 +1408,7 @@ cris_print_operand (file, x, code)
         w for -32768 <= x <= 65535, else abort.  */
       if (GET_CODE (x) != CONST_INT
          || INTVAL (x) < -32768 || INTVAL (x) > 65535)
-       fatal_insn ("Internal: Invalid operand with 'z'", x);
+       LOSE_AND_RETURN ("invalid operand for 'z' modifier", x);
       putc (INTVAL (x) >= -128 && INTVAL (x) <= 255 ? 'b' : 'w', file);
       return;
 
@@ -1317,30 +1419,50 @@ cris_print_operand (file, x, code)
        fputs ("\n\tnop", file);
       return;
 
+    case '!':
+      /* Output directive for alignment padded with "nop" insns.
+        Optimizing for size, it's plain 4-byte alignment, otherwise we
+        align the section to a cache-line (32 bytes) and skip at max 2
+        bytes, i.e. we skip if it's the last insn on a cache-line.  The
+        latter is faster by a small amount (for two test-programs 99.6%
+        and 99.9%) and larger by a small amount (ditto 100.1% and
+        100.2%).  This is supposed to be the simplest yet performance-
+        wise least intrusive way to make sure the immediately following
+        (supposed) muls/mulu insn isn't located at the end of a
+        cache-line.  */
+      if (TARGET_MUL_BUG)
+       fputs (optimize_size
+              ? ".p2alignw 2,0x050f\n\t"
+              : ".p2alignw 5,0x050f,2\n\t", file);
+      return;
+
     case 'H':
       /* Print high (most significant) part of something.  */
       switch (GET_CODE (operand))
        {
        case CONST_INT:
-         /* Sign-extension from a normal int to a long long.  */
-         fprintf (file, INTVAL (operand) < 0 ? "-1" : "0");
+         if (HOST_BITS_PER_WIDE_INT == 32)
+           /* Sign-extension from a normal int to a long long.  */
+           fprintf (file, INTVAL (operand) < 0 ? "-1" : "0");
+         else
+           fprintf (file, "0x%x", (unsigned int)(INTVAL (x) >> 31 >> 1));
          return;
 
        case CONST_DOUBLE:
          /* High part of a long long constant.  */
          if (GET_MODE (operand) == VOIDmode)
            {
-             fprintf (file, "0x%x", CONST_DOUBLE_HIGH (x));
+             fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_HIGH (x));
              return;
            }
          else
-           fatal_insn ("Internal: Invalid operand with 'H'", x);
+           LOSE_AND_RETURN ("invalid operand for 'H' modifier", x);
 
        case REG:
          /* Print reg + 1.  Check that there's not an attempt to print
             high-parts of registers like stack-pointer or higher.  */
          if (REGNO (operand) > STACK_POINTER_REGNUM - 2)
-           internal_error ("Internal: Bad register: %d", REGNO (operand));
+           LOSE_AND_RETURN ("bad register", operand);
          fprintf (file, "$%s", reg_names[REGNO (operand) + 1]);
          return;
 
@@ -1364,7 +1486,7 @@ cris_print_operand (file, x, code)
          }
 
        default:
-         fatal_insn ("Internal: Invalid operand for 'H'", x);
+         LOSE_AND_RETURN ("invalid operand for 'H' modifier", x);
        }
 
     case 'L':
@@ -1378,7 +1500,7 @@ cris_print_operand (file, x, code)
       if (GET_CODE (operand) != SIGN_EXTEND
          && GET_CODE (operand) != ZERO_EXTEND
          && GET_CODE (operand) != CONST_INT)
-       fatal_insn ("Internal: Invalid operand with 'e'", x);
+       LOSE_AND_RETURN ("invalid operand for 'e' modifier", x);
 
       if (cris_output_insn_is_bound)
        {
@@ -1395,7 +1517,7 @@ cris_print_operand (file, x, code)
       /* Print the size letter of the inner element.  We can do it by
         calling ourselves with the 's' modifier.  */
       if (GET_CODE (operand) != SIGN_EXTEND && GET_CODE (operand) != ZERO_EXTEND)
-       fatal_insn ("Internal: Invalid operand with 'm'", x);
+       LOSE_AND_RETURN ("invalid operand for 'm' modifier", x);
       cris_print_operand (file, XEXP (operand, 0), 's');
       return;
 
@@ -1403,18 +1525,24 @@ cris_print_operand (file, x, code)
       /* Print the least significant part of operand.  */
       if (GET_CODE (operand) == CONST_DOUBLE)
        {
-         fprintf (file, "0x%x", CONST_DOUBLE_LOW (x));
+         fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
+         return;
+       }
+      else if (HOST_BITS_PER_WIDE_INT > 32 && GET_CODE (operand) == CONST_INT)
+       {
+         fprintf (file, HOST_WIDE_INT_PRINT_HEX,
+                  INTVAL (x) & ((unsigned int) 0x7fffffff * 2 + 1));
          return;
        }
-      /* If not a CONST_DOUBLE, the least significant part equals the
-        normal part, so handle it normally.  */
+      /* Otherwise the least significant part equals the normal part,
+        so handle it normally.  */
       break;
 
     case 'A':
       /* When emitting an add for the high part of a DImode constant, we
         want to use addq for 0 and adds.w for -1.  */
       if (GET_CODE (operand) != CONST_INT)
-       fatal_insn ("Internal: Invalid operand with 'A' output modifier", x);
+       LOSE_AND_RETURN ("invalid operand for 'A' modifier", x);
       fprintf (file, INTVAL (operand) < 0 ? "adds.w" : "addq");
       return;
 
@@ -1422,7 +1550,7 @@ cris_print_operand (file, x, code)
       /* When emitting an sub for the high part of a DImode constant, we
         want to use subq for 0 and subs.w for -1.  */
       if (GET_CODE (operand) != CONST_INT)
-       fatal_insn ("Internal: Invalid operand with 'D' output modifier", x);
+       LOSE_AND_RETURN ("invalid operand for 'D' modifier", x);
       fprintf (file, INTVAL (operand) < 0 ? "subs.w" : "subq");
       return;
 
@@ -1436,30 +1564,24 @@ cris_print_operand (file, x, code)
       /* Print the size letter for an operand to a MULT, which must be a
         const_int with a suitable value.  */
       if (GET_CODE (operand) != CONST_INT || INTVAL (operand) > 4)
-       fatal_insn ("Internal: Invalid operand with 'T'", x);
-
+       LOSE_AND_RETURN ("invalid operand for 'T' modifier", x);
       fprintf (file, "%s", mults[INTVAL (operand)]);
       return;
 
     case 0:
-      /* No code, print as usual. */
+      /* No code, print as usual.  */
       break;
 
     default:
-      {
-#define BADFORMAT "Internal: Invalid operand for '%c'"
-       char s[sizeof BADFORMAT];
-       sprintf (s, BADFORMAT, code);
-       fatal_insn (s, x);
-      }
+      LOSE_AND_RETURN ("invalid operand modifier letter", x);
     }
 
-  /* Print an operand as without a modifier letter. */
+  /* Print an operand as without a modifier letter.  */
   switch (GET_CODE (operand))
     {
     case REG:
       if (REGNO (operand) > 15)
-       internal_error ("Internal: Bad register: %d", REGNO (operand));
+       internal_error ("internal error: bad register: %d", REGNO (operand));
       fprintf (file, "$%s", reg_names[REGNO (operand)]);
       return;
 
@@ -1507,7 +1629,7 @@ cris_print_operand (file, x, code)
        if (GET_CODE (reg) != REG
            || (GET_CODE (XEXP (operand, 0)) != CONST_INT
                && GET_CODE (XEXP (operand, 1)) != CONST_INT))
-         fatal_insn ("Can't print operand", x);
+         LOSE_AND_RETURN ("unexpected multiplicative operand", x);
 
        cris_print_base (reg, file);
        fprintf (file, ".%c",
@@ -1527,16 +1649,14 @@ cris_print_operand (file, x, code)
          return;
        }
 
-      fatal_insn ("Internal: Cannot decode operand", x);
+      LOSE_AND_RETURN ("unexpected operand", x);
     }
 }
 
 /* The PRINT_OPERAND_ADDRESS worker.  */
 
 void
-cris_print_operand_address (file, x)
-     FILE *file;
-     rtx x;
+cris_print_operand_address (FILE *file, rtx x)
 {
   /* All these were inside MEM:s so output indirection characters.  */
   putc ('[', file);
@@ -1562,7 +1682,7 @@ cris_print_operand_address (file, x)
          cris_print_index (x1, file);
        }
       else
-       fatal_insn ("Internal: This is not a recognized address", x);
+       LOSE_AND_RETURN ("unrecognized address", x);
     }
   else if (GET_CODE (x) == MEM)
     {
@@ -1572,7 +1692,7 @@ cris_print_operand_address (file, x)
       putc (']', file);
     }
   else
-    fatal_insn ("Internal: This is not a recognized address", x);
+    LOSE_AND_RETURN ("unrecognized address", x);
 
   putc (']', file);
 }
@@ -1586,9 +1706,7 @@ cris_print_operand_address (file, x)
    initial-value machinery.  */
 
 rtx
-cris_return_addr_rtx (count, frameaddr)
-     int count;
-     rtx frameaddr ATTRIBUTE_UNUSED;
+cris_return_addr_rtx (int count, rtx frameaddr ATTRIBUTE_UNUSED)
 {
   cfun->machine->needs_return_address_on_stack = 1;
 
@@ -1600,11 +1718,20 @@ cris_return_addr_rtx (count, frameaddr)
     : NULL_RTX;
 }
 
+/* Accessor used in cris.md:return because cfun->machine isn't available
+   there.  */
+
+int
+cris_return_address_on_stack ()
+{
+  return cfun->machine->needs_return_address_on_stack;
+}
+
 /* This used to be the INITIAL_FRAME_POINTER_OFFSET worker; now only
    handles FP -> SP elimination offset.  */
 
 static int
-cris_initial_frame_pointer_offset ()
+cris_initial_frame_pointer_offset (void)
 {
   int regno;
 
@@ -1615,7 +1742,7 @@ cris_initial_frame_pointer_offset ()
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
     if ((((regs_ever_live[regno]
           && !call_used_regs[regno])
-         || (regno == PIC_OFFSET_TABLE_REGNUM
+         || (regno == (int) PIC_OFFSET_TABLE_REGNUM
              && (current_function_uses_pic_offset_table
                  /* It is saved anyway, if there would be a gap.  */
                  || (flag_pic
@@ -1649,9 +1776,7 @@ cris_initial_frame_pointer_offset ()
    and imaginary arg pointer.  */
 
 int
-cris_initial_elimination_offset (fromreg, toreg)
-     int fromreg;
-     int toreg;
+cris_initial_elimination_offset (int fromreg, int toreg)
 {
   int fp_sp_offset
     = cris_initial_frame_pointer_offset ();
@@ -1662,7 +1787,7 @@ cris_initial_elimination_offset (fromreg, toreg)
     = regs_ever_live[CRIS_SRP_REGNUM]
     || cfun->machine->needs_return_address_on_stack != 0;
 
-  /* Here we act as if the frame-pointer is needed.  */
+  /* Here we act as if the frame-pointer were needed.  */
   int ap_fp_offset = 4 + (return_address_on_stack ? 4 : 0);
 
   if (fromreg == ARG_POINTER_REGNUM
@@ -1675,7 +1800,7 @@ cris_initial_elimination_offset (fromreg, toreg)
       && toreg == STACK_POINTER_REGNUM)
     return fp_sp_offset;
 
-  /* We need to balance out the frame pointer here. */
+  /* We need to balance out the frame pointer here.  */
   if (fromreg == ARG_POINTER_REGNUM
       && toreg == STACK_POINTER_REGNUM)
     return ap_fp_offset + fp_sp_offset - 4;
@@ -1695,13 +1820,11 @@ cris_initial_elimination_offset (fromreg, toreg)
     check-cc-attribute methods.  */
 
 void
-cris_notice_update_cc (exp, insn)
-     rtx exp;
-     rtx insn;
+cris_notice_update_cc (rtx exp, rtx insn)
 {
   /* Check if user specified "-mcc-init" as a bug-workaround.  FIXME:
      TARGET_CCINIT does not work; we must set CC_REVERSED as below.
-     Several test-cases will otherwise fail, for example
+     Several testcases will otherwise fail, for example
      gcc.c-torture/execute/20000217-1.c -O0 and -O1.  */
   if (TARGET_CCINIT)
     {
@@ -1719,13 +1842,11 @@ cris_notice_update_cc (exp, insn)
       if (GET_CODE (exp) == SET)
        {
          if (cc_status.value1
-             && cris_reg_overlap_mentioned_p (SET_DEST (exp),
-                                            cc_status.value1))
+             && modified_in_p (cc_status.value1, insn))
            cc_status.value1 = 0;
 
          if (cc_status.value2
-             && cris_reg_overlap_mentioned_p (SET_DEST (exp),
-                                            cc_status.value2))
+             && modified_in_p (cc_status.value2, insn))
            cc_status.value2 = 0;
        }
       return;
@@ -1779,13 +1900,13 @@ cris_notice_update_cc (exp, insn)
            return;
 
          /* Record CC0 changes, so we do not have to output multiple
-            test insns. */
+            test insns.  */
          if (SET_DEST (exp) == cc0_rtx)
            {
              cc_status.value1 = SET_SRC (exp);
              cc_status.value2 = 0;
 
-             /* Handle flags for the special btstq on one bit. */
+             /* Handle flags for the special btstq on one bit.  */
              if (GET_CODE (SET_SRC (exp)) == ZERO_EXTRACT
                  && XEXP (SET_SRC (exp), 1) == const1_rtx)
                {
@@ -1805,7 +1926,7 @@ cris_notice_update_cc (exp, insn)
                      && XEXP (SET_SRC (exp), 1) != const0_rtx)
                    /* For some reason gcc will not canonicalize compare
                       operations, reversing the sign by itself if
-                      operands are in wrong order. */
+                      operands are in wrong order.  */
                    /* (But NOT inverted; eq is still eq.) */
                    cc_status.flags = CC_REVERSED;
 
@@ -1823,14 +1944,14 @@ cris_notice_update_cc (exp, insn)
                       && REG_P (XEXP (SET_DEST (exp), 0))))
            {
              /* A register is set; normally CC is set to show that no
-                test insn is needed.  Catch the exceptions. */
+                test insn is needed.  Catch the exceptions.  */
 
              /* If not to cc0, then no "set"s in non-natural mode give
                 ok cc0...  */
              if (GET_MODE_SIZE (GET_MODE (SET_DEST (exp))) > UNITS_PER_WORD
                  || GET_MODE_CLASS (GET_MODE (SET_DEST (exp))) == MODE_FLOAT)
                {
-                 /* ... except add:s and sub:s in DImode. */
+                 /* ... except add:s and sub:s in DImode.  */
                  if (GET_MODE (SET_DEST (exp)) == DImode
                      && (GET_CODE (SET_SRC (exp)) == PLUS
                          || GET_CODE (SET_SRC (exp)) == MINUS))
@@ -1855,14 +1976,12 @@ cris_notice_update_cc (exp, insn)
                {
                  /* There's no CC0 change when clearing a register or
                     memory.  Just check for overlap.  */
-                 if ((cc_status.value1
-                      && cris_reg_overlap_mentioned_p (SET_DEST (exp),
-                                                       cc_status.value1)))
+                 if (cc_status.value1
+                     && modified_in_p (cc_status.value1, insn))
                    cc_status.value1 = 0;
 
-                 if ((cc_status.value2
-                      && cris_reg_overlap_mentioned_p (SET_DEST (exp),
-                                                       cc_status.value2)))
+                 if (cc_status.value2
+                     && modified_in_p (cc_status.value2, insn))
                    cc_status.value2 = 0;
 
                  return;
@@ -1894,14 +2013,12 @@ cris_notice_update_cc (exp, insn)
            {
              /* When SET to MEM, then CC is not changed (except for
                 overlap).  */
-             if ((cc_status.value1
-                  && cris_reg_overlap_mentioned_p (SET_DEST (exp),
-                                                   cc_status.value1)))
+             if (cc_status.value1
+                 && modified_in_p (cc_status.value1, insn))
                cc_status.value1 = 0;
 
-             if ((cc_status.value2
-                  && cris_reg_overlap_mentioned_p (SET_DEST (exp),
-                                                   cc_status.value2)))
+             if (cc_status.value2
+                 && modified_in_p (cc_status.value2, insn))
                cc_status.value2 = 0;
 
              return;
@@ -1920,15 +2037,15 @@ cris_notice_update_cc (exp, insn)
                     value1=rz and value2=[rx] */
                  cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0);
                  cc_status.value2
-                   = gen_rtx_MEM (GET_MODE (XEXP (XVECEXP (exp, 0, 0), 0)),
-                                  XEXP (XVECEXP (exp, 0, 1), 0));
+                   = replace_equiv_address (XEXP (XVECEXP (exp, 0, 0), 1),
+                                            XEXP (XVECEXP (exp, 0, 1), 0));
                  cc_status.flags = 0;
 
                  /* Huh?  A side-effect cannot change the destination
                     register.  */
                  if (cris_reg_overlap_mentioned_p (cc_status.value1,
                                                    cc_status.value2))
-                   internal_error ("Internal: sideeffect-insn affecting main effect");
+                   internal_error ("internal error: sideeffect-insn affecting main effect");
                  return;
                }
              else if ((REG_P (XEXP (XVECEXP (exp, 0, 0), 1))
@@ -1937,17 +2054,14 @@ cris_notice_update_cc (exp, insn)
                {
                  /* For "move.S rz,[rx=ry+o]" and "clear.S [rx=ry+o]",
                     say flags are not changed, except for overlap.  */
-                 if ((cc_status.value1
-                      && cris_reg_overlap_mentioned_p (XEXP
-                                                       (XVECEXP
-                                                        (exp, 0, 0), 0),
-                                                       cc_status.value1))
-                     || (cc_status.value2
-                         && cris_reg_overlap_mentioned_p (XEXP
-                                                          (XVECEXP
-                                                           (exp, 0, 1), 0),
-                                                          cc_status.value2)))
-                   CC_STATUS_INIT;
+                 if (cc_status.value1
+                     && modified_in_p (cc_status.value1, insn))
+                   cc_status.value1 = 0;
+
+                 if (cc_status.value2
+                     && modified_in_p (cc_status.value2, insn))
+                   cc_status.value2 = 0;
+
                  return;
                }
            }
@@ -1967,7 +2081,7 @@ cris_notice_update_cc (exp, insn)
    many registers must be saved, so return 0 then.  */
 
 int
-cris_simple_epilogue ()
+cris_simple_epilogue (void)
 {
   int regno;
   int reglimit = STACK_POINTER_REGNUM;
@@ -1990,7 +2104,7 @@ cris_simple_epilogue ()
      in the delay-slot of the "ret".  */
   for (regno = 0; regno < reglimit; regno++)
     if ((regs_ever_live[regno] && ! call_used_regs[regno])
-       || (regno == PIC_OFFSET_TABLE_REGNUM
+       || (regno == (int) PIC_OFFSET_TABLE_REGNUM
            && (current_function_uses_pic_offset_table
                /* It is saved anyway, if there would be a gap.  */
                || (flag_pic
@@ -2005,11 +2119,118 @@ cris_simple_epilogue ()
   return 1;
 }
 
+/* Compute a (partial) cost for rtx X.  Return true if the complete
+   cost has been computed, and false if subexpressions should be
+   scanned.  In either case, *TOTAL contains the cost result.  */
+
+static bool
+cris_rtx_costs (rtx x, int code, int outer_code, int *total)
+{
+  switch (code)
+    {
+    case CONST_INT:
+      {
+       HOST_WIDE_INT val = INTVAL (x);
+       if (val == 0)
+         *total = 0;
+       else if (val < 32 && val >= -32)
+         *total = 1;
+       /* Eight or 16 bits are a word and cycle more expensive.  */
+       else if (val <= 32767 && val >= -32768)
+         *total = 2;
+       /* A 32 bit constant (or very seldom, unsigned 16 bits) costs
+          another word.  FIXME: This isn't linear to 16 bits.  */
+       else
+         *total = 4;
+       return true;
+      }
+
+    case LABEL_REF:
+      *total = 6;
+      return true;
+
+    case CONST:
+    case SYMBOL_REF:
+      /* For PIC, we need a prefix (if it isn't already there),
+        and the PIC register.  For a global PIC symbol, we also
+        need a read of the GOT.  */
+      if (flag_pic)
+       {
+         if (cris_got_symbol (x))
+           *total = 2 + 4 + 6;
+         else
+           *total = 2 + 6;
+       }
+      else
+       *total = 6;
+      return true;
+
+    case CONST_DOUBLE:
+      if (x != CONST0_RTX (GET_MODE (x) == VOIDmode ? DImode : GET_MODE (x)))
+       *total = 12;
+      else
+        /* Make 0.0 cheap, else test-insns will not be used.  */
+       *total = 0;
+      return true;
+
+    case MULT:
+      /* Identify values that are no powers of two.  Powers of 2 are
+         taken care of already and those values should not be changed.  */
+      if (GET_CODE (XEXP (x, 1)) != CONST_INT
+          || exact_log2 (INTVAL (XEXP (x, 1)) < 0))
+       {
+         /* If we have a multiply insn, then the cost is between
+            1 and 2 "fast" instructions.  */
+         if (TARGET_HAS_MUL_INSNS)
+           {
+             *total = COSTS_N_INSNS (1) + COSTS_N_INSNS (1) / 2;
+             return true;
+           }
+
+         /* Estimate as 4 + 4 * #ofbits.  */
+         *total = COSTS_N_INSNS (132);
+         return true;
+       }
+      return false;
+
+    case UDIV:
+    case MOD:
+    case UMOD:
+    case DIV:
+      if (GET_CODE (XEXP (x, 1)) != CONST_INT
+          || exact_log2 (INTVAL (XEXP (x, 1)) < 0))
+       {
+         /* Estimate this as 4 + 8 * #of bits.  */
+         *total = COSTS_N_INSNS (260);
+         return true;
+       }
+      return false;
+
+    case AND:
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+          /* Two constants may actually happen before optimization.  */
+          && GET_CODE (XEXP (x, 0)) != CONST_INT
+          && !CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'I'))
+       {
+         *total = (rtx_cost (XEXP (x, 0), outer_code) + 2
+                   + 2 * GET_MODE_NUNITS (GET_MODE (XEXP (x, 0))));
+         return true;
+       }
+      return false;
+
+    case ZERO_EXTEND: case SIGN_EXTEND:
+      *total = rtx_cost (XEXP (x, 0), outer_code);
+      return true;
+
+    default:
+      return false;
+    }
+}
+
 /* The ADDRESS_COST worker.  */
 
-int
-cris_address_cost (x)
-     rtx x;
+static int
+cris_address_cost (rtx x)
 {
   /* The metric to use for the cost-macros is unclear.
      The metric used here is (the number of cycles needed) / 2,
@@ -2091,10 +2312,9 @@ cris_address_cost (x)
              whose mode we must consider.  */
 
 int
-cris_side_effect_mode_ok (code, ops, lreg, rreg, rval, multop, other_op)
-     enum rtx_code code;
-     rtx *ops;
-     int lreg, rreg, rval, multop, other_op;
+cris_side_effect_mode_ok (enum rtx_code code, rtx *ops,
+                         int lreg, int rreg, int rval,
+                         int multop, int other_op)
 {
   /* Find what value to multiply with, for rx =ry + rz * n.  */
   int mult = multop < 0 ? 1 : INTVAL (ops[multop]);
@@ -2198,7 +2418,7 @@ cris_side_effect_mode_ok (code, ops, lreg, rreg, rval, multop, other_op)
     }
 
   /* If we get here, the caller got its initial tests wrong.  */
-  internal_error ("Internal: cris_side_effect_mode_ok with bad operands");
+  internal_error ("internal error: cris_side_effect_mode_ok with bad operands");
 }
 
 /* The function reg_overlap_mentioned_p in CVS (still as of 2001-05-16)
@@ -2208,8 +2428,7 @@ cris_side_effect_mode_ok (code, ops, lreg, rreg, rval, multop, other_op)
    anyway.  */
 
 static int
-cris_reg_overlap_mentioned_p (x, in)
-     rtx x, in;
+cris_reg_overlap_mentioned_p (rtx x, rtx in)
 {
   /* The function reg_overlap_mentioned now handles when X is
      strict_low_part, but not when IN is a STRICT_LOW_PART.  */
@@ -2223,21 +2442,19 @@ cris_reg_overlap_mentioned_p (x, in)
    We just dispatch to the functions for ELF and a.out.  */
 
 void
-cris_target_asm_named_section (name, flags)
-     const char *name;
-     unsigned int flags;
+cris_target_asm_named_section (const char *name, unsigned int flags,
+                              tree decl)
 {
   if (! TARGET_ELF)
-    default_no_named_section (name, flags);
+    default_no_named_section (name, flags, decl);
   else
-    default_elf_asm_named_section (name, flags);
+    default_elf_asm_named_section (name, flags, decl);
 }
 
 /* The LEGITIMATE_PIC_OPERAND_P worker.  */
 
 int
-cris_legitimate_pic_operand (x)
-     rtx x;
+cris_legitimate_pic_operand (rtx x)
 {
   /* The PIC representation of a symbol with a GOT entry will be (for
      example; relocations differ):
@@ -2249,12 +2466,11 @@ cris_legitimate_pic_operand (x)
   return ! cris_symbol (x) || cris_got_symbol (x);
 }
 
-/* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+/* Return nonzero if there's a SYMBOL_REF or LABEL_REF hiding inside this
    CONSTANT_P.  */
 
 int
-cris_symbol (x)
-     rtx x;
+cris_symbol (rtx x)
 {
   switch (GET_CODE (x))
     {
@@ -2276,25 +2492,28 @@ cris_symbol (x)
 
     case CONST_INT:
     case CONST_DOUBLE:
-    case CONSTANT_P_RTX:
       return 0;
 
     default:
-      fatal_insn ("Unrecognized supposed constant", x);
+      fatal_insn ("unrecognized supposed constant", x);
     }
 
   return 1;
 }
 
-/* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+/* Return nonzero if there's a SYMBOL_REF or LABEL_REF hiding inside this
    CONSTANT_P, and the symbol does not need a GOT entry.  Also set
    current_function_uses_pic_offset_table if we're generating PIC and ever
    see something that would need one.  */
 
 int
-cris_gotless_symbol (x)
-     rtx x;
+cris_gotless_symbol (rtx x)
 {
+#ifdef ENABLE_CHECKING
+  if (!flag_pic)
+    abort ();
+#endif
+
   switch (GET_CODE (x))
     {
     case UNSPEC:
@@ -2302,9 +2521,9 @@ cris_gotless_symbol (x)
       return 1;
 
     case SYMBOL_REF:
-      if (flag_pic && cfun != NULL)
+      if (cfun != NULL)
        current_function_uses_pic_offset_table = 1;
-      return SYMBOL_REF_FLAG (x);
+      return SYMBOL_REF_LOCAL_P (x);
 
     case LABEL_REF:
       /* We don't set current_function_uses_pic_offset_table for
@@ -2334,23 +2553,26 @@ cris_gotless_symbol (x)
 
     case CONST_INT:
     case CONST_DOUBLE:
-    case CONSTANT_P_RTX:
       return 0;
 
     default:
-      fatal_insn ("Unrecognized supposed constant", x);
+      fatal_insn ("unrecognized supposed constant", x);
     }
 
   return 1;
 }
 
-/* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+/* Return nonzero if there's a SYMBOL_REF or LABEL_REF hiding inside this
    CONSTANT_P, and the symbol needs a GOT entry.  */
 
 int
-cris_got_symbol (x)
-     rtx x;
+cris_got_symbol (rtx x)
 {
+#ifdef ENABLE_CHECKING
+  if (!flag_pic)
+    abort ();
+#endif
+
   switch (GET_CODE (x))
     {
     case UNSPEC:
@@ -2358,9 +2580,9 @@ cris_got_symbol (x)
       return 0;
 
     case SYMBOL_REF:
-      if (flag_pic && cfun != NULL)
+      if (cfun != NULL)
        current_function_uses_pic_offset_table = 1;
-      return ! SYMBOL_REF_FLAG (x);
+      return ! SYMBOL_REF_LOCAL_P (x);
 
     case CONST:
       return cris_got_symbol (XEXP (x, 0));
@@ -2375,11 +2597,10 @@ cris_got_symbol (x)
 
     case CONST_INT:
     case CONST_DOUBLE:
-    case CONSTANT_P_RTX:
       return 0;
 
     default:
-      fatal_insn ("Unrecognized supposed constant in cris_global_pic_symbol",
+      fatal_insn ("unrecognized supposed constant in cris_global_pic_symbol",
                  x);
     }
 
@@ -2390,7 +2611,7 @@ cris_got_symbol (x)
    As is the norm, this also parses -mfoo=bar type parameters.  */
 
 void
-cris_override_options ()
+cris_override_options (void)
 {
   if (cris_max_stackframe_str)
     {
@@ -2426,7 +2647,7 @@ cris_override_options ()
        cris_cpu_version = 10;
 
       if (cris_cpu_version < 0 || cris_cpu_version > 10)
-       error ("Unknown CRIS version specification in -march= or -mcpu= : %s",
+       error ("unknown CRIS version specification in -march= or -mcpu= : %s",
               cris_cpu_str);
 
       /* Set the target flags.  */
@@ -2462,7 +2683,7 @@ cris_override_options ()
        cris_tune = 10;
 
       if (cris_tune < 0 || cris_tune > 10)
-       error ("Unknown CRIS cpu version specification in -mtune= : %s",
+       error ("unknown CRIS cpu version specification in -mtune= : %s",
               cris_tune_str);
 
       if (cris_tune >= CRIS_CPU_SVINTO)
@@ -2480,7 +2701,7 @@ cris_override_options ()
         further errors.  */
       if (! TARGET_LINUX)
        {
-         error ("-fPIC not supported in this configuration");
+         error ("-fPIC and -fpic are not supported in this configuration");
          flag_pic = 0;
        }
 
@@ -2493,10 +2714,9 @@ cris_override_options ()
       flag_no_function_cse = 1;
     }
 
-  if ((write_symbols == DWARF_DEBUG
-       || write_symbols == DWARF2_DEBUG) && ! TARGET_ELF)
+  if (write_symbols == DWARF2_DEBUG && ! TARGET_ELF)
     {
-      warning ("Specified -g option is invalid with -maout and -melinux");
+      warning ("that particular -g option is invalid with -maout and -melinux");
       write_symbols = DBX_DEBUG;
     }
 
@@ -2504,29 +2724,29 @@ cris_override_options ()
   init_machine_status = cris_init_machine_status;
 }
 
-/* The ASM_OUTPUT_MI_THUNK worker.  */
+/* The TARGET_ASM_OUTPUT_MI_THUNK worker.  */
 
-void
-cris_asm_output_mi_thunk (stream, thunkdecl, delta, funcdecl)
-     FILE *stream;
-     tree thunkdecl ATTRIBUTE_UNUSED;
-     int delta;
-     tree funcdecl;
+static void
+cris_asm_output_mi_thunk (FILE *stream,
+                         tree thunkdecl ATTRIBUTE_UNUSED,
+                         HOST_WIDE_INT delta,
+                         HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+                         tree funcdecl)
 {
   if (delta > 0)
-    asm_fprintf (stream, "\tadd%s %d,$%s\n",
-                ADDITIVE_SIZE_MODIFIER (delta), delta,
-                reg_names[CRIS_FIRST_ARG_REG]);
+    fprintf (stream, "\tadd%s " HOST_WIDE_INT_PRINT_DEC ",$%s\n",
+            ADDITIVE_SIZE_MODIFIER (delta), delta,
+            reg_names[CRIS_FIRST_ARG_REG]);
   else if (delta < 0)
-    asm_fprintf (stream, "\tsub%s %d,$%s\n",
-                ADDITIVE_SIZE_MODIFIER (-delta), -delta,
-                reg_names[CRIS_FIRST_ARG_REG]);
+    fprintf (stream, "\tsub%s " HOST_WIDE_INT_PRINT_DEC ",$%s\n",
+            ADDITIVE_SIZE_MODIFIER (-delta), -delta,
+            reg_names[CRIS_FIRST_ARG_REG]);
 
   if (flag_pic)
     {
       const char *name = XSTR (XEXP (DECL_RTL (funcdecl), 0), 0);
 
-      STRIP_NAME_ENCODING (name, name);
+      name = (* targetm.strip_name_encoding) (name);
       fprintf (stream, "add.d ");
       assemble_name (stream, name);
       fprintf (stream, "%s,$pc\n", CRIS_PLT_PCOFFSET_SUFFIX);
@@ -2539,86 +2759,68 @@ cris_asm_output_mi_thunk (stream, thunkdecl, delta, funcdecl)
     }
 }
 
-/* The EXPAND_BUILTIN_VA_ARG worker.  This is modified from the
-   "standard" implementation of va_arg: read the value from the current
-   address and increment by the size of one or two registers.  The
-   important difference for CRIS is that if the type is
-   pass-by-reference, then perform an indirection.  */
+/* Boilerplate emitted at start of file.  
 
-rtx
-cris_expand_builtin_va_arg (valist, type)
-     tree valist;
-     tree type;
-{
-  tree addr_tree, t;
-  rtx addr;
-  enum machine_mode mode = TYPE_MODE (type);
-  int passed_size;
+   NO_APP *only at file start* means faster assembly.  It also means
+   comments are not allowed.  In some cases comments will be output
+   for debugging purposes.  Make sure they are allowed then.
 
-  /* Get AP.  */
-  addr_tree = valist;
-
-  /* Check if the type is passed by value or by reference.  */
-  if (MUST_PASS_IN_STACK (mode, type)
-      || CRIS_FUNCTION_ARG_SIZE (mode, type) > 8)
-    {
-      tree type_ptr = build_pointer_type (type);
-      addr_tree = build1 (INDIRECT_REF, type_ptr, addr_tree);
-      passed_size = 4;
-    }
-  else
-    passed_size = (CRIS_FUNCTION_ARG_SIZE (mode, type) > 4) ? 8 : 4;
-
-  addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
-  addr = copy_to_reg (addr);
+   We want a .file directive only if TARGET_ELF.  */
+static void
+cris_file_start (void)
+{
+  /* These expressions can vary at run time, so we cannot put
+     them into TARGET_INITIALIZER.  */
+  targetm.file_start_app_off = !(TARGET_PDEBUG || flag_print_asm_name);
+  targetm.file_start_file_directive = TARGET_ELF;
 
-  /* Compute new value for AP.  */
-  t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-            build (PLUS_EXPR, TREE_TYPE (valist), valist,
-                   build_int_2 (passed_size, 0)));
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+  default_file_start ();
+}
 
-  return addr;
+/* Rename the function calls for integer multiply and divide.  */
+static void
+cris_init_libfuncs (void)
+{
+  set_optab_libfunc (smul_optab, SImode, "__Mul");
+  set_optab_libfunc (sdiv_optab, SImode, "__Div");
+  set_optab_libfunc (udiv_optab, SImode, "__Udiv");
+  set_optab_libfunc (smod_optab, SImode, "__Mod");
+  set_optab_libfunc (umod_optab, SImode, "__Umod");
 }
 
 /* The INIT_EXPANDERS worker sets the per-function-data initializer and
    mark functions.  */
 
 void
-cris_init_expanders ()
+cris_init_expanders (void)
 {
   /* Nothing here at the moment.  */
 }
 
 /* Zero initialization is OK for all current fields.  */
 
-static void
-cris_init_machine_status (p)
-     struct function *p;
+static struct machine_function *
+cris_init_machine_status (void)
 {
-  p->machine = xcalloc (1, sizeof (struct machine_function));
+  return ggc_alloc_cleared (sizeof (struct machine_function));
 }
 
 /* Split a 2 word move (DI or presumably DF) into component parts.
    Originally a copy of gen_split_move_double in m32r.c.  */
 
 rtx
-cris_split_movdx (operands)
-     rtx *operands;
+cris_split_movdx (rtx *operands)
 {
   enum machine_mode mode = GET_MODE (operands[0]);
   rtx dest = operands[0];
   rtx src  = operands[1];
   rtx val;
 
-  /* We might have (SUBREG (MEM)) here, so just get rid of the
-     subregs to make this code simpler.  It is safe to call
-     alter_subreg any time after reload.  */
-  if (GET_CODE (dest) == SUBREG)
-    dest = alter_subreg (dest);
-  if (GET_CODE (src) == SUBREG)
-    src = alter_subreg (src);
+  /* We used to have to handle (SUBREG (MEM)) here, but that should no
+     longer happen; after reload there are no SUBREGs any more, and we're
+     only called after reload.  */
+  if (GET_CODE (dest) == SUBREG || GET_CODE (src) == SUBREG)
+    abort ();
 
   start_sequence ();
   if (GET_CODE (dest) == REG)
@@ -2665,7 +2867,7 @@ cris_split_movdx (operands)
          int reverse
            = (refers_to_regno_p (dregno, dregno + 1, addr, NULL) != 0);
 
-         /* The original code imples that we can't do
+         /* The original code implies that we can't do
             move.x [rN+],rM  move.x [rN],rM+1
             when rN is dead, because of REG_NOTES damage.  That is
             consistent with what I've seen, so don't try it.
@@ -2675,11 +2877,11 @@ cris_split_movdx (operands)
 
           if (GET_CODE (addr) == POST_INC)
            {
-             emit_insn (gen_rtx_SET (VOIDmode, 
+             emit_insn (gen_rtx_SET (VOIDmode,
                                      operand_subword (dest, 0, TRUE, mode),
                                      change_address (src, SImode, addr)));
              emit_insn (gen_rtx_SET (VOIDmode,
-                                     operand_subword (dest, 1, TRUE, mode), 
+                                     operand_subword (dest, 1, TRUE, mode),
                                      change_address (src, SImode, addr)));
            }
          else
@@ -2689,7 +2891,7 @@ cris_split_movdx (operands)
                 GO_IF_LEGITIMATE_ADDRESS, but we're here for your
                 safety.  */
              if (side_effects_p (addr))
-               fatal_insn ("Unexpected side-effects in address", addr);
+               fatal_insn ("unexpected side-effects in address", addr);
 
              emit_insn (gen_rtx_SET
                         (VOIDmode,
@@ -2734,7 +2936,7 @@ cris_split_movdx (operands)
             postincrements.  They should be stopped in
             GO_IF_LEGITIMATE_ADDRESS, but we're here for your safety.  */
          if (side_effects_p (addr))
-           fatal_insn ("Unexpected side-effects in address", addr);
+           fatal_insn ("unexpected side-effects in address", addr);
 
          emit_insn (gen_rtx_SET
                     (VOIDmode,
@@ -2753,262 +2955,224 @@ cris_split_movdx (operands)
   else
     abort ();
 
-  val = gen_sequence ();
+  val = get_insns ();
   end_sequence ();
   return val;
 }
 
-/* This is in essence a copy of output_addr_const altered to output
-   symbolic operands as PIC.
+/* Use from within code, from e.g. PRINT_OPERAND and
+   PRINT_OPERAND_ADDRESS.  Macros used in output_addr_const need to emit
+   different things depending on whether code operand or constant is
+   emitted.  */
 
-   FIXME: Add hooks similar to ASM_OUTPUT_SYMBOL_REF to get this effect in
-   the "real" output_addr_const.  All we need is one for LABEL_REF (and
-   one for CODE_LABEL?).  */
+static void
+cris_output_addr_const (FILE *file, rtx x)
+{
+  in_code++;
+  output_addr_const (file, x);
+  in_code--;
+}
+
+/* Worker function for ASM_OUTPUT_SYMBOL_REF.  */
 
 void
-cris_output_addr_const (file, x)
-     FILE *file;
-     rtx x;
+cris_asm_output_symbol_ref (FILE *file, rtx x)
 {
-  int is_plt = 0;
-
-restart:
-  switch (GET_CODE (x))
+  if (flag_pic && in_code > 0)
     {
-    case UNSPEC:
-      ASSERT_PLT_UNSPEC (x);
-      x = XVECEXP (x, 0, 0);
-      is_plt = 1;
+      const char *origstr = XSTR (x, 0);
+      const char *str;
 
-      /* Fall through.  */
-    case SYMBOL_REF:
-      if (flag_pic)
-       {
-         const char *origstr = XSTR (x, 0);
-         const char *str;
+      str = (* targetm.strip_name_encoding) (origstr);
 
-         STRIP_NAME_ENCODING (str, origstr);
-
-         if (is_plt)
-           {
-             if (cris_pic_sympart_only)
-               {
-                 assemble_name (file, str);
-                 fprintf (file, ":PLTG");
-               }
-             else
-               {
-                 if (TARGET_AVOID_GOTPLT)
-                   /* We shouldn't get here.  */
-                   abort ();
-
-                 fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
-                 assemble_name (file, XSTR (x, 0));
-
-                 if (flag_pic == 1)
-                   fprintf (file, ":GOTPLT16]");
-                 else
-                   fprintf (file, ":GOTPLT]");
-               }
-           }
-         else if (cris_gotless_symbol (x))
-           {
-             if (! cris_pic_sympart_only)
-               fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
-             assemble_name (file, str);
-             fprintf (file, ":GOTOFF");
-           }
-         else if (cris_got_symbol (x))
-           {
-             if (cris_pic_sympart_only)
-               abort ();
-             fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
-             assemble_name (file, XSTR (x, 0));
+      if (cris_gotless_symbol (x))
+       {
+         if (! cris_pic_sympart_only)
+           fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+         assemble_name (file, str);
+         fprintf (file, ":GOTOFF");
+       }
+      else if (cris_got_symbol (x))
+       {
+         if (cris_pic_sympart_only)
+           abort ();
+         fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+         assemble_name (file, XSTR (x, 0));
 
-             if (flag_pic == 1)
-               fprintf (file, ":GOT16]");
-             else
-               fprintf (file, ":GOT]");
-           }
+         if (flag_pic == 1)
+           fprintf (file, ":GOT16]");
          else
-           fatal_insn ("Unexpected PIC symbol", x);
-
-         /* Sanity check.  */
-         if (! current_function_uses_pic_offset_table)
-           internal_error ("Emitting PIC operand, but PIC register isn't set up");
+           fprintf (file, ":GOT]");
        }
       else
-       assemble_name (file, XSTR (x, 0));
-      break;
+       LOSE_AND_RETURN ("unexpected PIC symbol", x);
 
-    case LABEL_REF:
-      /* If we get one of those here, it should be dressed as PIC.  Branch
-        labels are normally output with the 'l' specifier, which means it
-        will go directly to output_asm_label and not end up here.  */
-      if (GET_CODE (XEXP (x, 0)) != CODE_LABEL
-         && (GET_CODE (XEXP (x, 0)) != NOTE
-             || NOTE_LINE_NUMBER (XEXP (x, 0)) != NOTE_INSN_DELETED_LABEL))
-       fatal_insn ("Unexpected address expression", x);
+      /* Sanity check.  */
+      if (! current_function_uses_pic_offset_table)
+       output_operand_lossage ("PIC register isn't set up");
+    }
+  else
+    assemble_name (file, XSTR (x, 0));
+}
 
-      if (flag_pic)
-       {
-         if (cris_gotless_symbol (x))
-           {
-             if (! cris_pic_sympart_only)
-               fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
-             cris_output_addr_const (file, XEXP (x, 0));
+/* Worker function for ASM_OUTPUT_LABEL_REF.  */
 
-             fprintf (file, ":GOTOFF");
-           }
-         else
-           /* Labels are never marked as global symbols.  */
-           fatal_insn ("Unexpected PIC symbol", x);
+void
+cris_asm_output_label_ref (FILE *file, char *buf)
+{
+  if (flag_pic && in_code > 0)
+    {
+      if (! cris_pic_sympart_only)
+       fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+      assemble_name (file, buf);
 
-         /* Sanity check.  */
-         if (! current_function_uses_pic_offset_table)
-           internal_error ("Emitting PIC operand, but PIC register isn't set up");
-         break;
-       }
+      fprintf (file, ":GOTOFF");
 
-      output_addr_const (file, x);
-      break;
+      /* Sanity check.  */
+      if (! current_function_uses_pic_offset_table)
+       internal_error ("emitting PIC operand, but PIC register isn't set up");
+    }
+  else
+    assemble_name (file, buf);
+}
 
-    case NOTE:
-      if (NOTE_LINE_NUMBER (x) != NOTE_INSN_DELETED_LABEL)
-       fatal_insn ("Unexpected NOTE as addr_const:", x);
-    case CODE_LABEL:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case ZERO_EXTEND:
-    case SIGN_EXTEND:
-      output_addr_const (file, x);
-      break;
+/* Worker function for OUTPUT_ADDR_CONST_EXTRA.  */
 
-    case CONST:
-      /* This used to output parentheses around the expression,
-        but that does not work on the 386 (either ATT or BSD assembler).  */
-      cris_output_addr_const (file, XEXP (x, 0));
-      break;
+bool
+cris_output_addr_const_extra (FILE *file, rtx x)
+{
+  switch (GET_CODE (x))
+    {
+      const char *origstr;
+      const char *str;
 
-    case PLUS:
-      /* Some assemblers need integer constants to appear last (eg masm).  */
-      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+    case UNSPEC:
+      ASSERT_PLT_UNSPEC (x);
+      x = XVECEXP (x, 0, 0);
+      origstr = XSTR (x, 0);
+      str = (* targetm.strip_name_encoding) (origstr);
+      if (cris_pic_sympart_only)
        {
-         cris_output_addr_const (file, XEXP (x, 1));
-         if (INTVAL (XEXP (x, 0)) >= 0)
-           fprintf (file, "+");
-         output_addr_const (file, XEXP (x, 0));
+         assemble_name (file, str);
+         fprintf (file, ":PLTG");
        }
       else
        {
-         cris_output_addr_const (file, XEXP (x, 0));
-         if (GET_CODE (XEXP (x, 1)) != CONST_INT
-             || INTVAL (XEXP (x, 1)) >= 0)
-           fprintf (file, "+");
-         cris_output_addr_const (file, XEXP (x, 1));
-       }
-      break;
+         if (TARGET_AVOID_GOTPLT)
+           /* We shouldn't get here.  */
+           abort ();
 
-    case MINUS:
-      /* Avoid outputting things like x-x or x+5-x,
-        since some assemblers can't handle that.  */
-      x = simplify_subtraction (x);
-      if (GET_CODE (x) != MINUS)
-       goto restart;
-
-      cris_output_addr_const (file, XEXP (x, 0));
-      fprintf (file, "-");
-      if ((GET_CODE (XEXP (x, 1)) == CONST_INT
-          && INTVAL (XEXP (x, 1)) < 0)
-         || GET_CODE (XEXP (x, 1)) != CONST_INT)
-       {
-         fprintf (file, "%s", targetm.asm_out.open_paren);
-         cris_output_addr_const (file, XEXP (x, 1));
-         fprintf (file, "%s", targetm.asm_out.close_paren);
+         fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+         assemble_name (file, XSTR (x, 0));
+
+         if (flag_pic == 1)
+           fprintf (file, ":GOTPLT16]");
+         else
+           fprintf (file, ":GOTPLT]");
        }
-      else
-       output_addr_const (file, XEXP (x, 1));
-      break;
+      return true;
 
     default:
-      fatal_insn ("Unexpected address expression", x);
+      return false;
     }
 }
 
-/* The ENCODE_SECTION_INFO worker.  Code-in whether we can get away
-   without a GOT entry (needed for externally visible objects but not for
-   functions) into SYMBOL_REF_FLAG and add the PLT suffix for global
-   functions.  */
+/* Worker function for TARGET_STRUCT_VALUE_RTX.  */
 
-void
-cris_encode_section_info (exp)
-     tree exp;
+static rtx
+cris_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
+                      int incoming ATTRIBUTE_UNUSED)
 {
-  if (flag_pic)
+  return gen_rtx_REG (Pmode, CRIS_STRUCT_VALUE_REGNUM);
+}
+
+/* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
+
+static void
+cris_setup_incoming_varargs (CUMULATIVE_ARGS *ca,
+                            enum machine_mode mode ATTRIBUTE_UNUSED,
+                            tree type ATTRIBUTE_UNUSED,
+                            int *pretend_arg_size,
+                            int second_time)
+{
+  if (ca->regs < CRIS_MAX_ARGS_IN_REGS)
+    *pretend_arg_size = (CRIS_MAX_ARGS_IN_REGS - ca->regs) * 4;
+  if (TARGET_PDEBUG)
     {
-      if (DECL_P (exp))
-       {
-         if (TREE_CODE (exp) == FUNCTION_DECL
-             && (TREE_PUBLIC (exp) || DECL_WEAK (exp)))
-           SYMBOL_REF_FLAG (XEXP (DECL_RTL (exp), 0)) = 0;
-         else
-           SYMBOL_REF_FLAG (XEXP (DECL_RTL (exp), 0))
-             = ! TREE_PUBLIC (exp) && ! DECL_WEAK (exp);
-       }
-      else
-       /* Others are local entities.  */
-       SYMBOL_REF_FLAG (XEXP (TREE_CST_RTL (exp), 0)) = 1;
+      fprintf (asm_out_file,
+              "\n; VA:: ANSI: %d args before, anon @ #%d, %dtime\n",
+              ca->regs, *pretend_arg_size, second_time);
     }
 }
 
+/* Return true if TYPE must be passed by invisible reference.
+   For cris, we pass <= 8 bytes by value, others by reference.  */
+
+static bool
+cris_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
+                       enum machine_mode mode, tree type,
+                       bool named ATTRIBUTE_UNUSED)
+{
+  return (targetm.calls.must_pass_in_stack (mode, type)
+         || CRIS_FUNCTION_ARG_SIZE (mode, type) > 8);
+}
+
+
+static int
+cris_arg_partial_bytes (CUMULATIVE_ARGS *ca, enum machine_mode mode,
+                       tree type, bool named ATTRIBUTE_UNUSED)
+{
+  if (ca->regs == CRIS_MAX_ARGS_IN_REGS - 1
+      && !targetm.calls.must_pass_in_stack (mode, type)
+      && CRIS_FUNCTION_ARG_SIZE (mode, type) > 4
+      && CRIS_FUNCTION_ARG_SIZE (mode, type) <= 8)
+    return UNITS_PER_WORD;
+  else
+    return 0;
+}
+
+
 #if 0
 /* Various small functions to replace macros.  Only called from a
    debugger.  They might collide with gcc functions or system functions,
    so only emit them when '#if 1' above.  */
 
-enum rtx_code Get_code PARAMS ((rtx));
+enum rtx_code Get_code (rtx);
 
 enum rtx_code
-Get_code (x)
-     rtx x;
+Get_code (rtx x)
 {
   return GET_CODE (x);
 }
 
-const char *Get_mode PARAMS ((rtx));
+const char *Get_mode (rtx);
 
 const char *
-Get_mode (x)
-     rtx x;
+Get_mode (rtx x)
 {
   return GET_MODE_NAME (GET_MODE (x));
 }
 
-rtx Xexp PARAMS ((rtx, int));
+rtx Xexp (rtx, int);
 
 rtx
-Xexp (x, n)
-     rtx x;
-     int n;
+Xexp (rtx x, int n)
 {
   return XEXP (x, n);
 }
 
-rtx Xvecexp PARAMS ((rtx, int, int));
+rtx Xvecexp (rtx, int, int);
 
 rtx
-Xvecexp (x, n, m)
-     rtx x;
-     int n;
-{ 
+Xvecexp (rtx x, int n, int m)
+{
   return XVECEXP (x, n, m);
 }
 
-int Get_rtx_len PARAMS ((rtx));
+int Get_rtx_len (rtx);
 
 int
-Get_rtx_len (x)
-     rtx x;
+Get_rtx_len (rtx x)
 {
   return GET_RTX_LENGTH (GET_CODE (x));
 }
@@ -3016,25 +3180,25 @@ Get_rtx_len (x)
 /* Use upper-case to distinguish from local variables that are sometimes
    called next_insn and prev_insn.  */
 
-rtx Next_insn PARAMS ((rtx));
+rtx Next_insn (rtx);
 
 rtx
-Next_insn (insn)
-     rtx insn;
+Next_insn (rtx insn)
 {
   return NEXT_INSN (insn);
 }
 
-rtx Prev_insn PARAMS ((rtx));
+rtx Prev_insn (rtx);
 
 rtx
-Prev_insn (insn)
-     rtx insn;
+Prev_insn (rtx insn)
 {
   return PREV_INSN (insn);
 }
 #endif
 
+#include "gt-cris.h"
+
 /*
  * Local variables:
  * eval: (c-set-style "gnu")