diff gcc/config/cris/cris.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents f6334be47118
children 84e7813d76e9
line wrap: on
line diff
--- a/gcc/config/cris/cris.c	Sun Aug 21 07:07:55 2011 +0900
+++ b/gcc/config/cris/cris.c	Fri Oct 27 22:46:09 2017 +0900
@@ -1,6 +1,5 @@
 /* Definitions for GCC.  Part of the machine description for CRIS.
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-   2008, 2009, 2010  Free Software Foundation, Inc.
+   Copyright (C) 1998-2017 Free Software Foundation, Inc.
    Contributed by Axis Communications.  Written by Hans-Peter Nilsson.
 
 This file is part of GCC.
@@ -22,29 +21,37 @@
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "target.h"
 #include "rtl.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "cfghooks.h"
+#include "df.h"
+#include "memmodel.h"
+#include "tm_p.h"
+#include "optabs.h"
 #include "regs.h"
-#include "hard-reg-set.h"
-#include "insn-config.h"
+#include "emit-rtl.h"
+#include "recog.h"
+#include "cgraph.h"
+#include "diagnostic-core.h"
 #include "conditions.h"
 #include "insn-attr.h"
-#include "flags.h"
-#include "tree.h"
+#include "alias.h"
+#include "varasm.h"
+#include "stor-layout.h"
+#include "calls.h"
+#include "explow.h"
 #include "expr.h"
-#include "except.h"
-#include "function.h"
-#include "diagnostic-core.h"
-#include "recog.h"
 #include "reload.h"
-#include "tm_p.h"
-#include "debug.h"
 #include "output.h"
-#include "target.h"
+#include "tm-constrs.h"
+#include "builtins.h"
+
+/* This file should be included last.  */
 #include "target-def.h"
-#include "ggc.h"
-#include "optabs.h"
-#include "df.h"
 
 /* Usable when we have an amount to add or subtract, and want the
    optimal size of the insn.  */
@@ -84,9 +91,11 @@
 /* Fix for reg_overlap_mentioned_p.  */
 static int cris_reg_overlap_mentioned_p (rtx, rtx);
 
-static enum machine_mode cris_promote_function_mode (const_tree, enum machine_mode,
+static machine_mode cris_promote_function_mode (const_tree, machine_mode,
 						     int *, const_tree, int);
 
+static unsigned int cris_atomic_align_for_mode (machine_mode);
+
 static void cris_print_base (rtx, FILE *);
 
 static void cris_print_index (rtx, FILE *);
@@ -97,7 +106,7 @@
 
 static rtx cris_struct_value_rtx (tree, int);
 
-static void cris_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
+static void cris_setup_incoming_varargs (cumulative_args_t, machine_mode,
 					 tree type, int *, int);
 
 static int cris_initial_frame_pointer_offset (void);
@@ -108,10 +117,12 @@
 
 static void cris_print_operand (FILE *, rtx, int);
 
-static void cris_print_operand_address (FILE *, rtx);
+static void cris_print_operand_address (FILE *, machine_mode, rtx);
 
 static bool cris_print_operand_punct_valid_p (unsigned char code);
 
+static bool cris_output_addr_const_extra (FILE *, rtx);
+
 static void cris_conditional_register_usage (void);
 
 static void cris_asm_output_mi_thunk
@@ -120,23 +131,27 @@
 static void cris_file_start (void);
 static void cris_init_libfuncs (void);
 
-static int cris_register_move_cost (enum machine_mode, reg_class_t, reg_class_t);
-static int cris_memory_move_cost (enum machine_mode, reg_class_t, bool);
-static bool cris_rtx_costs (rtx, int, int, int *, bool);
-static int cris_address_cost (rtx, bool);
-static bool cris_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+static reg_class_t cris_preferred_reload_class (rtx, reg_class_t);
+
+static int cris_register_move_cost (machine_mode, reg_class_t, reg_class_t);
+static int cris_memory_move_cost (machine_mode, reg_class_t, bool);
+static bool cris_rtx_costs (rtx, machine_mode, int, int, int *, bool);
+static int cris_address_cost (rtx, machine_mode, addr_space_t, bool);
+static bool cris_pass_by_reference (cumulative_args_t, machine_mode,
 				    const_tree, bool);
-static int cris_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+static int cris_arg_partial_bytes (cumulative_args_t, machine_mode,
 				   tree, bool);
-static rtx cris_function_arg (CUMULATIVE_ARGS *, enum machine_mode,
+static rtx cris_function_arg (cumulative_args_t, machine_mode,
 			      const_tree, bool);
-static rtx cris_function_incoming_arg (CUMULATIVE_ARGS *,
-				       enum machine_mode, const_tree, bool);
-static void cris_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
+static rtx cris_function_incoming_arg (cumulative_args_t,
+				       machine_mode, const_tree, bool);
+static void cris_function_arg_advance (cumulative_args_t, machine_mode,
 				       const_tree, bool);
-static tree cris_md_asm_clobbers (tree, tree, tree);
-
-static bool cris_handle_option (size_t, const char *, int);
+static rtx_insn *cris_md_asm_adjust (vec<rtx> &, vec<rtx> &,
+				     vec<const char *> &,
+				     vec<rtx> &, HARD_REG_SET &);
+static bool cris_cannot_force_const_mem (machine_mode, rtx);
+
 static void cris_option_override (void);
 
 static bool cris_frame_pointer_required (void);
@@ -145,7 +160,13 @@
 static void cris_trampoline_init (rtx, tree, rtx);
 
 static rtx cris_function_value(const_tree, const_tree, bool);
-static rtx cris_libcall_value (enum machine_mode, const_rtx);
+static rtx cris_libcall_value (machine_mode, const_rtx);
+static bool cris_function_value_regno_p (const unsigned int);
+static void cris_file_end (void);
+static unsigned int cris_hard_regno_nregs (unsigned int, machine_mode);
+static bool cris_hard_regno_mode_ok (unsigned int, machine_mode);
+static HOST_WIDE_INT cris_static_rtx_alignment (machine_mode);
+static HOST_WIDE_INT cris_constant_alignment (const_tree, HOST_WIDE_INT);
 
 /* This is the parsed result of the "-max-stack-stackframe=" option.  If
    it (still) is zero, then there was no such option given.  */
@@ -154,14 +175,6 @@
 /* This is the parsed result of the "-march=" option, if given.  */
 int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION;
 
-/* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
-
-static const struct default_options cris_option_optimization_table[] =
-  {
-    { OPT_LEVELS_2_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
-    { OPT_LEVELS_NONE, 0, NULL, 0 }
-  };
-
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
 #undef TARGET_ASM_ALIGNED_SI_OP
@@ -187,6 +200,8 @@
 #define TARGET_PRINT_OPERAND_ADDRESS cris_print_operand_address
 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P cris_print_operand_punct_valid_p
+#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
+#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA cris_output_addr_const_extra
 
 #undef TARGET_CONDITIONAL_REGISTER_USAGE
 #define TARGET_CONDITIONAL_REGISTER_USAGE cris_conditional_register_usage
@@ -198,10 +213,24 @@
 
 #undef TARGET_ASM_FILE_START
 #define TARGET_ASM_FILE_START cris_file_start
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END cris_file_end
 
 #undef TARGET_INIT_LIBFUNCS
 #define TARGET_INIT_LIBFUNCS cris_init_libfuncs
 
+#undef TARGET_LRA_P
+#define TARGET_LRA_P hook_bool_void_false
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P cris_legitimate_address_p
+
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P cris_legitimate_constant_p
+
+#undef TARGET_PREFERRED_RELOAD_CLASS
+#define TARGET_PREFERRED_RELOAD_CLASS cris_preferred_reload_class
+
 #undef TARGET_REGISTER_MOVE_COST
 #define TARGET_REGISTER_MOVE_COST cris_register_move_cost
 #undef TARGET_MEMORY_MOVE_COST
@@ -214,6 +243,9 @@
 #undef TARGET_PROMOTE_FUNCTION_MODE
 #define TARGET_PROMOTE_FUNCTION_MODE cris_promote_function_mode
 
+#undef TARGET_ATOMIC_ALIGN_FOR_MODE
+#define TARGET_ATOMIC_ALIGN_FOR_MODE cris_atomic_align_for_mode
+
 #undef TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX cris_struct_value_rtx
 #undef TARGET_SETUP_INCOMING_VARARGS
@@ -228,19 +260,17 @@
 #define TARGET_FUNCTION_INCOMING_ARG cris_function_incoming_arg
 #undef TARGET_FUNCTION_ARG_ADVANCE
 #define TARGET_FUNCTION_ARG_ADVANCE cris_function_arg_advance
-#undef TARGET_MD_ASM_CLOBBERS
-#define TARGET_MD_ASM_CLOBBERS cris_md_asm_clobbers
-#undef TARGET_DEFAULT_TARGET_FLAGS
-#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | CRIS_SUBTARGET_DEFAULT)
-#undef TARGET_HANDLE_OPTION
-#define TARGET_HANDLE_OPTION cris_handle_option
+#undef TARGET_MD_ASM_ADJUST
+#define TARGET_MD_ASM_ADJUST cris_md_asm_adjust
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM cris_cannot_force_const_mem
+
 #undef TARGET_FRAME_POINTER_REQUIRED
 #define TARGET_FRAME_POINTER_REQUIRED cris_frame_pointer_required
 
 #undef TARGET_OPTION_OVERRIDE
 #define TARGET_OPTION_OVERRIDE cris_option_override
-#undef TARGET_OPTION_OPTIMIZATION_TABLE
-#define TARGET_OPTION_OPTIMIZATION_TABLE cris_option_optimization_table
 
 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
 #define TARGET_ASM_TRAMPOLINE_TEMPLATE cris_asm_trampoline_template
@@ -251,6 +281,18 @@
 #define TARGET_FUNCTION_VALUE cris_function_value
 #undef TARGET_LIBCALL_VALUE
 #define TARGET_LIBCALL_VALUE cris_libcall_value
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P cris_function_value_regno_p
+
+#undef TARGET_HARD_REGNO_NREGS
+#define TARGET_HARD_REGNO_NREGS cris_hard_regno_nregs
+#undef TARGET_HARD_REGNO_MODE_OK
+#define TARGET_HARD_REGNO_MODE_OK cris_hard_regno_mode_ok
+
+#undef TARGET_STATIC_RTX_ALIGNMENT
+#define TARGET_STATIC_RTX_ALIGNMENT cris_static_rtx_alignment
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT cris_constant_alignment
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
@@ -492,6 +534,21 @@
   return crtl->uses_pic_offset_table;
 }
 
+/* Worker function for TARGET_CANNOT_FORCE_CONST_MEM.
+   We can't put PIC addresses in the constant pool, not even the ones that
+   can be reached as pc-relative as we can't tell when or how to do that.  */
+
+static bool
+cris_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
+{
+  enum cris_symbol_type t = cris_symbol_type_of (x);
+
+  return
+    t == cris_unspec
+    || t == cris_got_symbol
+    || t == cris_rel_symbol;
+}
+
 /* Given an rtx, return the text string corresponding to the CODE of X.
    Intended for use in the assembly language output section of a
    define_insn.  */
@@ -504,11 +561,9 @@
     {
     case PLUS:
       return "add";
-      break;
 
     case MINUS:
       return "sub";
-      break;
 
     case MULT:
       /* This function is for retrieving a part of an instruction name for
@@ -520,46 +575,36 @@
 
     case DIV:
       return "div";
-      break;
 
     case AND:
       return "and";
-      break;
 
     case IOR:
       return "or";
-      break;
 
     case XOR:
       return "xor";
-      break;
 
     case NOT:
       return "not";
-      break;
 
     case ASHIFT:
       return "lsl";
-      break;
 
     case LSHIFTRT:
       return "lsr";
-      break;
 
     case ASHIFTRT:
       return "asr";
-      break;
 
     case UMIN:
       /* Used to control the sign/zero-extend character for the 'E' modifier.
 	 BOUND has none.  */
       cris_output_insn_is_bound = 1;
       return "bound";
-      break;
 
     default:
       return "Unknown operator";
-      break;
   }
 }
 
@@ -587,7 +632,7 @@
 
   if (REG_P (index))
     fprintf (file, "$%s.b", reg_names[REGNO (index)]);
-  else if (CONSTANT_P (index))
+  else if (CRIS_CONSTANT_P (index))
     cris_output_addr_const (file, index);
   else if (GET_CODE (index) == MULT)
     {
@@ -703,8 +748,7 @@
     case 'b':
       /* 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 (!CONST_INT_P (x)
-	  || !CRIS_CONST_OK_FOR_LETTER_P (INTVAL (x), 'O'))
+      if (!satisfies_constraint_O (x))
 	LOSE_AND_RETURN ("invalid operand for 'b' modifier", x);
       fprintf (file, HOST_WIDE_INT_PRINT_DEC,
 	       INTVAL (x)| (INTVAL (x) <= 255 ? ~255 : ~65535));
@@ -767,7 +811,7 @@
 		return;
 	      }
 	  }
-	output_address (addr);
+	output_address (VOIDmode, addr);
       }
       return;
 
@@ -906,7 +950,7 @@
 	      adj_mem
 		= adjust_address (adj_mem, GET_MODE (adj_mem), size / 2);
 
-	    output_address (XEXP (adj_mem, 0));
+	    output_address (VOIDmode, XEXP (adj_mem, 0));
 	    return;
 	  }
 
@@ -977,11 +1021,58 @@
       fprintf (file, INTVAL (operand) < 0 ? "adds.w" : "addq");
       return;
 
+    case 'P':
+      /* For const_int operands, print the additive mnemonic and the
+	 modified operand (byte-sized operands don't save anything):
+          N=MIN_INT..-65536: add.d N
+          -65535..-64: subu.w -N
+          -63..-1: subq -N
+          0..63: addq N
+          64..65535: addu.w N
+          65536..MAX_INT: add.d N.
+	 (Emitted mnemonics are capitalized to simplify testing.)
+	 For anything else (N.B: only register is valid), print "add.d".  */
+      if (REG_P (operand))
+	{
+	  fprintf (file, "Add.d ");
+
+	  /* Deal with printing the operand by dropping through to the
+	     normal path.  */
+	  break;
+	}
+      else
+	{
+	  int val;
+	  gcc_assert (CONST_INT_P (operand));
+
+	  val = INTVAL (operand);
+	  if (!IN_RANGE (val, -65535, 65535))
+	      fprintf (file, "Add.d %d", val);
+	  else if (val <= -64)
+	    fprintf (file, "Subu.w %d", -val);
+	  else if (val <= -1)
+	    fprintf (file, "Subq %d", -val);
+	  else if (val <= 63)
+	      fprintf (file, "Addq %d", val);
+	  else if (val <= 65535)
+	    fprintf (file, "Addu.w %d", val);
+	  return;
+	}
+      break;
+
+    case 'q':
+      /* If the operand is an integer -31..31, print "q" else ".d".  */
+      if (CONST_INT_P (operand) && IN_RANGE (INTVAL (operand), -31, 31))
+	fprintf (file, "q");
+      else
+	fprintf (file, ".d");
+      return;
+
     case 'd':
       /* If this is a GOT symbol, force it to be emitted as :GOT and
 	 :GOTPLT regardless of -fpic (i.e. not as :GOT16, :GOTPLT16).
 	 Avoid making this too much of a special case.  */
-      if (flag_pic == 1 && CONSTANT_P (operand))
+      if (flag_pic == 1 && CRIS_CONSTANT_P (operand))
 	{
 	  int flag_pic_save = flag_pic;
 
@@ -1046,7 +1137,7 @@
       return;
 
     case MEM:
-      output_address (XEXP (operand, 0));
+      output_address (GET_MODE (operand), XEXP (operand, 0));
       return;
 
     case CONST_DOUBLE:
@@ -1056,14 +1147,11 @@
       else
 	{
 	  /* Only single precision is allowed as plain operands the
-	     moment.  FIXME:  REAL_VALUE_FROM_CONST_DOUBLE isn't
-	     documented.  */
-	  REAL_VALUE_TYPE r;
+	     moment.  */
 	  long l;
 
 	  /* FIXME:  Perhaps check overflow of the "single".  */
-	  REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
-	  REAL_VALUE_TO_TARGET_SINGLE (r, l);
+	  REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (operand), l);
 
 	  fprintf (file, "0x%lx", l);
 	}
@@ -1101,7 +1189,7 @@
     default:
       /* No need to handle all strange variants, let output_addr_const
 	 do it for us.  */
-      if (CONSTANT_P (operand))
+      if (CRIS_CONSTANT_P (operand))
 	{
 	  cris_output_addr_const (file, operand);
 	  return;
@@ -1120,14 +1208,14 @@
 /* The PRINT_OPERAND_ADDRESS worker.  */
 
 static void
-cris_print_operand_address (FILE *file, rtx x)
+cris_print_operand_address (FILE *file, machine_mode /*mode*/, rtx x)
 {
   /* All these were inside MEM:s so output indirection characters.  */
   putc ('[', file);
 
   if (CONSTANT_ADDRESS_P (x))
     cris_output_addr_const (file, x);
-  else if (BASE_OR_AUTOINCR_P (x))
+  else if (cris_base_or_autoincr_p (x, true))
     cris_print_base (x, file);
   else if (GET_CODE (x) == PLUS)
     {
@@ -1135,12 +1223,12 @@
 
       x1 = XEXP (x, 0);
       x2 = XEXP (x, 1);
-      if (BASE_P (x1))
+      if (cris_base_p (x1, true))
 	{
 	  cris_print_base (x1, file);
 	  cris_print_index (x2, file);
 	}
-      else if (BASE_P (x2))
+      else if (cris_base_p (x2, true))
 	{
 	  cris_print_base (x2, file);
 	  cris_print_index (x1, file);
@@ -1178,7 +1266,7 @@
      present).  Apparently we can't eliminate from the frame-pointer in
      that direction, so use the incoming args (maybe pretended) pointer.  */
   return count == 0
-    ? gen_rtx_MEM (Pmode, plus_constant (virtual_incoming_args_rtx, -4))
+    ? gen_rtx_MEM (Pmode, plus_constant (Pmode, virtual_incoming_args_rtx, -4))
     : NULL_RTX;
 }
 
@@ -1202,8 +1290,7 @@
     : cris_return_address_on_stack ();
 }
 
-/* This used to be the INITIAL_FRAME_POINTER_OFFSET worker; now only
-   handles FP -> SP elimination offset.  */
+/* This handles FP -> SP elimination offset.  */
 
 static int
 cris_initial_frame_pointer_offset (void)
@@ -1219,7 +1306,7 @@
       push_topmost_sequence ();
       got_really_used
 	= reg_used_between_p (pic_offset_table_rtx, get_insns (),
-			      NULL_RTX);
+			      NULL);
       pop_topmost_sequence ();
     }
 
@@ -1277,11 +1364,164 @@
   gcc_unreachable ();
 }
 
+/* Nonzero if X is a hard reg that can be used as an index.  */
+static inline bool
+reg_ok_for_base_p (const_rtx x, bool strict)
+{
+  return ((! strict && ! HARD_REGISTER_P (x))
+          || REGNO_OK_FOR_BASE_P (REGNO (x)));
+}
+
+/* Nonzero if X is a hard reg that can be used as an index.  */
+static inline bool
+reg_ok_for_index_p (const_rtx x, bool strict)
+{
+  return reg_ok_for_base_p (x, strict);
+}
+
+/* No symbol can be used as an index (or more correct, as a base) together
+   with a register with PIC; the PIC register must be there.  */
+
+bool
+cris_constant_index_p (const_rtx x)
+{
+  return (CRIS_CONSTANT_P (x) && (!flag_pic || cris_valid_pic_const (x, true)));
+}
+
+/* True if X is a valid base register.  */
+
+bool
+cris_base_p (const_rtx x, bool strict)
+{
+  return (REG_P (x) && reg_ok_for_base_p (x, strict));
+}
+
+/* True if X is a valid index register.  */
+
+static inline bool
+cris_index_p (const_rtx x, bool strict)
+{
+  return (REG_P (x) && reg_ok_for_index_p (x, strict));
+}
+
+/* True if X is a valid base register with or without autoincrement.  */
+
+bool
+cris_base_or_autoincr_p (const_rtx x, bool strict)
+{
+  return (cris_base_p (x, strict)
+	  || (GET_CODE (x) == POST_INC
+	      && cris_base_p (XEXP (x, 0), strict)
+	      && REGNO (XEXP (x, 0)) != CRIS_ACR_REGNUM));
+}
+
+/* True if X is a valid (register) index for BDAP, i.e. [Rs].S or [Rs+].S.  */
+
+bool
+cris_bdap_index_p (const_rtx x, bool strict)
+{
+  return ((MEM_P (x)
+	   && GET_MODE (x) == SImode
+	   && cris_base_or_autoincr_p (XEXP (x, 0), strict))
+	  || (GET_CODE (x) == SIGN_EXTEND
+	      && MEM_P (XEXP (x, 0))
+	      && (GET_MODE (XEXP (x, 0)) == HImode
+		  || GET_MODE (XEXP (x, 0)) == QImode)
+	      && cris_base_or_autoincr_p (XEXP (XEXP (x, 0), 0), strict)));
+}
+
+/* True if X is a valid (register) index for BIAP, i.e. Rd.m.  */
+
+bool
+cris_biap_index_p (const_rtx x, bool strict)
+{
+  return (cris_index_p (x, strict)
+	  || (GET_CODE (x) == MULT
+	      && cris_index_p (XEXP (x, 0), strict)
+	      && cris_scale_int_operand (XEXP (x, 1), VOIDmode)));
+}
+
+/* Worker function for TARGET_LEGITIMATE_ADDRESS_P.
+
+   A PIC operand looks like a normal symbol here.  At output we dress it
+   in "[rPIC+symbol:GOT]" (global symbol) or "rPIC+symbol:GOTOFF" (local
+   symbol) so we exclude all addressing modes where we can't replace a
+   plain "symbol" with that.  A global PIC symbol does not fit anywhere
+   here (but is thankfully a general_operand in itself).  A local PIC
+   symbol is valid for the plain "symbol + offset" case.  */
+
+bool
+cris_legitimate_address_p (machine_mode mode, rtx x, bool strict)
+{
+  const_rtx x1, x2;
+
+  if (cris_base_or_autoincr_p (x, strict))
+    return true;
+  else if (TARGET_V32)
+    /* Nothing else is valid then.  */
+    return false;
+  else if (cris_constant_index_p (x))
+    return true;
+  /* Indexed?  */
+  else if (GET_CODE (x) == PLUS)
+    {
+      x1 = XEXP (x, 0);
+      x2 = XEXP (x, 1);
+      /* BDAP o, Rd.  */
+      if ((cris_base_p (x1, strict) && cris_constant_index_p (x2))
+	  || (cris_base_p (x2, strict) && cris_constant_index_p (x1))
+	   /* BDAP Rs[+], Rd.  */
+	  || (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+	      && ((cris_base_p (x1, strict)
+		   && cris_bdap_index_p (x2, strict))
+		  || (cris_base_p (x2, strict)
+		      && cris_bdap_index_p (x1, strict))
+		  /* BIAP.m Rs, Rd */
+		  || (cris_base_p (x1, strict)
+		      && cris_biap_index_p (x2, strict))
+		  || (cris_base_p (x2, strict)
+		      && cris_biap_index_p (x1, strict)))))
+	return true;
+     }
+  else if (MEM_P (x))
+    {
+      /* DIP (Rs).  Reject [[reg+]] and [[reg]] for DImode (long long).  */
+      if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+	  && cris_base_or_autoincr_p (XEXP (x, 0), strict))
+	return true;
+    }
+
+  return false;
+}
+
+/* Worker function for TARGET_LEGITIMATE_CONSTANT_P.  We have to handle
+   PIC constants that aren't legitimized.  FIXME: there used to be a
+   guarantee that the target LEGITIMATE_CONSTANT_P didn't have to handle
+   PIC constants, but no more (4.7 era); testcase: glibc init-first.c.
+   While that may be seen as a bug, that guarantee seems a wart by design,
+   so don't bother; fix the documentation instead.  */
+
+bool
+cris_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
+{
+  enum cris_symbol_type t;
+
+  if (flag_pic)
+    return LEGITIMATE_PIC_OPERAND_P (x);
+
+  t = cris_symbol_type_of (x);
+
+  return
+    t == cris_no_symbol
+    || t == cris_offsettable_symbol
+    || t == cris_unspec;
+}
+
 /* Worker function for LEGITIMIZE_RELOAD_ADDRESS.  */
 
 bool
 cris_reload_address_legitimized (rtx x,
-				 enum machine_mode mode ATTRIBUTE_UNUSED,
+				 machine_mode mode ATTRIBUTE_UNUSED,
 				 int opnum ATTRIBUTE_UNUSED,
 				 int itype,
 				 int ind_levels ATTRIBUTE_UNUSED)
@@ -1352,30 +1592,43 @@
   return false;
 }
 
+
+/* Worker function for TARGET_PREFERRED_RELOAD_CLASS.
+
+   It seems like gcc (2.7.2 and 2.9x of 2000-03-22) may send "NO_REGS" as
+   the class for a constant (testcase: __Mul in arit.c).  To avoid forcing
+   out a constant into the constant pool, we will trap this case and
+   return something a bit more sane.  FIXME: Check if this is a bug.
+   Beware that we must not "override" classes that can be specified as
+   constraint letters, or else asm operands using them will fail when
+   they need to be reloaded.  FIXME: Investigate whether that constitutes
+   a bug.  */
+
+static reg_class_t
+cris_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, reg_class_t rclass)
+{
+  if (rclass != ACR_REGS
+      && rclass != MOF_REGS
+      && rclass != MOF_SRP_REGS
+      && rclass != SRP_REGS
+      && rclass != CC0_REGS
+      && rclass != SPECIAL_REGS)
+    return GENNONACR_REGS;
+
+  return rclass;
+}
+
 /* Worker function for TARGET_REGISTER_MOVE_COST.  */
 
 static int
-cris_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+cris_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
 			 reg_class_t from, reg_class_t to)
 {
-  if (!TARGET_V32)
-    {
-      /* Pretend that classes that we don't support are ALL_REGS, so
-	 we give them the highest cost.  */
-      if (from != SPECIAL_REGS && from != MOF_REGS
-	  && from != GENERAL_REGS && from != GENNONACR_REGS)
-	from = ALL_REGS;
-
-      if (to != SPECIAL_REGS && to != MOF_REGS
-	  && to != GENERAL_REGS && to != GENNONACR_REGS)
-	to = ALL_REGS;
-    }
-
   /* Can't move to and from a SPECIAL_REGS register, so we have to say
      their move cost within that class is higher.  How about 7?  That's 3
      for a move to a GENERAL_REGS register, 3 for the move from the
      GENERAL_REGS register, and 1 for the increased register pressure.
-     Also, it's higher than the memory move cost, which is in order.  
+     Also, it's higher than the memory move cost, as it should.
      We also do this for ALL_REGS, since we don't want that class to be
      preferred (even to memory) at all where GENERAL_REGS doesn't fit.
      Whenever it's about to be used, it's for SPECIAL_REGS.  If we don't
@@ -1384,13 +1637,15 @@
      GENERAL_REGS left to allocate.  This is because the fall-back when
      the most preferred register class isn't available, isn't the next
      (or next good) wider register class, but the *most widest* register
-     class.  */
+     class.  FIXME: pre-IRA comment, perhaps obsolete now.  */
 
   if ((reg_classes_intersect_p (from, SPECIAL_REGS)
        && reg_classes_intersect_p (to, SPECIAL_REGS))
       || from == ALL_REGS || to == ALL_REGS)
     return 7;
 
+  /* Make moves to/from SPECIAL_REGS slightly more expensive, as we
+     generally prefer GENERAL_REGS.  */
   if (reg_classes_intersect_p (from, SPECIAL_REGS)
       || reg_classes_intersect_p (to, SPECIAL_REGS))
     return 3;
@@ -1404,7 +1659,7 @@
    suffice.  */
 
 static int
-cris_memory_move_cost (enum machine_mode mode,
+cris_memory_move_cost (machine_mode mode,
                        reg_class_t rclass ATTRIBUTE_UNUSED,
                        bool in ATTRIBUTE_UNUSED)
 {
@@ -1548,9 +1803,8 @@
 		       && (REGNO (SET_SRC (exp))
 			   > CRIS_LAST_GENERAL_REGISTER))
 		   || (TARGET_V32
-		       && GET_CODE (SET_SRC (exp)) == CONST_INT
-		       && CRIS_CONST_OK_FOR_LETTER_P (INTVAL (SET_SRC (exp)),
-						      'I')))
+		       && REG_P (SET_DEST (exp))
+		       && satisfies_constraint_I (SET_SRC (exp))))
 	    {
 	      /* There's no CC0 change for this case.  Just check
 		 for overlap.  */
@@ -1671,7 +1925,7 @@
     check-cc-attribute methods.  */
 
 void
-cris_notice_update_cc (rtx exp, rtx insn)
+cris_notice_update_cc (rtx exp, rtx_insn *insn)
 {
   enum attr_cc attrval = get_attr_cc (insn);
 
@@ -1764,7 +2018,7 @@
     {
       push_topmost_sequence ();
       got_really_used
-	= reg_used_between_p (pic_offset_table_rtx, get_insns (), NULL_RTX);
+	= reg_used_between_p (pic_offset_table_rtx, get_insns (), NULL);
       pop_topmost_sequence ();
     }
 
@@ -1776,6 +2030,37 @@
   return true;
 }
 
+/* Emit checking that MEM is aligned for an access in MODE, failing
+   that, executing a "break 8" (or call to abort, if "break 8" is
+   disabled).  */
+
+void
+cris_emit_trap_for_misalignment (rtx mem)
+{
+  rtx addr, reg, ok_label, andop;
+  rtx_insn *jmp;
+  int natural_alignment;
+  gcc_assert (MEM_P (mem));
+
+  natural_alignment = GET_MODE_SIZE (GET_MODE (mem));
+  addr = XEXP (mem, 0);
+  reg = force_reg (Pmode, addr);
+  ok_label = gen_label_rtx ();
+
+  /* This will yield a btstq without a separate register used, usually -
+     with the exception for PRE hoisting the "and" but not the branch
+     around the trap: see testsuite/gcc.target/cris/sync-3s.c.  */
+  andop = gen_rtx_AND (Pmode, reg, GEN_INT (natural_alignment - 1));
+  emit_cmp_and_jump_insns (force_reg (SImode, andop), const0_rtx, EQ,
+			   NULL_RTX, Pmode, 1, ok_label);
+  jmp = get_last_insn ();
+  gcc_assert (JUMP_P (jmp));
+
+  predict_insn_def (jmp, PRED_NORETURN, TAKEN);
+  expand_builtin_trap ();
+  emit_label (ok_label);
+}
+
 /* Expand a return insn (just one insn) marked as using SRP or stack
    slot depending on parameter ON_STACK.  */
 
@@ -1788,7 +2073,7 @@
      we do that until they're fixed.  Currently, all return insns in a
      function must be the same (not really a limiting factor) so we need
      to check that it doesn't change half-way through.  */
-  emit_jump_insn (gen_rtx_RETURN (VOIDmode));
+  emit_jump_insn (ret_rtx);
 
   CRIS_ASSERT (cfun->machine->return_type != CRIS_RETINSN_RET || !on_stack);
   CRIS_ASSERT (cfun->machine->return_type != CRIS_RETINSN_JUMP || on_stack);
@@ -1802,9 +2087,11 @@
    scanned.  In either case, *TOTAL contains the cost result.  */
 
 static bool
-cris_rtx_costs (rtx x, int code, int outer_code, int *total,
-		bool speed)
+cris_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno,
+		int *total, bool speed)
 {
+  int code = GET_CODE (x);
+
   switch (code)
     {
     case CONST_INT:
@@ -1834,7 +2121,7 @@
       return true;
 
     case CONST_DOUBLE:
-      if (x != CONST0_RTX (GET_MODE (x) == VOIDmode ? DImode : GET_MODE (x)))
+      if (x != CONST0_RTX (mode == VOIDmode ? DImode : mode))
 	*total = 12;
       else
         /* Make 0.0 cheap, else test-insns will not be used.  */
@@ -1851,7 +2138,7 @@
 
 	 FIXME: this case is a stop-gap for 4.3 and 4.4, this whole
 	 function should be rewritten.  */
-      if (outer_code == PLUS && BIAP_INDEX_P (x))
+      if (outer_code == PLUS && cris_biap_index_p (x, false))
 	{
 	  *total = 0;
 	  return true;
@@ -1893,11 +2180,12 @@
       if (CONST_INT_P (XEXP (x, 1))
           /* Two constants may actually happen before optimization.  */
           && !CONST_INT_P (XEXP (x, 0))
-          && !CRIS_CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'I'))
+	  && !satisfies_constraint_I (XEXP (x, 1)))
 	{
 	  *total
-	    = (rtx_cost (XEXP (x, 0), (enum rtx_code) outer_code, speed) + 2
-	       + 2 * GET_MODE_NUNITS (GET_MODE (XEXP (x, 0))));
+	    = (rtx_cost (XEXP (x, 0), mode, (enum rtx_code) outer_code,
+			 opno, speed) + 2
+	       + 2 * GET_MODE_NUNITS (mode));
 	  return true;
 	}
       return false;
@@ -1908,7 +2196,8 @@
       /* fall through */
 
     case ZERO_EXTEND: case SIGN_EXTEND:
-      *total = rtx_cost (XEXP (x, 0), (enum rtx_code) outer_code, speed);
+      *total = rtx_cost (XEXP (x, 0), VOIDmode, (enum rtx_code) outer_code,
+			 opno, speed);
       return true;
 
     default:
@@ -1919,7 +2208,9 @@
 /* The ADDRESS_COST worker.  */
 
 static int
-cris_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
+cris_address_cost (rtx x, machine_mode mode ATTRIBUTE_UNUSED,
+		   addr_space_t as ATTRIBUTE_UNUSED,
+		   bool speed ATTRIBUTE_UNUSED)
 {
   /* The metric to use for the cost-macros is unclear.
      The metric used here is (the number of cycles needed) / 2,
@@ -1932,7 +2223,7 @@
      loop there, without apparent reason.  */
 
   /* The cheapest addressing modes get 0, since nothing extra is needed.  */
-  if (BASE_OR_AUTOINCR_P (x))
+  if (cris_base_or_autoincr_p (x, false))
     return 0;
 
   /* An indirect mem must be a DIP.  This means two bytes extra for code,
@@ -1962,7 +2253,7 @@
       /* A BIAP is 2 extra bytes for the prefix insn, nothing more.  We
 	 recognize the typical MULT which is always in tem1 because of
 	 insn canonicalization.  */
-      if ((GET_CODE (tem1) == MULT && BIAP_INDEX_P (tem1))
+      if ((GET_CODE (tem1) == MULT && cris_biap_index_p (tem1, false))
 	  || REG_P (tem2))
 	return 2 / 2;
 
@@ -1973,12 +2264,11 @@
 
       /* A BDAP -32768 .. 32767 is like BDAP quick, but with 2 extra
 	 bytes.  */
-      if (CONST_INT_P (tem2)
-	  && CRIS_CONST_OK_FOR_LETTER_P (INTVAL (tem2), 'L'))
+      if (satisfies_constraint_L (tem2))
 	return (2 + 2) / 2;
 
       /* A BDAP with some other constant is 2 bytes extra.  */
-      if (CONSTANT_P (tem2))
+      if (CRIS_CONSTANT_P (tem2))
 	return (2 + 2 + 2) / 2;
 
       /* BDAP with something indirect should have a higher cost than
@@ -2020,12 +2310,12 @@
   /* The operands may be swapped.  Canonicalize them in reg_rtx and
      val_rtx, where reg_rtx always is a reg (for this constraint to
      match).  */
-  if (! BASE_P (reg_rtx))
+  if (! cris_base_p (reg_rtx, reload_in_progress || reload_completed))
     reg_rtx = val_rtx, val_rtx = ops[rreg];
 
   /* Don't forget to check that reg_rtx really is a reg.  If it isn't,
      we have no business.  */
-  if (! BASE_P (reg_rtx))
+  if (! cris_base_p (reg_rtx, reload_in_progress || reload_completed))
     return 0;
 
   /* Don't do this when -mno-split.  */
@@ -2050,8 +2340,9 @@
       /* Check if the lvalue register is the same as the "other
 	 operand".  If so, the result is undefined and we shouldn't do
 	 this.  FIXME:  Check again.  */
-      if ((BASE_P (ops[lreg])
-	   && BASE_P (ops[other_op])
+      if ((cris_base_p (ops[lreg], reload_in_progress || reload_completed)
+	   && cris_base_p (ops[other_op],
+			   reload_in_progress || reload_completed)
 	   && REGNO (ops[lreg]) == REGNO (ops[other_op]))
 	  || rtx_equal_p (ops[other_op], ops[lreg]))
       return 0;
@@ -2064,7 +2355,7 @@
     return 0;
 
   if (code == PLUS
-      && ! BASE_P (val_rtx))
+      && ! cris_base_p (val_rtx, reload_in_progress || reload_completed))
     {
 
       /* Do not allow rx = rx + n if a normal add or sub with same size
@@ -2075,22 +2366,27 @@
 	return 0;
 
       /* Check allowed cases, like [r(+)?].[bwd] and const.  */
-      if (CONSTANT_P (val_rtx))
+      if (CRIS_CONSTANT_P (val_rtx))
 	return 1;
 
-      if (MEM_P (val_rtx) && BASE_OR_AUTOINCR_P (XEXP (val_rtx, 0)))
+      if (MEM_P (val_rtx)
+	  && cris_base_or_autoincr_p (XEXP (val_rtx, 0),
+				      reload_in_progress || reload_completed))
 	return 1;
 
       if (GET_CODE (val_rtx) == SIGN_EXTEND
 	  && MEM_P (XEXP (val_rtx, 0))
-	  && BASE_OR_AUTOINCR_P (XEXP (XEXP (val_rtx, 0), 0)))
+	  && cris_base_or_autoincr_p (XEXP (XEXP (val_rtx, 0), 0),
+				      reload_in_progress || reload_completed))
 	return 1;
 
       /* If we got here, it's not a valid addressing mode.  */
       return 0;
     }
   else if (code == MULT
-	   || (code == PLUS && BASE_P (val_rtx)))
+	   || (code == PLUS
+	       && cris_base_p (val_rtx,
+			       reload_in_progress || reload_completed)))
     {
       /* Do not allow rx = rx + ry.S, since it doesn't give better code.  */
       if (rtx_equal_p (ops[lreg], reg_rtx)
@@ -2102,7 +2398,7 @@
 	return 0;
 
       /* Only allow  r + ...  */
-      if (! BASE_P (reg_rtx))
+      if (! cris_base_p (reg_rtx, reload_in_progress || reload_completed))
 	return 0;
 
       /* If we got here, all seems ok.
@@ -2118,9 +2414,9 @@
    insn for other reasons.  */
 
 bool
-cris_cc0_user_requires_cmp (rtx insn)
+cris_cc0_user_requires_cmp (rtx_insn *insn)
 {
-  rtx cc0_user = NULL;
+  rtx_insn *cc0_user = NULL;
   rtx body;
   rtx set;
 
@@ -2174,25 +2470,12 @@
   return reg_overlap_mentioned_p (x, in);
 }
 
-/* The TARGET_ASM_NAMED_SECTION worker.
-   We just dispatch to the functions for ELF and a.out.  */
-
-void
-cris_target_asm_named_section (const char *name, unsigned int flags,
-			       tree decl)
-{
-  if (! TARGET_ELF)
-    default_no_named_section (name, flags, decl);
-  else
-    default_elf_asm_named_section (name, flags, decl);
-}
-
 /* Return TRUE iff X is a CONST valid for e.g. indexing.
    ANY_OPERAND is 0 if X is in a CALL_P insn or movsi, 1
    elsewhere.  */
 
 bool
-cris_valid_pic_const (rtx x, bool any_operand)
+cris_valid_pic_const (const_rtx x, bool any_operand)
 {
   gcc_assert (flag_pic);
 
@@ -2235,36 +2518,38 @@
 	gcc_unreachable ();
       }
 
-  return cris_pic_symbol_type_of (x) == cris_no_symbol;
+  return cris_symbol_type_of (x) == cris_no_symbol;
 }
 
-/* Helper function to find the right PIC-type symbol to generate,
+/* Helper function to find the right symbol-type to generate,
    given the original (non-PIC) representation.  */
 
-enum cris_pic_symbol_type
-cris_pic_symbol_type_of (rtx x)
+enum cris_symbol_type
+cris_symbol_type_of (const_rtx x)
 {
   switch (GET_CODE (x))
     {
     case SYMBOL_REF:
-      return SYMBOL_REF_LOCAL_P (x)
-	? cris_rel_symbol : cris_got_symbol;
+      return flag_pic
+	? (SYMBOL_REF_LOCAL_P (x)
+	   ? cris_rel_symbol : cris_got_symbol)
+	: cris_offsettable_symbol;
 
     case LABEL_REF:
-      return cris_rel_symbol;
+      return flag_pic ? cris_rel_symbol : cris_offsettable_symbol;
 
     case CONST:
-      return cris_pic_symbol_type_of (XEXP (x, 0));
+      return cris_symbol_type_of (XEXP (x, 0));
 
     case PLUS:
     case MINUS:
       {
-	enum cris_pic_symbol_type t1 = cris_pic_symbol_type_of (XEXP (x, 0));
-	enum cris_pic_symbol_type t2 = cris_pic_symbol_type_of (XEXP (x, 1));
+	enum cris_symbol_type t1 = cris_symbol_type_of (XEXP (x, 0));
+	enum cris_symbol_type t2 = cris_symbol_type_of (XEXP (x, 1));
 
 	gcc_assert (t1 == cris_no_symbol || t2 == cris_no_symbol);
 
-	if (t1 == cris_got_symbol || t1 == cris_got_symbol)
+	if (t1 == cris_got_symbol || t2 == cris_got_symbol)
 	  return cris_got_symbol_needing_fixup;
 
 	return t1 != cris_no_symbol ? t1 : t2;
@@ -2275,9 +2560,7 @@
       return cris_no_symbol;
 
     case UNSPEC:
-      /* Likely an offsettability-test attempting to add a constant to
-	 a GOTREAD symbol, which can't be handled.  */
-      return cris_invalid_pic_symbol;
+      return cris_unspec;
 
     default:
       fatal_insn ("unrecognized supposed constant", x);
@@ -2295,20 +2578,42 @@
   return cris_valid_pic_const (x, true);
 }
 
+/* Queue an .ident string in the queue of top-level asm statements.
+   If the front-end is done, we must be being called from toplev.c.
+   In that case, do nothing.  */
+void 
+cris_asm_output_ident (const char *string)
+{
+  if (symtab->state != PARSING)
+    return;
+
+  default_asm_output_ident_directive (string);
+}
+
 /* The ASM_OUTPUT_CASE_END worker.  */
 
 void
-cris_asm_output_case_end (FILE *stream, int num, rtx table)
+cris_asm_output_case_end (FILE *stream, int num, rtx_insn *table)
 {
+  /* Step back, over the label for the table, to the actual casejump and
+     assert that we find only what's expected.  */
+  rtx_insn *whole_jump_insn = prev_nonnote_nondebug_insn (table);
+  gcc_assert (whole_jump_insn != NULL_RTX && LABEL_P (whole_jump_insn));
+  whole_jump_insn = prev_nonnote_nondebug_insn (whole_jump_insn);
+  gcc_assert (whole_jump_insn != NULL_RTX
+	      && (JUMP_P (whole_jump_insn)
+		  || (TARGET_V32 && INSN_P (whole_jump_insn)
+		      && GET_CODE (PATTERN (whole_jump_insn)) == SEQUENCE)));
+  /* Get the pattern of the casejump, so we can extract the default label.  */
+  rtx whole_jump_pat = PATTERN (whole_jump_insn);
+
   if (TARGET_V32)
     {
-      rtx whole_jump_insn = PATTERN (PREV_INSN (PREV_INSN (table)));
-
       /* This can be a SEQUENCE, meaning the delay-slot of the jump is
-	 filled.  */
+	 filled.  We also output the offset word a little differently.  */
       rtx parallel_jump
-	= (GET_CODE (whole_jump_insn) == SEQUENCE
-	   ? PATTERN (XVECEXP (whole_jump_insn, 0, 0)) : whole_jump_insn);
+	= (GET_CODE (whole_jump_pat) == SEQUENCE
+	   ? PATTERN (XVECEXP (whole_jump_pat, 0, 0)) : whole_jump_pat);
 
       asm_fprintf (stream,
 		   "\t.word %LL%d-.%s\n",
@@ -2323,74 +2628,12 @@
 	       "\t.word %LL%d-%LL%d%s\n",
 	       CODE_LABEL_NUMBER (XEXP
 				  (XEXP
-				   (XEXP
-				    (XVECEXP
-				     (PATTERN
-				      (PREV_INSN
-				       (PREV_INSN (table))), 0, 0), 1),
+				   (XEXP (XVECEXP (whole_jump_pat, 0, 0), 1),
 				    2), 0)),
 	       num,
 	       (TARGET_PDEBUG ? "; default" : ""));
 }
 
-/* TARGET_HANDLE_OPTION worker.  We just store the values into local
-   variables here.  Checks for correct semantics are in
-   cris_option_override.  */
-
-static bool
-cris_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
-		    int value ATTRIBUTE_UNUSED)
-{
-  switch (code)
-    {
-    case OPT_metrax100:
-      target_flags
-	|= (MASK_SVINTO
-	    + MASK_ETRAX4_ADD
-	    + MASK_ALIGN_BY_32);
-      break;
-
-    case OPT_mno_etrax100:
-      target_flags
-	&= ~(MASK_SVINTO
-	     + MASK_ETRAX4_ADD
-	     + MASK_ALIGN_BY_32);
-      break;
-
-    case OPT_m32_bit:
-    case OPT_m32bit:
-      target_flags
-	|= (MASK_STACK_ALIGN
-	    + MASK_CONST_ALIGN
-	    + MASK_DATA_ALIGN
-	    + MASK_ALIGN_BY_32);
-      break;
-
-    case OPT_m16_bit:
-    case OPT_m16bit:
-      target_flags
-	|= (MASK_STACK_ALIGN
-	    + MASK_CONST_ALIGN
-	    + MASK_DATA_ALIGN);
-      break;
-
-    case OPT_m8_bit:
-    case OPT_m8bit:
-      target_flags
-	&= ~(MASK_STACK_ALIGN
-	     + MASK_CONST_ALIGN
-	     + MASK_DATA_ALIGN);
-      break;
-
-    default:
-      break;
-    }
-
-  CRIS_SUBTARGET_HANDLE_OPTION(code, arg, value);
-
-  return true;
-}
-
 /* The TARGET_OPTION_OVERRIDE worker.
    As is the norm, this also parses -mfoo=bar type parameters.  */
 
@@ -2501,12 +2744,6 @@
       flag_no_function_cse = 1;
     }
 
-  if (write_symbols == DWARF2_DEBUG && ! TARGET_ELF)
-    {
-      warning (0, "that particular -g option is invalid with -maout and -melinux");
-      write_symbols = DBX_DEBUG;
-    }
-
   /* Set the per-function-data initializer.  */
   init_machine_status = cris_init_machine_status;
 }
@@ -2520,6 +2757,9 @@
 			  HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
 			  tree funcdecl)
 {
+  /* Make sure unwind info is emitted for the thunk if needed.  */
+  final_start_function (emit_barrier (), stream, 1);
+
   if (delta > 0)
     fprintf (stream, "\tadd%s " HOST_WIDE_INT_PRINT_DEC ",$%s\n",
 	     ADDITIVE_SIZE_MODIFIER (delta), delta,
@@ -2539,44 +2779,54 @@
 	{
 	  fprintf (stream, "\tba ");
 	  assemble_name (stream, name);
-	  fprintf (stream, "%s\n", CRIS_PLT_PCOFFSET_SUFFIX);
+	  fprintf (stream, "%s\n\tnop\n", CRIS_PLT_PCOFFSET_SUFFIX);
 	}
       else
 	{
-	  fprintf (stream, "add.d ");
+	  fprintf (stream, "\tadd.d ");
 	  assemble_name (stream, name);
 	  fprintf (stream, "%s,$pc\n", CRIS_PLT_PCOFFSET_SUFFIX);
 	}
     }
   else
     {
-      fprintf (stream, "jump ");
+      fprintf (stream, "\tjump ");
       assemble_name (stream, XSTR (XEXP (DECL_RTL (funcdecl), 0), 0));
       fprintf (stream, "\n");
 
       if (TARGET_V32)
 	fprintf (stream, "\tnop\n");
     }
+
+  final_end_function ();
 }
 
 /* Boilerplate emitted at start of file.
 
    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.
-
-   We want a .file directive only if TARGET_ELF.  */
+   for debugging purposes.  Make sure they are allowed then.  */
 static void
 cris_file_start (void)
 {
   /* These expressions can vary at run time, so we cannot put
      them into TARGET_INITIALIZER.  */
   targetm.asm_file_start_app_off = !(TARGET_PDEBUG || flag_print_asm_name);
-  targetm.asm_file_start_file_directive = TARGET_ELF;
 
   default_file_start ();
 }
 
+/* Output that goes at the end of the file, similarly.  */
+
+static void
+cris_file_end (void)
+{
+  /* For CRIS, the default is to assume *no* executable stack, so output
+     an executable-stack-note only when needed.  */
+  if (TARGET_LINUX && trampolines_created)
+    file_end_indicate_exec_stack ();
+}
+
 /* Rename the function calls for integer multiply and divide.  */
 static void
 cris_init_libfuncs (void)
@@ -2586,6 +2836,16 @@
   set_optab_libfunc (udiv_optab, SImode, "__Udiv");
   set_optab_libfunc (smod_optab, SImode, "__Mod");
   set_optab_libfunc (umod_optab, SImode, "__Umod");
+
+  /* Atomic data being unaligned is unfortunately a reality.
+     Deal with it.  */
+  if (TARGET_ATOMICS_MAY_CALL_LIBFUNCS)
+    {
+      set_optab_libfunc (sync_compare_and_swap_optab, SImode,
+			 "__cris_atcmpxchgr32");
+      set_optab_libfunc (sync_compare_and_swap_optab, HImode,
+			 "__cris_atcmpxchgr16");
+    }
 }
 
 /* The INIT_EXPANDERS worker sets the per-function-data initializer and
@@ -2602,7 +2862,7 @@
 static struct machine_function *
 cris_init_machine_status (void)
 {
-  return ggc_alloc_cleared_machine_function ();
+  return ggc_cleared_alloc<machine_function> ();
 }
 
 /* Split a 2 word move (DI or presumably DF) into component parts.
@@ -2611,7 +2871,7 @@
 rtx
 cris_split_movdx (rtx *operands)
 {
-  enum machine_mode mode = GET_MODE (operands[0]);
+  machine_mode mode = GET_MODE (operands[0]);
   rtx dest = operands[0];
   rtx src  = operands[1];
   rtx val;
@@ -2636,12 +2896,10 @@
 	  /* We normally copy the low-numbered register first.  However, if
 	     the first register operand 0 is the same as the second register of
 	     operand 1, we must copy in the opposite order.  */
-	  emit_insn (gen_rtx_SET (VOIDmode,
-				  operand_subword (dest, reverse, TRUE, mode),
+	  emit_insn (gen_rtx_SET (operand_subword (dest, reverse, TRUE, mode),
 				  operand_subword (src, reverse, TRUE, mode)));
 
-	  emit_insn (gen_rtx_SET (VOIDmode,
-				  operand_subword (dest, !reverse, TRUE, mode),
+	  emit_insn (gen_rtx_SET (operand_subword (dest, !reverse, TRUE, mode),
 				  operand_subword (src, !reverse, TRUE, mode)));
 	}
       /* Constant-to-reg copy.  */
@@ -2649,12 +2907,10 @@
 	{
 	  rtx words[2];
 	  split_double (src, &words[0], &words[1]);
-	  emit_insn (gen_rtx_SET (VOIDmode,
-				  operand_subword (dest, 0, TRUE, mode),
+	  emit_insn (gen_rtx_SET (operand_subword (dest, 0, TRUE, mode),
 				  words[0]));
 
-	  emit_insn (gen_rtx_SET (VOIDmode,
-				  operand_subword (dest, 1, TRUE, mode),
+	  emit_insn (gen_rtx_SET (operand_subword (dest, 1, TRUE, mode),
 				  words[1]));
 	}
       /* Mem-to-reg copy.  */
@@ -2663,8 +2919,7 @@
 	  /* If the high-address word is used in the address, we must load it
 	     last.  Otherwise, load it first.  */
 	  rtx addr = XEXP (src, 0);
-	  int reverse
-	    = (refers_to_regno_p (dregno, dregno + 1, addr, NULL) != 0);
+	  int reverse = (refers_to_regno_p (dregno, addr) != 0);
 
 	  /* The original code implies that we can't do
 	     move.x [rN+],rM  move.x [rN],rM+1
@@ -2684,8 +2939,7 @@
 		 manually.  */
 	      mem = change_address (src, SImode, addr);
 	      insn
-		= gen_rtx_SET (VOIDmode,
-			       operand_subword (dest, 0, TRUE, mode), mem);
+		= gen_rtx_SET (operand_subword (dest, 0, TRUE, mode), mem);
 	      insn = emit_insn (insn);
 	      if (GET_CODE (XEXP (mem, 0)) == POST_INC)
 		REG_NOTES (insn)
@@ -2694,8 +2948,7 @@
 
 	      mem = copy_rtx (mem);
 	      insn
-		= gen_rtx_SET (VOIDmode,
-			       operand_subword (dest, 1, TRUE, mode), mem);
+		= gen_rtx_SET (operand_subword (dest, 1, TRUE, mode), mem);
 	      insn = emit_insn (insn);
 	      if (GET_CODE (XEXP (mem, 0)) == POST_INC)
 		REG_NOTES (insn)
@@ -2712,18 +2965,16 @@
 		fatal_insn ("unexpected side-effects in address", addr);
 
 	      emit_insn (gen_rtx_SET
-			 (VOIDmode,
-			  operand_subword (dest, reverse, TRUE, mode),
+			 (operand_subword (dest, reverse, TRUE, mode),
 			  change_address
 			  (src, SImode,
-			   plus_constant (addr,
+			   plus_constant (Pmode, addr,
 					  reverse * UNITS_PER_WORD))));
 	      emit_insn (gen_rtx_SET
-			 (VOIDmode,
-			  operand_subword (dest, ! reverse, TRUE, mode),
+			 (operand_subword (dest, ! reverse, TRUE, mode),
 			  change_address
 			  (src, SImode,
-			   plus_constant (addr,
+			   plus_constant (Pmode, addr,
 					  (! reverse) *
 					  UNITS_PER_WORD))));
 	    }
@@ -2748,8 +2999,7 @@
 	     ourselves, we must add a post-inc note manually.  */
 	  mem = change_address (dest, SImode, addr);
 	  insn
-	    = gen_rtx_SET (VOIDmode,
-			   mem, operand_subword (src, 0, TRUE, mode));
+	    = gen_rtx_SET (mem, operand_subword (src, 0, TRUE, mode));
 	  insn = emit_insn (insn);
 	  if (GET_CODE (XEXP (mem, 0)) == POST_INC)
 	    REG_NOTES (insn)
@@ -2757,10 +3007,7 @@
 				 REG_NOTES (insn));
 
 	  mem = copy_rtx (mem);
-	  insn
-	    = gen_rtx_SET (VOIDmode,
-			   mem,
-			   operand_subword (src, 1, TRUE, mode));
+	  insn = gen_rtx_SET (mem, operand_subword (src, 1, TRUE, mode));
 	  insn = emit_insn (insn);
 	  if (GET_CODE (XEXP (mem, 0)) == POST_INC)
 	    REG_NOTES (insn)
@@ -2776,14 +3023,12 @@
 	    fatal_insn ("unexpected side-effects in address", addr);
 
 	  emit_insn (gen_rtx_SET
-		     (VOIDmode,
-		      change_address (dest, SImode, addr),
+		     (change_address (dest, SImode, addr),
 		      operand_subword (src, 0, TRUE, mode)));
 
 	  emit_insn (gen_rtx_SET
-		     (VOIDmode,
-		      change_address (dest, SImode,
-				      plus_constant (addr,
+		     (change_address (dest, SImode,
+				      plus_constant (Pmode, addr,
 						     UNITS_PER_WORD)),
 		      operand_subword (src, 1, TRUE, mode)));
 	}
@@ -2827,7 +3072,7 @@
 	 it's still used.  */
       push_topmost_sequence ();
       got_really_used
-	= reg_used_between_p (pic_offset_table_rtx, get_insns (), NULL_RTX);
+	= reg_used_between_p (pic_offset_table_rtx, get_insns (), NULL);
       pop_topmost_sequence ();
     }
 
@@ -2853,9 +3098,9 @@
 	   stdarg_regs > 0;
 	   regno--, pretend -= 4, stdarg_regs--)
 	{
-	  insn = emit_insn (gen_rtx_SET (VOIDmode,
-					 stack_pointer_rtx,
-					 plus_constant (stack_pointer_rtx,
+	  insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
+					 plus_constant (Pmode,
+							stack_pointer_rtx,
 							-4)));
 	  /* FIXME: When dwarf2 frame output and unless asynchronous
 	     exceptions, make dwarf2 bundle together all stack
@@ -2865,7 +3110,7 @@
 
 	  mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
 	  set_mem_alias_set (mem, get_varargs_alias_set ());
-	  insn = emit_move_insn (mem, gen_rtx_raw_REG (SImode, regno));
+	  insn = emit_move_insn (mem, gen_raw_REG (SImode, regno));
 
 	  /* Note the absence of RTX_FRAME_RELATED_P on the above insn:
 	     the value isn't restored, so we don't want to tell dwarf2
@@ -2881,16 +3126,15 @@
   /* Save SRP if not a leaf function.  */
   if (return_address_on_stack)
     {
-      insn = emit_insn (gen_rtx_SET (VOIDmode,
-				     stack_pointer_rtx,
-				     plus_constant (stack_pointer_rtx,
+      insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
+				     plus_constant (Pmode, stack_pointer_rtx,
 						    -4 - pretend)));
       pretend = 0;
       RTX_FRAME_RELATED_P (insn) = 1;
 
       mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
       set_mem_alias_set (mem, get_frame_alias_set ());
-      insn = emit_move_insn (mem, gen_rtx_raw_REG (SImode, CRIS_SRP_REGNUM));
+      insn = emit_move_insn (mem, gen_raw_REG (SImode, CRIS_SRP_REGNUM));
       RTX_FRAME_RELATED_P (insn) = 1;
       framesize += 4;
     }
@@ -2898,9 +3142,8 @@
   /* Set up the frame pointer, if needed.  */
   if (frame_pointer_needed)
     {
-      insn = emit_insn (gen_rtx_SET (VOIDmode,
-				     stack_pointer_rtx,
-				     plus_constant (stack_pointer_rtx,
+      insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
+				     plus_constant (Pmode, stack_pointer_rtx,
 						    -4 - pretend)));
       pretend = 0;
       RTX_FRAME_RELATED_P (insn) = 1;
@@ -2953,7 +3196,7 @@
 		    {
 		      mem
 			= gen_rtx_MEM (SImode,
-				       plus_constant (stack_pointer_rtx,
+				       plus_constant (Pmode, stack_pointer_rtx,
 						      -(n_saved * 4 + size)));
 		      set_mem_alias_set (mem, get_frame_alias_set ());
 		      insn
@@ -2964,9 +3207,8 @@
 		  else
 		    {
 		      insn
-			= gen_rtx_SET (VOIDmode,
-				       stack_pointer_rtx,
-				       plus_constant (stack_pointer_rtx,
+			= gen_rtx_SET (stack_pointer_rtx,
+				       plus_constant (Pmode, stack_pointer_rtx,
 						      -(n_saved * 4 + size)));
 		      insn = emit_insn (insn);
 		      RTX_FRAME_RELATED_P (insn) = 1;
@@ -2982,15 +3224,15 @@
 		  size = 0;
 		}
 
-	      insn = emit_insn (gen_rtx_SET (VOIDmode,
-					     stack_pointer_rtx,
-					     plus_constant (stack_pointer_rtx,
+	      insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
+					     plus_constant (Pmode,
+							    stack_pointer_rtx,
 							    -4 - size)));
 	      RTX_FRAME_RELATED_P (insn) = 1;
 
 	      mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
 	      set_mem_alias_set (mem, get_frame_alias_set ());
-	      insn = emit_move_insn (mem, gen_rtx_raw_REG (SImode, regno));
+	      insn = emit_move_insn (mem, gen_raw_REG (SImode, regno));
 	      RTX_FRAME_RELATED_P (insn) = 1;
 
 	      framesize += 4 + size;
@@ -3014,7 +3256,7 @@
 	{
 	  mem
 	    = gen_rtx_MEM (SImode,
-			   plus_constant (stack_pointer_rtx,
+			   plus_constant (Pmode, stack_pointer_rtx,
 					  -(n_saved * 4 + size)));
 	  set_mem_alias_set (mem, get_frame_alias_set ());
 	  insn = cris_emit_movem_store (mem, GEN_INT (n_saved),
@@ -3023,9 +3265,8 @@
       else
 	{
 	  insn
-	    = gen_rtx_SET (VOIDmode,
-			   stack_pointer_rtx,
-			   plus_constant (stack_pointer_rtx,
+	    = gen_rtx_SET (stack_pointer_rtx,
+			   plus_constant (Pmode, stack_pointer_rtx,
 					  -(n_saved * 4 + size)));
 	  insn = emit_insn (insn);
 	  RTX_FRAME_RELATED_P (insn) = 1;
@@ -3039,9 +3280,9 @@
       /* We have to put outgoing argument space after regs.  */
       if (cfoa_size)
 	{
-	  insn = emit_insn (gen_rtx_SET (VOIDmode,
-					 stack_pointer_rtx,
-					 plus_constant (stack_pointer_rtx,
+	  insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
+					 plus_constant (Pmode,
+							stack_pointer_rtx,
 							-cfoa_size)));
 	  RTX_FRAME_RELATED_P (insn) = 1;
 	  framesize += cfoa_size;
@@ -3049,9 +3290,9 @@
     }
   else if ((size + cfoa_size) > 0)
     {
-      insn = emit_insn (gen_rtx_SET (VOIDmode,
-				     stack_pointer_rtx,
-				     plus_constant (stack_pointer_rtx,
+      insn = emit_insn (gen_rtx_SET (stack_pointer_rtx,
+				     plus_constant (Pmode,
+						    stack_pointer_rtx,
 						    -(cfoa_size + size))));
       RTX_FRAME_RELATED_P (insn) = 1;
       framesize += size + cfoa_size;
@@ -3106,7 +3347,7 @@
 	 it's still used.  */
       push_topmost_sequence ();
       got_really_used
-	= reg_used_between_p (pic_offset_table_rtx, get_insns (), NULL_RTX);
+	= reg_used_between_p (pic_offset_table_rtx, get_insns (), NULL);
       pop_topmost_sequence ();
     }
 
@@ -3147,9 +3388,8 @@
 	  {
 	    /* There is an area for outgoing parameters located before
 	       the saved registers.  We have to adjust for that.  */
-	    emit_insn (gen_rtx_SET (VOIDmode,
-				    stack_pointer_rtx,
-				    plus_constant (stack_pointer_rtx,
+	    emit_insn (gen_rtx_SET (stack_pointer_rtx,
+				    plus_constant (Pmode, stack_pointer_rtx,
 						   argspace_offset)));
 	    /* Make sure we only do this once.  */
 	    argspace_offset = 0;
@@ -3158,7 +3398,7 @@
 	mem = gen_rtx_MEM (SImode, gen_rtx_POST_INC (SImode,
 						     stack_pointer_rtx));
 	set_mem_alias_set (mem, get_frame_alias_set ());
-	insn = emit_move_insn (gen_rtx_raw_REG (SImode, regno), mem);
+	insn = emit_move_insn (gen_raw_REG (SImode, regno), mem);
 
 	/* Whenever we emit insns with post-incremented addresses
 	   ourselves, we must add a post-inc note manually.  */
@@ -3173,9 +3413,8 @@
 
       if (argspace_offset)
 	{
-	  emit_insn (gen_rtx_SET (VOIDmode,
-				  stack_pointer_rtx,
-				  plus_constant (stack_pointer_rtx,
+	  emit_insn (gen_rtx_SET (stack_pointer_rtx,
+				  plus_constant (Pmode, stack_pointer_rtx,
 						 argspace_offset)));
 	  argspace_offset = 0;
 	}
@@ -3232,9 +3471,8 @@
 	 yet.  */
       size += argspace_offset;
 
-      emit_insn (gen_rtx_SET (VOIDmode,
-			      stack_pointer_rtx,
-			      plus_constant (stack_pointer_rtx, size)));
+      emit_insn (gen_rtx_SET (stack_pointer_rtx,
+			      plus_constant (Pmode, stack_pointer_rtx, size)));
     }
 
   /* If this function has no pushed register parameters
@@ -3246,7 +3484,7 @@
 	{
 	  rtx mem;
 	  rtx insn;
-	  rtx srpreg = gen_rtx_raw_REG (SImode, CRIS_SRP_REGNUM);
+	  rtx srpreg = gen_raw_REG (SImode, CRIS_SRP_REGNUM);
 	  mem = gen_rtx_MEM (SImode,
 			     gen_rtx_POST_INC (SImode,
 					       stack_pointer_rtx));
@@ -3261,8 +3499,7 @@
 	  if (crtl->calls_eh_return)
 	    emit_insn (gen_addsi3 (stack_pointer_rtx,
 				   stack_pointer_rtx,
-				   gen_rtx_raw_REG (SImode,
-						    CRIS_STACKADJ_REG)));
+				   gen_raw_REG (SImode, CRIS_STACKADJ_REG)));
 	  cris_expand_return (false);
 	}
       else
@@ -3279,7 +3516,7 @@
       if (return_address_on_stack)
 	{
 	  rtx mem;
-	  rtx srpreg = gen_rtx_raw_REG (SImode, CRIS_SRP_REGNUM);
+	  rtx srpreg = gen_raw_REG (SImode, CRIS_SRP_REGNUM);
 	  rtx insn;
 
 	  mem = gen_rtx_MEM (SImode,
@@ -3294,17 +3531,16 @@
 	    = alloc_EXPR_LIST (REG_INC, stack_pointer_rtx, REG_NOTES (insn));
 	}
 
-      emit_insn (gen_rtx_SET (VOIDmode,
-			      stack_pointer_rtx,
-			      plus_constant (stack_pointer_rtx, pretend)));
+      emit_insn (gen_rtx_SET (stack_pointer_rtx,
+			      plus_constant (Pmode, stack_pointer_rtx,
+					     pretend)));
     }
 
   /* Perform the "physical" unwinding that the EH machinery calculated.  */
   if (crtl->calls_eh_return)
     emit_insn (gen_addsi3 (stack_pointer_rtx,
 			   stack_pointer_rtx,
-			   gen_rtx_raw_REG (SImode,
-					    CRIS_STACKADJ_REG)));
+			   gen_raw_REG (SImode, CRIS_STACKADJ_REG)));
   cris_expand_return (false);
 }
 
@@ -3344,19 +3580,19 @@
   if (GET_CODE (XEXP (src, 0)) == POST_INC)
     {
       RTVEC_ELT (vec, nprefix + 1)
-	= gen_rtx_SET (VOIDmode, srcreg, plus_constant (srcreg, nregs * 4));
+	= gen_rtx_SET (srcreg, plus_constant (Pmode, srcreg, nregs * 4));
       eltno++;
     }
 
   src = replace_equiv_address (src, srcreg);
   RTVEC_ELT (vec, nprefix)
-    = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, regno), src);
+    = gen_rtx_SET (gen_rtx_REG (SImode, regno), src);
   regno += regno_inc;
 
   for (i = 1; i < nregs; i++, eltno++)
     {
       RTVEC_ELT (vec, nprefix + eltno)
-	= gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, regno),
+	= gen_rtx_SET (gen_rtx_REG (SImode, regno),
 		       adjust_address_nv (src, SImode, i * 4));
       regno += regno_inc;
     }
@@ -3399,7 +3635,7 @@
      registers so there's a three cycles penalty for use.  */
   if (nregs == 1)
     {
-      rtx mov = gen_rtx_SET (VOIDmode, dest, gen_rtx_REG (SImode, 0));
+      rtx mov = gen_rtx_SET (dest, gen_rtx_REG (SImode, 0));
 
       if (increment == 0)
 	{
@@ -3414,8 +3650,8 @@
       vec = rtvec_alloc (2);
 
       RTVEC_ELT (vec, 0) = mov;
-      RTVEC_ELT (vec, 1) = gen_rtx_SET (VOIDmode, destreg,
-					plus_constant (destreg, increment));
+      RTVEC_ELT (vec, 1) = gen_rtx_SET (destreg, plus_constant (Pmode, destreg,
+								increment));
       if (frame_related)
 	{
 	  RTX_FRAME_RELATED_P (mov) = 1;
@@ -3426,9 +3662,8 @@
     {
       vec = rtvec_alloc (nregs + (increment != 0 ? 1 : 0));
       RTVEC_ELT (vec, 0)
-	= gen_rtx_SET (VOIDmode,
-		       replace_equiv_address (dest,
-					      plus_constant (destreg,
+	= gen_rtx_SET (replace_equiv_address (dest,
+					      plus_constant (Pmode, destreg,
 							     increment)),
 		       gen_rtx_REG (SImode, regno));
       regno += regno_inc;
@@ -3442,10 +3677,9 @@
       if (increment != 0)
 	{
 	  RTVEC_ELT (vec, 1)
-	    = gen_rtx_SET (VOIDmode, destreg,
-			   plus_constant (destreg,
-					  increment != 0
-					  ? increment : nregs * 4));
+	    = gen_rtx_SET (destreg, plus_constant (Pmode, destreg,
+						   increment != 0
+						   ? increment : nregs * 4));
 	  eltno++;
 
 	  if (frame_related)
@@ -3460,7 +3694,7 @@
       for (i = 1; i < nregs; i++, eltno++)
 	{
 	  RTVEC_ELT (vec, eltno)
-	    = gen_rtx_SET (VOIDmode, adjust_address_nv (dest, SImode, i * 4),
+	    = gen_rtx_SET (adjust_address_nv (dest, SImode, i * 4),
 			   gen_rtx_REG (SImode, regno));
 	  if (frame_related)
 	    RTX_FRAME_RELATED_P (RTVEC_ELT (vec, eltno)) = 1;
@@ -3501,19 +3735,19 @@
 /* Worker function for expanding the address for PIC function calls.  */
 
 void
-cris_expand_pic_call_address (rtx *opp)
+cris_expand_pic_call_address (rtx *opp, rtx *markerp)
 {
   rtx op = *opp;
 
-  gcc_assert (MEM_P (op));
+  gcc_assert (flag_pic && MEM_P (op));
   op = XEXP (op, 0);
 
   /* It might be that code can be generated that jumps to 0 (or to a
      specific address).  Don't die on that.  (There is a
      testcase.)  */
-  if (CONSTANT_ADDRESS_P (op) && !CONST_INT_P (op))
+  if (CONSTANT_P (op) && !CONST_INT_P (op))
     {
-      enum cris_pic_symbol_type t = cris_pic_symbol_type_of (op);
+      enum cris_symbol_type t = cris_symbol_type_of (op);
 
       CRIS_ASSERT (can_create_pseudo_p ());
 
@@ -3539,18 +3773,21 @@
 	    }
 	  else
 	    op = force_reg (Pmode, op);
+
+	  /* A local call.  */
+	  *markerp = const0_rtx;
 	}
       else if (t == cris_got_symbol)
 	{
 	  if (TARGET_AVOID_GOTPLT)
 	    {
 	      /* Change a "jsr sym" into (allocate register rM, rO)
-		 "move.d (const (unspec [sym rPIC] CRIS_UNSPEC_PLT_GOTREL)),rM"
+		 "move.d (const (unspec [sym] CRIS_UNSPEC_PLT_GOTREL)),rM"
 		 "add.d rPIC,rM,rO", "jsr rO" for pre-v32 and
-		 "jsr (const (unspec [sym rPIC] CRIS_UNSPEC_PLT_PCREL))"
+		 "jsr (const (unspec [sym] CRIS_UNSPEC_PLT_PCREL))"
 		 for v32.  */
 	      rtx tem, rm, ro;
-	      gcc_assert (can_create_pseudo_p ());
+
 	      crtl->uses_pic_offset_table = 1;
 	      tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op),
 				    TARGET_V32
@@ -3604,14 +3841,27 @@
 	      MEM_NOTRAP_P (mem) = 1;
 	      op = mem;
 	    }
+
+	  /* We need to prepare this call to go through the PLT; we
+	     need to make GOT available.  */
+	  *markerp = pic_offset_table_rtx;
 	}
       else
-	/* Can't possibly get a GOT-needing-fixup for a function-call,
-	   right?  */
+	/* Can't possibly get anything else for a function-call, right?  */
 	fatal_insn ("unidentifiable call op", op);
 
-      *opp = replace_equiv_address (*opp, op);
+      /* If the validizing variant is called, it will try to validize
+	 the address as a valid any-operand constant, but as it's only
+	 valid for calls and moves, it will fail and always be forced
+	 into a register.  */
+      *opp = replace_equiv_address_nv (*opp, op);
     }
+  else
+    /* Can't tell what locality a call to a non-constant address has;
+       better make the GOT register alive at it.
+       FIXME: Can we see whether the register has known constant
+       contents?  */
+    *markerp = pic_offset_table_rtx;
 }
 
 /* Make sure operands are in the right order for an addsi3 insn as
@@ -3684,9 +3934,9 @@
     assemble_name (file, buf);
 }
 
-/* Worker function for OUTPUT_ADDR_CONST_EXTRA.  */
-
-bool
+/* Worker function for TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA.  */
+
+static bool
 cris_output_addr_const_extra (FILE *file, rtx xconst)
 {
   switch (GET_CODE (xconst))
@@ -3759,12 +4009,14 @@
 /* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
 
 static void
-cris_setup_incoming_varargs (CUMULATIVE_ARGS *ca,
-			     enum machine_mode mode ATTRIBUTE_UNUSED,
+cris_setup_incoming_varargs (cumulative_args_t ca_v,
+			     machine_mode mode ATTRIBUTE_UNUSED,
 			     tree type ATTRIBUTE_UNUSED,
 			     int *pretend_arg_size,
 			     int second_time)
 {
+  CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v);
+
   if (ca->regs < CRIS_MAX_ARGS_IN_REGS)
     {
       int stdarg_regs = CRIS_MAX_ARGS_IN_REGS - ca->regs;
@@ -3782,8 +4034,8 @@
    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, const_tree type,
+cris_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
+			machine_mode mode, const_tree type,
 			bool named ATTRIBUTE_UNUSED)
 {
   return (targetm.calls.must_pass_in_stack (mode, type)
@@ -3794,9 +4046,9 @@
    and *not* defining TARGET_PROMOTE_PROTOTYPES or PROMOTE_MODE gives the
    best code size and speed for gcc, ipps and products in gcc-2.7.2.  */
 
-enum machine_mode
+machine_mode
 cris_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
-                            enum machine_mode mode,
+                            machine_mode mode,
                             int *punsignedp ATTRIBUTE_UNUSED,
 			    const_tree fntype ATTRIBUTE_UNUSED,
                             int for_return)
@@ -3809,6 +4061,14 @@
   return CRIS_PROMOTED_MODE (mode, *punsignedp, type);
 } 
 
+/* Atomic types require alignment to be at least their "natural" size.  */
+
+static unsigned int
+cris_atomic_align_for_mode (machine_mode mode)
+{
+  return GET_MODE_BITSIZE (mode);
+}
+
 /* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the
    time being.  */
 
@@ -3824,7 +4084,7 @@
    time being.  */
 
 static rtx
-cris_libcall_value (enum machine_mode mode,
+cris_libcall_value (machine_mode mode,
 		    const_rtx fun ATTRIBUTE_UNUSED)
 {
   return gen_rtx_REG (mode, CRIS_FIRST_ARG_REG);
@@ -3833,17 +4093,17 @@
 /* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the
    time being.  */
 
-bool
+static bool
 cris_function_value_regno_p (const unsigned int regno)
 {
   return (regno == CRIS_FIRST_ARG_REG);
 }
 
 static int
-cris_arg_partial_bytes (CUMULATIVE_ARGS *ca, enum machine_mode mode,
+cris_arg_partial_bytes (cumulative_args_t ca, machine_mode mode,
 			tree type, bool named ATTRIBUTE_UNUSED)
 {
-  if (ca->regs == CRIS_MAX_ARGS_IN_REGS - 1
+  if (get_cumulative_args (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)
@@ -3853,11 +4113,13 @@
 }
 
 static rtx
-cris_function_arg_1 (const CUMULATIVE_ARGS *ca,
-		     enum machine_mode mode ATTRIBUTE_UNUSED,
+cris_function_arg_1 (cumulative_args_t ca_v,
+		     machine_mode mode ATTRIBUTE_UNUSED,
 		     const_tree type ATTRIBUTE_UNUSED,
 		     bool named, bool incoming)
 {
+  const CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v);
+
   if ((!incoming || named) && ca->regs < CRIS_MAX_ARGS_IN_REGS)
     return gen_rtx_REG (mode, CRIS_FIRST_ARG_REG + ca->regs);
   else
@@ -3868,7 +4130,7 @@
    The void_type_node is sent as a "closing" call.  */
 
 static rtx
-cris_function_arg (CUMULATIVE_ARGS *ca, enum machine_mode mode,
+cris_function_arg (cumulative_args_t ca, machine_mode mode,
 		   const_tree type, bool named)
 {
   return cris_function_arg_1 (ca, mode, type, named, false);
@@ -3882,7 +4144,7 @@
    void_type_node TYPE parameter.  */
 
 static rtx
-cris_function_incoming_arg (CUMULATIVE_ARGS *ca, enum machine_mode mode,
+cris_function_incoming_arg (cumulative_args_t ca, machine_mode mode,
 			    const_tree type, bool named)
 {
   return cris_function_arg_1 (ca, mode, type, named, true);
@@ -3891,61 +4153,49 @@
 /* Worker function for TARGET_FUNCTION_ARG_ADVANCE.  */
 
 static void
-cris_function_arg_advance (CUMULATIVE_ARGS *ca, enum machine_mode mode,
+cris_function_arg_advance (cumulative_args_t ca_v, machine_mode mode,
 			   const_tree type, bool named ATTRIBUTE_UNUSED)
 {
+  CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v);
+
   ca->regs += (3 + CRIS_FUNCTION_ARG_SIZE (mode, type)) / 4;
 }
 
-/* Worker function for TARGET_MD_ASM_CLOBBERS.  */
-
-static tree
-cris_md_asm_clobbers (tree outputs, tree inputs, tree in_clobbers)
+/* Worker function for TARGET_MD_ASM_ADJUST.  */
+
+static rtx_insn *
+cris_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &inputs,
+		    vec<const char *> &constraints,
+		    vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs)
 {
-  HARD_REG_SET mof_set;
-  tree clobbers;
-  tree t;
-
-  CLEAR_HARD_REG_SET (mof_set);
-  SET_HARD_REG_BIT (mof_set, CRIS_MOF_REGNUM);
-
-  /* For the time being, all asms clobber condition codes.  Revisit when
-     there's a reasonable use for inputs/outputs that mention condition
-     codes.  */
-  clobbers
-    = tree_cons (NULL_TREE,
-		 build_string (strlen (reg_names[CRIS_CC0_REGNUM]),
-			       reg_names[CRIS_CC0_REGNUM]),
-		 in_clobbers);
-
-  for (t = outputs; t != NULL; t = TREE_CHAIN (t))
-    {
-      tree val = TREE_VALUE (t);
-
-      /* The constraint letter for the singleton register class of MOF
-	 is 'h'.  If it's mentioned in the constraints, the asm is
-	 MOF-aware and adding it to the clobbers would cause it to have
-	 impossible constraints.  */
-      if (strchr (TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))),
-		  'h') != NULL
-	  || tree_overlaps_hard_reg_set (val, &mof_set) != NULL_TREE)
-	return clobbers;
-    }
-
-  for (t = inputs; t != NULL; t = TREE_CHAIN (t))
-    {
-      tree val = TREE_VALUE (t);
-
-      if (strchr (TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))),
-		  'h') != NULL
-	  || tree_overlaps_hard_reg_set (val, &mof_set) != NULL_TREE)
-	return clobbers;
-    }
-
-  return tree_cons (NULL_TREE,
-		    build_string (strlen (reg_names[CRIS_MOF_REGNUM]),
-				  reg_names[CRIS_MOF_REGNUM]),
-		    clobbers);
+  /* For the time being, all asms clobber condition codes.
+     Revisit when there's a reasonable use for inputs/outputs
+     that mention condition codes.  */
+  clobbers.safe_push (gen_rtx_REG (CCmode, CRIS_CC0_REGNUM));
+  SET_HARD_REG_BIT (clobbered_regs, CRIS_CC0_REGNUM);
+
+  /* Determine if the source using MOF.  If it is, automatically
+     clobbering MOF would cause it to have impossible constraints.  */
+
+  /* Look for a use of the MOF constraint letter: h.  */
+  for (unsigned i = 0, n = constraints.length(); i < n; ++i)
+    if (strchr (constraints[i], 'h') != NULL)
+      return NULL;
+
+  /* Look for an output or an input that touches MOF.  */
+  rtx mof_reg = gen_rtx_REG (SImode, CRIS_MOF_REGNUM);
+  for (unsigned i = 0, n = outputs.length(); i < n; ++i)
+    if (reg_overlap_mentioned_p (mof_reg, outputs[i]))
+      return NULL;
+  for (unsigned i = 0, n = inputs.length(); i < n; ++i)
+    if (reg_overlap_mentioned_p (mof_reg, inputs[i]))
+      return NULL;
+
+  /* No direct reference to MOF or its constraint.
+     Clobber it for backward compatibility.  */
+  clobbers.safe_push (mof_reg);
+  SET_HARD_REG_BIT (clobbered_regs, CRIS_MOF_REGNUM);
+  return NULL;
 }
 
 /* Implement TARGET_FRAME_POINTER_REQUIRED.
@@ -3957,7 +4207,7 @@
 bool
 cris_frame_pointer_required (void)
 {
-  return !current_function_sp_is_unchanging;
+  return !crtl->sp_is_unchanging;
 }
 
 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE.
@@ -4038,7 +4288,7 @@
   if (TARGET_V32)
     {
       mem = adjust_address (m_tramp, SImode, 6);
-      emit_move_insn (mem, plus_constant (tramp, 38));
+      emit_move_insn (mem, plus_constant (Pmode, tramp, 38));
       mem = adjust_address (m_tramp, SImode, 22);
       emit_move_insn (mem, chain_value);
       mem = adjust_address (m_tramp, SImode, 28);
@@ -4056,6 +4306,64 @@
      sake of a trampoline.  */
 }
 
+/* Implement TARGET_HARD_REGNO_NREGS.
+
+   The VOIDmode test is so we can omit mode on anonymous insns.  FIXME:
+   Still needed in 2.9x, at least for Axis-20000319.  */
+
+static unsigned int
+cris_hard_regno_nregs (unsigned int, machine_mode mode)
+{
+  if (mode == VOIDmode)
+    return 1;
+  return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
+}
+
+/* Implement TARGET_HARD_REGNO_MODE_OK.
+
+   CRIS permits all registers to hold all modes.  Well, except for the
+   condition-code register.  And we can't hold larger-than-register size
+   modes in the last special register that can hold a full 32 bits.  */
+static bool
+cris_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
+{
+  return ((mode == CCmode || regno != CRIS_CC0_REGNUM)
+	  && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+	      || (regno != CRIS_MOF_REGNUM && regno != CRIS_ACR_REGNUM)));
+}
+
+/* Return the preferred minimum alignment for a static object.  */
+
+static HOST_WIDE_INT
+cris_preferred_mininum_alignment (void)
+{
+  if (!TARGET_CONST_ALIGN)
+    return 8;
+  if (TARGET_ALIGN_BY_32)
+    return 32;
+  return 16;
+}
+
+/* Implement TARGET_STATIC_RTX_ALIGNMENT.  */
+
+static HOST_WIDE_INT
+cris_static_rtx_alignment (machine_mode mode)
+{
+  return MAX (cris_preferred_mininum_alignment (), GET_MODE_ALIGNMENT (mode));
+}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT.  Note that this hook has the
+   effect of making gcc believe that ALL references to constant stuff
+   (in code segment, like strings) have this alignment.  That is a rather
+   rushed assumption.  Luckily we do not care about the "alignment"
+   operand to builtin memcpy (only place where it counts), so it doesn't
+   affect any bad spots.  */
+
+static HOST_WIDE_INT
+cris_constant_alignment (const_tree, HOST_WIDE_INT basic_align)
+{
+  return MAX (cris_preferred_mininum_alignment (), basic_align);
+}
 
 #if 0
 /* Various small functions to replace macros.  Only called from a