This is the cut down set of differences between the official GCC 4.1.1 release
and the ST40R2 4.0.1 release compiler sources.  The full set had a lot of
cosmetic differences which were not useful (nor harmful) and have been omitted.



diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/basic-block.h gcc-4.1.1/gcc/basic-block.h
--- gcc-4.1.1.orig/gcc/basic-block.h	2005-07-11 14:31:44.000000000 +0100
+++ gcc-4.1.1/gcc/basic-block.h	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Define control and data flow tables, and regsets.
    Copyright (C) 1987, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -807,6 +808,9 @@ enum update_life_extent
 					   to flag analysis of asms.  */
 #define PROP_DEAD_INSN		1024	/* Internal flag used within flow.c
 					   to flag analysis of dead insn.  */
+#define PROP_POST_REGSTACK	2048	/* We run after reg-stack and need
+					   to preserve REG_DEAD notes for
+					   stack regs.  */
 #define PROP_FINAL		(PROP_DEATH_NOTES | PROP_LOG_LINKS  \
 				 | PROP_REG_INFO | PROP_KILL_DEAD_CODE  \
 				 | PROP_SCAN_DEAD_CODE | PROP_AUTOINC \
@@ -831,6 +835,17 @@ #define PROP_POSTRELOAD		(PROP_DEATH_NOT
 #define CLEANUP_CFGLAYOUT	128	/* Do cleanup in cfglayout mode.  */
 #define CLEANUP_LOG_LINKS	256	/* Update log links.  */
 
+/* The following are ORed in on top of the CLEANUP* flags in calls to
+   struct_equiv_block_eq.  */
+#define STRUCT_EQUIV_START	512	 /* Initializes the search range.  */
+#define STRUCT_EQUIV_RERUN	1024	/* Rerun to find register use in
+					   found equivalence.  */
+#define STRUCT_EQUIV_FINAL	2048	/* Make any changes necessary to get
+					   actual equivalence.  */
+#define STRUCT_EQUIV_NEED_FULL_BLOCK 4096 /* struct_equiv_block_eq is required
+					     to match only full blocks  */
+#define STRUCT_EQUIV_MATCH_JUMPS 8192	/* Also include the jumps at the end of the block in the comparison.  */
+
 extern void life_analysis (FILE *, int);
 extern int update_life_info (sbitmap, enum update_life_extent, int);
 extern int update_life_info_in_dirty_blocks (enum update_life_extent, int);
@@ -991,4 +1006,169 @@ extern basic_block get_bb_copy (basic_bl
 
 #include "cfghooks.h"
 
+/* In struct-equiv.c */
+
+/* Constants used to size arrays in struct equiv_info (currently only one).
+   When these limits are exceeded, struct_equiv returns zero.
+   The maximum number of pseudo registers that are different in the two blocks,
+   but appear in equivalent places and are dead at the end (or where one of
+   a pair is dead at the end).  */
+#define STRUCT_EQUIV_MAX_LOCAL 16
+/* The maximum number of references to an input register that struct_equiv
+   can handle.  */
+
+/* Structure used to track state during struct_equiv that can be rolled
+   back when we find we can't match an insn, or if we want to match part
+   of it in a different way.
+   This information pertains to the pair of partial blocks that has been
+   matched so far.  Since this pair is structurally equivalent, this is
+   conceptually just one partial block expressed in two potentially
+   different ways.  */
+struct struct_equiv_checkpoint
+{
+  int ninsns;       /* Insns are matched so far.  */
+  int local_count;  /* Number of block-local registers.  */
+  int input_count;  /* Number of inputs to the block.  */
+
+  /* X_START and Y_START are the first insns (in insn stream order)
+     of the partial blocks that have been considered for matching so far.
+     Since we are scanning backwards, they are also the instructions that
+     are currently considered - or the last ones that have been considered -
+     for matching (Unless we tracked back to these because a preceding
+     instruction failed to match).  */
+  rtx x_start, y_start;
+
+  /*  INPUT_VALID indicates if we have actually set up X_INPUT / Y_INPUT
+      during the current pass; we keep X_INPUT / Y_INPUT around between passes
+      so that we can match REG_EQUAL / REG_EQUIV notes referring to these.  */
+  bool input_valid;
+
+  /* Some information would be expensive to exactly checkpoint, so we
+     merely increment VERSION any time information about local
+     registers, inputs and/or register liveness changes.  When backtracking,
+     it is decremented for changes that can be undone, and if a discrepancy
+     remains, NEED_RERUN in the relevant struct equiv_info is set to indicate
+     that a new pass should be made over the entire block match to get
+     accurate register information.  */
+  int version;
+};
+
+/* A struct equiv_info is used to pass information to struct_equiv and
+   to gather state while two basic blocks are checked for structural
+   equivalence.  */
+
+struct equiv_info
+{
+  /* Fields set up by the caller to struct_equiv_block_eq */
+
+  basic_block x_block, y_block;  /* The two blocks being matched.  */
+
+  /* MODE carries the mode bits from cleanup_cfg if we are called from
+     try_crossjump_to_edge, and additionally it carries the
+     STRUCT_EQUIV_* bits described above.  */
+  int mode;
+
+  /* INPUT_COST is the cost that adding an extra input to the matched blocks
+     is supposed to have, and is taken into account when considering if the
+     matched sequence should be extended backwards.  input_cost < 0 means
+     don't accept any inputs at all.  */
+  int input_cost;
+
+
+  /* Fields to track state inside of struct_equiv_block_eq.  Some of these
+     are also outputs.  */
+
+  /* X_INPUT and Y_INPUT are used by struct_equiv to record a register that
+     is used as an input parameter, i.e. where different registers are used
+     as sources.  This is only used for a register that is live at the end
+     of the blocks, or in some identical code at the end of the blocks;
+     Inputs that are dead at the end go into X_LOCAL / Y_LOCAL.  */
+  rtx x_input, y_input;
+  /* When a previous pass has identified a valid input, INPUT_REG is set
+     by struct_equiv_block_eq, and it is henceforth replaced in X_BLOCK
+     for the input.  */
+  rtx input_reg;
+
+  /* COMMON_LIVE keeps track of the registers which are currently live
+     (as we scan backwards from the end) and have the same numbers in both
+     blocks.  N.B. a register that is in common_live is unsuitable to become
+     a local reg.  */
+  regset common_live;
+  /* Likewise, X_LOCAL_LIVE / Y_LOCAL_LIVE keep track of registers that are
+     local to one of the blocks; these registers must not be accepted as
+     identical when encountered in both blocks.  */
+  regset x_local_live, y_local_live;
+
+  /* EQUIV_USED indicates for which insns a REG_EQUAL or REG_EQUIV note is
+     being used, to avoid having to backtrack in the next pass, so that we
+     get accurate life info for this insn then.  For each such insn,
+     the bit with the number corresponding to the CUR.NINSNS value at the
+     time of scanning is set.  */
+  bitmap equiv_used;
+
+  /* Current state that can be saved & restored easily.  */
+  struct struct_equiv_checkpoint cur;
+  /* BEST_MATCH is used to store the best match so far, weighing the
+     cost of matched insns COSTS_N_INSNS (CUR.NINSNS) against the cost
+     CUR.INPUT_COUNT * INPUT_COST of setting up the inputs.  */
+  struct struct_equiv_checkpoint best_match;
+  /* If a checkpoint restore failed, or an input conflict newly arises,
+     NEED_RERUN is set.  This has to be tested by the caller to re-run
+     the comparison if the match appears otherwise sound.  The state kept in
+     x_start, y_start, equiv_used and check_input_conflict ensures that
+     we won't loop indefinetly.  */
+  bool need_rerun;
+  /* If there is indication of an input conflict at the end,
+     CHECK_INPUT_CONFLICT is set so that we'll check for input conflicts
+     for each insn in the next pass.  This is needed so that we won't discard
+     a partial match if there is a longer match that has to be abandoned due
+     to an input conflict.  */
+  bool check_input_conflict;
+  /* HAD_INPUT_CONFLICT is set if CHECK_INPUT_CONFLICT was already set and we
+     have passed a point where there were multiple dying inputs.  This helps
+     us decide if we should set check_input_conflict for the next pass.  */
+  bool had_input_conflict;
+
+  /* LIVE_UPDATE controls if we want to change any life info at all.  We
+     set it to false during REG_EQUAL / REG_EUQIV note comparison of the final
+     pass so that we don't introduce new registers just for the note; if we
+     can't match the notes without the current register information, we drop
+     them.  */
+  bool live_update;
+
+  /* X_LOCAL and Y_LOCAL are used to gather register numbers of register pairs
+     that are local to X_BLOCK and Y_BLOCK, with CUR.LOCAL_COUNT being the index
+     to the next free entry.  */
+  rtx x_local[STRUCT_EQUIV_MAX_LOCAL], y_local[STRUCT_EQUIV_MAX_LOCAL];
+  /* LOCAL_RVALUE is nonzero if the corresponding X_LOCAL / Y_LOCAL entry
+     was a source operand (including STRICT_LOW_PART) for the last invocation
+     of struct_equiv mentioning it, zero if it was a destination-only operand.
+     Since we are scanning backwards, this means the register is input/local
+     for the (partial) block scanned so far.  */
+  bool local_rvalue[STRUCT_EQUIV_MAX_LOCAL];
+
+
+  /* Additional fields that are computed for the convenience of the caller.  */
+
+  /* DYING_INPUTS is set to the number of local registers that turn out
+     to be inputs to the (possibly partial) block.  */
+  int dying_inputs;
+  /* X_END and Y_END are the last insns in X_BLOCK and Y_BLOCK, respectively,
+     that are being compared.  A final jump insn will not be included.  */
+  rtx x_end, y_end;
+
+  /* If we are matching tablejumps, X_LABEL in X_BLOCK coresponds to
+     Y_LABEL in Y_BLOCK.  */
+  rtx x_label, y_label;
+
+};
+
+extern bool insns_match_p (rtx, rtx, struct equiv_info *);
+extern int struct_equiv_block_eq (int, struct equiv_info *);
+extern bool struct_equiv_init (int, struct equiv_info *, bool);
+extern bool rtx_equiv_p (rtx *, rtx, int, struct equiv_info *);
+
+/* In cfgrtl.c */
+extern bool condjump_equiv_p (struct equiv_info *, bool);
+
 #endif /* GCC_BASIC_BLOCK_H */
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/builtins.c gcc-4.1.1/gcc/builtins.c
--- gcc-4.1.1.orig/gcc/builtins.c	2006-05-08 07:13:23.000000000 +0100
+++ gcc-4.1.1/gcc/builtins.c	2006-08-10 09:56:05.000000000 +0100
@@ -276,16 +276,44 @@ 	  exp = TREE_OPERAND (exp, 0);
 	  /* See what we are pointing at and look at its alignment.  */
 	  exp = TREE_OPERAND (exp, 0);
 	  inner = max_align;
-	  while (handled_component_p (exp))
+	  if (handled_component_p (exp))
 	    {
-	      /* Fields in a structure can be packed, honour DECL_ALIGN
-		 of the FIELD_DECL.  For all other references the conservative 
-		 alignment is the element type alignment.  */
-	      if (TREE_CODE (exp) == COMPONENT_REF)
-		inner = MIN (inner, DECL_ALIGN (TREE_OPERAND (exp, 1)));
-	      else
-		inner = MIN (inner, TYPE_ALIGN (TREE_TYPE (exp)));
-	      exp = TREE_OPERAND (exp, 0);
+	      HOST_WIDE_INT bitsize, bitpos;
+	      tree offset;
+	      enum machine_mode mode;
+	      int unsignedp, volatilep;
+	      
+	      exp = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+					 &mode, &unsignedp, &volatilep, true);
+	      if (bitpos)
+		inner = MIN (inner, (unsigned) (bitpos & -bitpos));
+	      if (offset && TREE_CODE (offset) == PLUS_EXPR
+		  && host_integerp (TREE_OPERAND (offset, 1), 1))
+		{
+		  /* Any overflow in calculating offset_bits won't change
+		     the alignment.  */
+		  unsigned offset_bits
+		    = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
+		       * BITS_PER_UNIT);
+
+		  if (offset_bits)
+		    inner = MIN (inner, (offset_bits & -offset_bits));
+		  offset = TREE_OPERAND (offset, 0);
+		}
+	      if (offset && TREE_CODE (offset) == MULT_EXPR
+		  && host_integerp (TREE_OPERAND (offset, 1), 1))
+		{
+		  /* Any overflow in calculating offset_factor won't change
+		     the alignment.  */
+		  unsigned offset_factor
+		    = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
+		       * BITS_PER_UNIT);
+
+		  if (offset_factor)
+		    inner = MIN (inner, (offset_factor & -offset_factor));
+		}
+	      else if (offset)
+		inner = MIN (inner, BITS_PER_UNIT);
 	    }
 	  if (TREE_CODE (exp) == FUNCTION_DECL)
 	    align = FUNCTION_BOUNDARY;
@@ -295,6 +323,9 @@ 	    align = MIN (inner, DECL_ALIGN (exp
 	  else if (CONSTANT_CLASS_P (exp))
 	    align = MIN (inner, (unsigned)CONSTANT_ALIGNMENT (exp, align));
 #endif
+	  else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR
+		   || TREE_CODE (exp) == INDIRECT_REF)
+	    align = MIN (TYPE_ALIGN (TREE_TYPE (exp)), inner);
 	  else
 	    align = MIN (align, inner);
 	  return MIN (align, max_align);
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/cfgcleanup.c gcc-4.1.1/gcc/cfgcleanup.c
--- gcc-4.1.1.orig/gcc/cfgcleanup.c	2005-07-29 01:45:57.000000000 +0100
+++ gcc-4.1.1/gcc/cfgcleanup.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Control flow optimization code for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -58,11 +59,6 @@ #define FORWARDER_BLOCK_P(BB) ((BB)->fla
   
 /* Set to true when we are running first pass of try_optimize_cfg loop.  */
 static bool first_pass;
-static bool try_crossjump_to_edge (int, edge, edge);
-static bool try_crossjump_bb (int, basic_block);
-static bool outgoing_edges_match (int, basic_block, basic_block);
-static int flow_find_cross_jump (int, basic_block, basic_block, rtx *, rtx *);
-static bool insns_match_p (int, rtx, rtx);
 
 static void merge_blocks_move_predecessor_nojumps (basic_block, basic_block);
 static void merge_blocks_move_successor_nojumps (basic_block, basic_block);
@@ -74,7 +70,6 @@ static bool mark_effect (rtx, bitmap);
 static void notice_new_block (basic_block);
 static void update_forwarder_flag (basic_block);
 static int mentions_nonequal_regs (rtx *, void *);
-static void merge_memattrs (rtx, rtx);
 
 /* Set flags for newly created block.  */
 
@@ -881,328 +876,148 @@       merge_blocks_move_predecessor_noju
   return NULL;
 }
 
-
-/* Removes the memory attributes of MEM expression
-   if they are not equal.  */
-
-void
-merge_memattrs (rtx x, rtx y)
+/* Return true iff the condbranches at the end of BB1 and BB2 match.  */
+bool
+condjump_equiv_p (struct equiv_info *info, bool call_init)
 {
-  int i;
-  int j;
-  enum rtx_code code;
-  const char *fmt;
-
-  if (x == y)
-    return;
-  if (x == 0 || y == 0)
-    return;
-
-  code = GET_CODE (x);
-
-  if (code != GET_CODE (y))
-    return;
-
-  if (GET_MODE (x) != GET_MODE (y))
-    return;
-
-  if (code == MEM && MEM_ATTRS (x) != MEM_ATTRS (y))
-    {
-      if (! MEM_ATTRS (x))
-	MEM_ATTRS (y) = 0;
-      else if (! MEM_ATTRS (y))
-	MEM_ATTRS (x) = 0;
-      else 
-	{
-	  rtx mem_size;
-
-	  if (MEM_ALIAS_SET (x) != MEM_ALIAS_SET (y))
-	    {
-	      set_mem_alias_set (x, 0);
-	      set_mem_alias_set (y, 0);
-	    }
-	  
-	  if (! mem_expr_equal_p (MEM_EXPR (x), MEM_EXPR (y)))
-	    {
-	      set_mem_expr (x, 0);
-	      set_mem_expr (y, 0);
-	      set_mem_offset (x, 0);
-	      set_mem_offset (y, 0);
-	    }
-	  else if (MEM_OFFSET (x) != MEM_OFFSET (y))
-	    {
-	      set_mem_offset (x, 0);
-	      set_mem_offset (y, 0);
-	    }
-	 
-	  if (!MEM_SIZE (x))
-	    mem_size = NULL_RTX;
-	  else if (!MEM_SIZE (y))
-	    mem_size = NULL_RTX;
-	  else
-	    mem_size = GEN_INT (MAX (INTVAL (MEM_SIZE (x)),
-				     INTVAL (MEM_SIZE (y))));
-	  set_mem_size (x, mem_size);
-	  set_mem_size (y, mem_size);
-
-	  set_mem_align (x, MIN (MEM_ALIGN (x), MEM_ALIGN (y)));
-	  set_mem_align (y, MEM_ALIGN (x));
-	}
-    }
-  
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    {
-      switch (fmt[i])
-	{
-	case 'E':
-	  /* Two vectors must have the same length.  */
-	  if (XVECLEN (x, i) != XVECLEN (y, i))
-	    return;
-
-	  for (j = 0; j < XVECLEN (x, i); j++)
-	    merge_memattrs (XVECEXP (x, i, j), XVECEXP (y, i, j));
-
-	  break;
-
-	case 'e':
-	  merge_memattrs (XEXP (x, i), XEXP (y, i));
-	}
-    }
-  return;
-}
-
+  basic_block bb1 = info->x_block;
+  basic_block bb2 = info->y_block;
+  edge b1 = BRANCH_EDGE (bb1);
+  edge b2 = BRANCH_EDGE (bb2);
+  edge f1 = FALLTHRU_EDGE (bb1);
+  edge f2 = FALLTHRU_EDGE (bb2);
+  bool reverse, match;
+  rtx set1, set2, cond1, cond2;
+  rtx src1, src2;
+  enum rtx_code code1, code2;
 
-/* Return true if I1 and I2 are equivalent and thus can be crossjumped.  */
+  /* Get around possible forwarders on fallthru edges.  Other cases
+     should be optimized out already.  */
+  if (FORWARDER_BLOCK_P (f1->dest))
+    f1 = single_succ_edge (f1->dest);
 
-static bool
-insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
-{
-  rtx p1, p2;
+  if (FORWARDER_BLOCK_P (f2->dest))
+    f2 = single_succ_edge (f2->dest);
 
-  /* Verify that I1 and I2 are equivalent.  */
-  if (GET_CODE (i1) != GET_CODE (i2))
+  /* To simplify use of this function, return false if there are
+     unneeded forwarder blocks.  These will get eliminated later
+     during cleanup_cfg.  */
+  if (FORWARDER_BLOCK_P (f1->dest)
+      || FORWARDER_BLOCK_P (f2->dest)
+      || FORWARDER_BLOCK_P (b1->dest)
+      || FORWARDER_BLOCK_P (b2->dest))
     return false;
 
-  p1 = PATTERN (i1);
-  p2 = PATTERN (i2);
-
-  if (GET_CODE (p1) != GET_CODE (p2))
+  if (f1->dest == f2->dest && b1->dest == b2->dest)
+    reverse = false;
+  else if (f1->dest == b2->dest && b1->dest == f2->dest)
+    reverse = true;
+  else
     return false;
 
-  /* If this is a CALL_INSN, compare register usage information.
-     If we don't check this on stack register machines, the two
-     CALL_INSNs might be merged leaving reg-stack.c with mismatching
-     numbers of stack registers in the same basic block.
-     If we don't check this on machines with delay slots, a delay slot may
-     be filled that clobbers a parameter expected by the subroutine.
+  set1 = pc_set (BB_END (bb1));
+  set2 = pc_set (BB_END (bb2));
+  if ((XEXP (SET_SRC (set1), 1) == pc_rtx)
+      != (XEXP (SET_SRC (set2), 1) == pc_rtx))
+    reverse = !reverse;
 
-     ??? We take the simple route for now and assume that if they're
-     equal, they were constructed identically.  */
+  src1 = SET_SRC (set1);
+  src2 = SET_SRC (set2);
+  cond1 = XEXP (src1, 0);
+  cond2 = XEXP (src2, 0);
+  code1 = GET_CODE (cond1);
+  if (reverse)
+    code2 = reversed_comparison_code (cond2, BB_END (bb2));
+  else
+    code2 = GET_CODE (cond2);
 
-  if (CALL_P (i1)
-      && (!rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
-		        CALL_INSN_FUNCTION_USAGE (i2))
-	  || SIBLING_CALL_P (i1) != SIBLING_CALL_P (i2)))
+  if (code2 == UNKNOWN)
     return false;
 
-#ifdef STACK_REGS
-  /* If cross_jump_death_matters is not 0, the insn's mode
-     indicates whether or not the insn contains any stack-like
-     regs.  */
-
-  if ((mode & CLEANUP_POST_REGSTACK) && stack_regs_mentioned (i1))
-    {
-      /* If register stack conversion has already been done, then
-         death notes must also be compared before it is certain that
-         the two instruction streams match.  */
-
-      rtx note;
-      HARD_REG_SET i1_regset, i2_regset;
-
-      CLEAR_HARD_REG_SET (i1_regset);
-      CLEAR_HARD_REG_SET (i2_regset);
-
-      for (note = REG_NOTES (i1); note; note = XEXP (note, 1))
-	if (REG_NOTE_KIND (note) == REG_DEAD && STACK_REG_P (XEXP (note, 0)))
-	  SET_HARD_REG_BIT (i1_regset, REGNO (XEXP (note, 0)));
-
-      for (note = REG_NOTES (i2); note; note = XEXP (note, 1))
-	if (REG_NOTE_KIND (note) == REG_DEAD && STACK_REG_P (XEXP (note, 0)))
-	  SET_HARD_REG_BIT (i2_regset, REGNO (XEXP (note, 0)));
-
-      GO_IF_HARD_REG_EQUAL (i1_regset, i2_regset, done);
-
-      return false;
-
-    done:
-      ;
-    }
-#endif
-
-  if (reload_completed
-      ? rtx_renumbered_equal_p (p1, p2) : rtx_equal_p (p1, p2))
-    return true;
-
-  /* Do not do EQUIV substitution after reload.  First, we're undoing the
-     work of reload_cse.  Second, we may be undoing the work of the post-
-     reload splitting pass.  */
-  /* ??? Possibly add a new phase switch variable that can be used by
-     targets to disallow the troublesome insns after splitting.  */
-  if (!reload_completed)
+  if (call_init)
+    struct_equiv_init (STRUCT_EQUIV_START | info->mode, info, false);
+  /* Make the sources of the pc sets unreadable so that when we call
+     insns_match_p it won't process them.
+     The death_notes_match_p from insns_match_p won't see the local registers
+     used for the pc set, but that could only cause missed optimizations when
+     there are actually condjumps that use stack registers.  */
+  SET_SRC (set1) = pc_rtx;
+  SET_SRC (set2) = pc_rtx;
+  /* Verify codes and operands match.  */
+  if (code1 == code2)
     {
-      /* The following code helps take care of G++ cleanups.  */
-      rtx equiv1 = find_reg_equal_equiv_note (i1);
-      rtx equiv2 = find_reg_equal_equiv_note (i2);
+      match = (insns_match_p (BB_END (bb1), BB_END (bb2), info)
+	       && rtx_equiv_p (&XEXP (cond1, 0), XEXP (cond2, 0), 1, info)
+	       && rtx_equiv_p (&XEXP (cond1, 1), XEXP (cond2, 1), 1, info));
 
-      if (equiv1 && equiv2
-	  /* If the equivalences are not to a constant, they may
-	     reference pseudos that no longer exist, so we can't
-	     use them.  */
-	  && (! reload_completed
-	      || (CONSTANT_P (XEXP (equiv1, 0))
-		  && rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0)))))
-	{
-	  rtx s1 = single_set (i1);
-	  rtx s2 = single_set (i2);
-	  if (s1 != 0 && s2 != 0
-	      && rtx_renumbered_equal_p (SET_DEST (s1), SET_DEST (s2)))
-	    {
-	      validate_change (i1, &SET_SRC (s1), XEXP (equiv1, 0), 1);
-	      validate_change (i2, &SET_SRC (s2), XEXP (equiv2, 0), 1);
-	      if (! rtx_renumbered_equal_p (p1, p2))
-		cancel_changes (0);
-	      else if (apply_change_group ())
-		return true;
-	    }
-	}
     }
-
-  return false;
-}
-
-/* Look through the insns at the end of BB1 and BB2 and find the longest
-   sequence that are equivalent.  Store the first insns for that sequence
-   in *F1 and *F2 and return the sequence length.
-
-   To simplify callers of this function, if the blocks match exactly,
-   store the head of the blocks in *F1 and *F2.  */
-
-static int
-flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1,
-		      basic_block bb2, rtx *f1, rtx *f2)
-{
-  rtx i1, i2, last1, last2, afterlast1, afterlast2;
-  int ninsns = 0;
-
-  /* Skip simple jumps at the end of the blocks.  Complex jumps still
-     need to be compared for equivalence, which we'll do below.  */
-
-  i1 = BB_END (bb1);
-  last1 = afterlast1 = last2 = afterlast2 = NULL_RTX;
-  if (onlyjump_p (i1)
-      || (returnjump_p (i1) && !side_effects_p (PATTERN (i1))))
+  else if (code1 == swap_condition (code2))
     {
-      last1 = i1;
-      i1 = PREV_INSN (i1);
-    }
+      match = (insns_match_p (BB_END (bb1), BB_END (bb2), info)
+	       && rtx_equiv_p (&XEXP (cond1, 1), XEXP (cond2, 0), 1, info)
+	       && rtx_equiv_p (&XEXP (cond1, 0), XEXP (cond2, 1), 1, info));
 
-  i2 = BB_END (bb2);
-  if (onlyjump_p (i2)
-      || (returnjump_p (i2) && !side_effects_p (PATTERN (i2))))
-    {
-      last2 = i2;
-      /* Count everything except for unconditional jump as insn.  */
-      if (!simplejump_p (i2) && !returnjump_p (i2) && last1)
-	ninsns++;
-      i2 = PREV_INSN (i2);
     }
+  else
+    match = false;
+  SET_SRC (set1) = src1;
+  SET_SRC (set2) = src2;
+  match &= verify_changes (0);
 
-  while (true)
+  /* If we return true, we will join the blocks.  Which means that
+     we will only have one branch prediction bit to work with.  Thus
+     we require the existing branches to have probabilities that are
+     roughly similar.  */
+  if (match
+      && !optimize_size
+      && maybe_hot_bb_p (bb1)
+      && maybe_hot_bb_p (bb2))
     {
-      /* Ignore notes.  */
-      while (!INSN_P (i1) && i1 != BB_HEAD (bb1))
-	i1 = PREV_INSN (i1);
-
-      while (!INSN_P (i2) && i2 != BB_HEAD (bb2))
-	i2 = PREV_INSN (i2);
-
-      if (i1 == BB_HEAD (bb1) || i2 == BB_HEAD (bb2))
-	break;
-
-      if (!insns_match_p (mode, i1, i2))
-	break;
+      int prob2;
 
-      merge_memattrs (i1, i2);
+      if (b1->dest == b2->dest)
+	prob2 = b2->probability;
+      else
+	/* Do not use f2 probability as f2 may be forwarded.  */
+	prob2 = REG_BR_PROB_BASE - b2->probability;
 
-      /* Don't begin a cross-jump with a NOTE insn.  */
-      if (INSN_P (i1))
+      /* Fail if the difference in probabilities is greater than 50%.
+	 This rules out two well-predicted branches with opposite
+	 outcomes.  */
+      if (abs (b1->probability - prob2) > REG_BR_PROB_BASE / 2)
 	{
-	  /* If the merged insns have different REG_EQUAL notes, then
-	     remove them.  */
-	  rtx equiv1 = find_reg_equal_equiv_note (i1);
-	  rtx equiv2 = find_reg_equal_equiv_note (i2);
-
-	  if (equiv1 && !equiv2)
-	    remove_note (i1, equiv1);
-	  else if (!equiv1 && equiv2)
-	    remove_note (i2, equiv2);
-	  else if (equiv1 && equiv2
-		   && !rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0)))
-	    {
-	      remove_note (i1, equiv1);
-	      remove_note (i2, equiv2);
-	    }
+	  if (dump_file)
+	    fprintf (dump_file,
+		     "Outcomes of branch in bb %i and %i differ too much (%i %i)\n",
+		     bb1->index, bb2->index, b1->probability, prob2);
 
-	  afterlast1 = last1, afterlast2 = last2;
-	  last1 = i1, last2 = i2;
-	  ninsns++;
+	  match = false;
 	}
-
-      i1 = PREV_INSN (i1);
-      i2 = PREV_INSN (i2);
     }
 
-#ifdef HAVE_cc0
-  /* Don't allow the insn after a compare to be shared by
-     cross-jumping unless the compare is also shared.  */
-  if (ninsns && reg_mentioned_p (cc0_rtx, last1) && ! sets_cc0_p (last1))
-    last1 = afterlast1, last2 = afterlast2, ninsns--;
-#endif
-
-  /* Include preceding notes and labels in the cross-jump.  One,
-     this may bring us to the head of the blocks as requested above.
-     Two, it keeps line number notes as matched as may be.  */
-  if (ninsns)
-    {
-      while (last1 != BB_HEAD (bb1) && !INSN_P (PREV_INSN (last1)))
-	last1 = PREV_INSN (last1);
-
-      if (last1 != BB_HEAD (bb1) && LABEL_P (PREV_INSN (last1)))
-	last1 = PREV_INSN (last1);
-
-      while (last2 != BB_HEAD (bb2) && !INSN_P (PREV_INSN (last2)))
-	last2 = PREV_INSN (last2);
-
-      if (last2 != BB_HEAD (bb2) && LABEL_P (PREV_INSN (last2)))
-	last2 = PREV_INSN (last2);
-
-      *f1 = last1;
-      *f2 = last2;
-    }
+  if (dump_file && match)
+    fprintf (dump_file, "Conditionals in bb %i and %i match.\n",
+	     bb1->index, bb2->index);
 
-  return ninsns;
+  if (!match)
+    cancel_changes (0);
+  return match;
 }
 
-/* Return true iff outgoing edges of BB1 and BB2 match, together with
-   the branch instruction.  This means that if we commonize the control
-   flow before end of the basic block, the semantic remains unchanged.
+/* Return true iff outgoing edges of INFO->y_block and INFO->x_block match,
+   together with the branch instruction.  This means that if we commonize the
+   control flow before end of the basic block, the semantic remains unchanged.
+   If we need to compare jumps, we set STRUCT_EQUIV_MATCH_JUMPS in *MODE,
+   and pass *MODE to struct_equiv_init or assign it to INFO->mode, as
+   appropriate.
 
    We may assume that there exists one edge with a common destination.  */
 
 static bool
-outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
+outgoing_edges_match (int *mode, struct equiv_info *info)
 {
+  basic_block bb1 = info->y_block;
+  basic_block bb2 = info->x_block;
   int nehedges1 = 0, nehedges2 = 0;
   edge fallthru1 = 0, fallthru2 = 0;
   edge e1, e2;
@@ -1218,114 +1033,19 @@ 	    && (single_succ_edge (bb2)->flags
 		& (EDGE_COMPLEX | EDGE_FAKE)) == 0
 	    && (!JUMP_P (BB_END (bb2)) || simplejump_p (BB_END (bb2))));
 
+  *mode |= STRUCT_EQUIV_MATCH_JUMPS;
   /* Match conditional jumps - this may get tricky when fallthru and branch
      edges are crossed.  */
   if (EDGE_COUNT (bb1->succs) == 2
       && any_condjump_p (BB_END (bb1))
       && onlyjump_p (BB_END (bb1)))
     {
-      edge b1, f1, b2, f2;
-      bool reverse, match;
-      rtx set1, set2, cond1, cond2;
-      enum rtx_code code1, code2;
-
       if (EDGE_COUNT (bb2->succs) != 2
 	  || !any_condjump_p (BB_END (bb2))
 	  || !onlyjump_p (BB_END (bb2)))
 	return false;
-
-      b1 = BRANCH_EDGE (bb1);
-      b2 = BRANCH_EDGE (bb2);
-      f1 = FALLTHRU_EDGE (bb1);
-      f2 = FALLTHRU_EDGE (bb2);
-
-      /* Get around possible forwarders on fallthru edges.  Other cases
-         should be optimized out already.  */
-      if (FORWARDER_BLOCK_P (f1->dest))
-	f1 = single_succ_edge (f1->dest);
-
-      if (FORWARDER_BLOCK_P (f2->dest))
-	f2 = single_succ_edge (f2->dest);
-
-      /* To simplify use of this function, return false if there are
-	 unneeded forwarder blocks.  These will get eliminated later
-	 during cleanup_cfg.  */
-      if (FORWARDER_BLOCK_P (f1->dest)
-	  || FORWARDER_BLOCK_P (f2->dest)
-	  || FORWARDER_BLOCK_P (b1->dest)
-	  || FORWARDER_BLOCK_P (b2->dest))
-	return false;
-
-      if (f1->dest == f2->dest && b1->dest == b2->dest)
-	reverse = false;
-      else if (f1->dest == b2->dest && b1->dest == f2->dest)
-	reverse = true;
-      else
-	return false;
-
-      set1 = pc_set (BB_END (bb1));
-      set2 = pc_set (BB_END (bb2));
-      if ((XEXP (SET_SRC (set1), 1) == pc_rtx)
-	  != (XEXP (SET_SRC (set2), 1) == pc_rtx))
-	reverse = !reverse;
-
-      cond1 = XEXP (SET_SRC (set1), 0);
-      cond2 = XEXP (SET_SRC (set2), 0);
-      code1 = GET_CODE (cond1);
-      if (reverse)
-	code2 = reversed_comparison_code (cond2, BB_END (bb2));
-      else
-	code2 = GET_CODE (cond2);
-
-      if (code2 == UNKNOWN)
-	return false;
-
-      /* Verify codes and operands match.  */
-      match = ((code1 == code2
-		&& rtx_renumbered_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
-		&& rtx_renumbered_equal_p (XEXP (cond1, 1), XEXP (cond2, 1)))
-	       || (code1 == swap_condition (code2)
-		   && rtx_renumbered_equal_p (XEXP (cond1, 1),
-					      XEXP (cond2, 0))
-		   && rtx_renumbered_equal_p (XEXP (cond1, 0),
-					      XEXP (cond2, 1))));
-
-      /* If we return true, we will join the blocks.  Which means that
-	 we will only have one branch prediction bit to work with.  Thus
-	 we require the existing branches to have probabilities that are
-	 roughly similar.  */
-      if (match
-	  && !optimize_size
-	  && maybe_hot_bb_p (bb1)
-	  && maybe_hot_bb_p (bb2))
-	{
-	  int prob2;
-
-	  if (b1->dest == b2->dest)
-	    prob2 = b2->probability;
-	  else
-	    /* Do not use f2 probability as f2 may be forwarded.  */
-	    prob2 = REG_BR_PROB_BASE - b2->probability;
-
-	  /* Fail if the difference in probabilities is greater than 50%.
-	     This rules out two well-predicted branches with opposite
-	     outcomes.  */
-	  if (abs (b1->probability - prob2) > REG_BR_PROB_BASE / 2)
-	    {
-	      if (dump_file)
-		fprintf (dump_file,
-			 "Outcomes of branch in bb %i and %i differ too much (%i %i)\n",
-			 bb1->index, bb2->index, b1->probability, prob2);
-
-	      return false;
-	    }
-	}
-
-      if (dump_file && match)
-	fprintf (dump_file, "Conditionals in bb %i and %i match.\n",
-		 bb1->index, bb2->index);
-
-      return match;
+      info->mode = *mode;
+      return condjump_equiv_p (info, true);
     }
 
   /* Generic case - we are seeing a computed jump, table jump or trapping
@@ -1373,31 +1093,22 @@ 		    if (!rtx_equal_p (XVECEXP (p1, 1, 
 		      identical = false;
 		}
 
-	      if (identical)
+	      if (identical
+		  && struct_equiv_init (STRUCT_EQUIV_START | *mode, info, true))
 		{
-		  replace_label_data rr;
 		  bool match;
 
-		  /* Temporarily replace references to LABEL1 with LABEL2
+		  /* Indicate that LABEL1 is to be replaced with LABEL2
 		     in BB1->END so that we could compare the instructions.  */
-		  rr.r1 = label1;
-		  rr.r2 = label2;
-		  rr.update_label_nuses = false;
-		  for_each_rtx (&BB_END (bb1), replace_label, &rr);
+		  info->y_label = label1;
+		  info->x_label = label2;
 
-		  match = insns_match_p (mode, BB_END (bb1), BB_END (bb2));
+		  match = insns_match_p (BB_END (bb1), BB_END (bb2), info);
 		  if (dump_file && match)
 		    fprintf (dump_file,
 			     "Tablejumps in bb %i and %i match.\n",
 			     bb1->index, bb2->index);
 
-		  /* Set the original label in BB1->END because when deleting
-		     a block whose end is a tablejump, the tablejump referenced
-		     from the instruction is deleted too.  */
-		  rr.r1 = label2;
-		  rr.r2 = label1;
-		  for_each_rtx (&BB_END (bb1), replace_label, &rr);
-
 		  return match;
 		}
 	    }
@@ -1405,16 +1116,20 @@ 		  for_each_rtx (&BB_END (bb1), replace
 	}
     }
 
+  /* Ensure that the edge counts do match.  */
+  if (EDGE_COUNT (bb1->succs) != EDGE_COUNT (bb2->succs))
+    return false;
+
   /* First ensure that the instructions match.  There may be many outgoing
      edges so this test is generally cheaper.  */
-  if (!insns_match_p (mode, BB_END (bb1), BB_END (bb2)))
+  /* FIXME: the regset compare might be costly.  We should try to get a cheap
+     and reasonably effective test first.  */
+  if (!struct_equiv_init (STRUCT_EQUIV_START | *mode, info, true)
+      || !insns_match_p (BB_END (bb1), BB_END (bb2), info))
     return false;
 
-  /* Search the outgoing edges, ensure that the counts do match, find possible
-     fallthru and exception handling edges since these needs more
-     validation.  */
-  if (EDGE_COUNT (bb1->succs) != EDGE_COUNT (bb2->succs))
-    return false;
+  /* Search the outgoing edges, find possible fallthru and exception
+     handling edges since these needs more validation.  */
 
   FOR_EACH_EDGE (e1, ei, bb1->succs)
     {
@@ -1473,22 +1188,21 @@    (maybe the middle of) E1->SRC to (may
 static bool
 try_crossjump_to_edge (int mode, edge e1, edge e2)
 {
-  int nmatch;
+  int nmatch, i;
   basic_block src1 = e1->src, src2 = e2->src;
   basic_block redirect_to, redirect_from, to_remove;
-  rtx newpos1, newpos2;
   edge s;
   edge_iterator ei;
-
-  newpos1 = newpos2 = NULL_RTX;
+  struct equiv_info info;
+  rtx x_active, y_active;
 
   /* If we have partitioned hot/cold basic blocks, it is a bad idea
-     to try this optimization. 
+     to try this optimization.
 
      Basic block partitioning may result in some jumps that appear to
-     be optimizable (or blocks that appear to be mergeable), but which really 
-     must be left untouched (they are required to make it safely across 
-     partition boundaries).  See the comments at the top of 
+     be optimizable (or blocks that appear to be mergeable), but which really
+     must be left untouched (they are required to make it safely across
+     partition boundaries).  See the comments at the top of
      bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
 
   if (flag_reorder_blocks_and_partition && no_new_pseudos)
@@ -1527,19 +1241,66 @@   if (EDGE_COUNT (src1->preds) == 0 || E
     return false;
 
   /* Look for the common insn sequence, part the first ...  */
-  if (!outgoing_edges_match (mode, src1, src2))
+  info.x_block = src2;
+  info.y_block = src1;
+  if (!outgoing_edges_match (&mode, &info))
     return false;
 
   /* ... and part the second.  */
-  nmatch = flow_find_cross_jump (mode, src1, src2, &newpos1, &newpos2);
+  info.input_cost = optimize_size ? COSTS_N_INSNS (1) : -1;
+  nmatch = struct_equiv_block_eq (STRUCT_EQUIV_START | mode, &info);
 
   /* Don't proceed with the crossjump unless we found a sufficient number
      of matching instructions or the 'from' block was totally matched
      (such that its predecessors will hopefully be redirected and the
      block removed).  */
-  if ((nmatch < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
-      && (newpos1 != BB_HEAD (src1)))
+  if (!nmatch)
     return false;
+  if ((nmatch -info.cur.input_count < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
+      && (info.cur.y_start != BB_HEAD (src1)))
+    return false;
+  while (info.need_rerun)
+    {
+      nmatch = struct_equiv_block_eq (STRUCT_EQUIV_RERUN | mode, &info);
+      if (!nmatch)
+	return false;
+      if ((nmatch -info.cur.input_count < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
+	   && (info.cur.y_start != BB_HEAD (src1)))
+	return false;
+    }
+  nmatch = struct_equiv_block_eq (STRUCT_EQUIV_FINAL | mode, &info);
+  if ((nmatch -info.cur.input_count < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
+      && (info.cur.y_start != BB_HEAD (src1)))
+    return false;
+
+  /* Skip possible basic block header.  */
+  x_active = info.cur.x_start;
+  if (LABEL_P (x_active))
+    x_active = NEXT_INSN (x_active);
+  if (NOTE_P (x_active))
+    x_active = NEXT_INSN (x_active);
+
+  y_active = info.cur.y_start;
+  if (LABEL_P (y_active))
+    y_active = NEXT_INSN (y_active);
+  if (NOTE_P (y_active))
+    y_active = NEXT_INSN (y_active);
+
+  /* In order for this code to become active, either we have to be called
+     before reload, or struct_equiv_block_eq needs to add register scavenging
+     code to allocate input_reg after reload.  */
+  if (info.input_reg)
+    {
+      emit_insn_before (gen_move_insn (info.input_reg, info.x_input),
+			x_active);
+      emit_insn_before (gen_move_insn (info.input_reg, info.y_input),
+			y_active);
+    }
+
+  for (i = 0; i < info.cur.local_count; i++)
+    if (info.local_rvalue[i])
+      emit_insn_before (gen_move_insn (info.x_local[i], info.y_local[i]),
+			y_active);
 
   /* Here we know that the insns in the end of SRC1 which are common with SRC2
      will be deleted.
@@ -1572,21 +1333,37 @@ 		for_each_rtx (&insn, replace_label, &r
 	}
     }
 
-  /* Avoid splitting if possible.  */
-  if (newpos2 == BB_HEAD (src2))
+  /* Avoid splitting if possible.  We must always split when SRC2 has
+     EH predecessor edges, or we may end up with basic blocks with both
+     normal and EH predecessor edges.  */
+  if (info.cur.x_start == BB_HEAD (src2)
+      && !(EDGE_PRED (src2, 0)->flags & EDGE_EH))
     redirect_to = src2;
   else
     {
+      if (info.cur.x_start == BB_HEAD (src2))
+	{
+	  /* Skip possible basic block header.  */
+	  if (LABEL_P (info.cur.x_start))
+	    info.cur.x_start = NEXT_INSN (info.cur.x_start);
+	  if (NOTE_P (info.cur.x_start))
+	    info.cur.x_start = NEXT_INSN (info.cur.x_start);
+	}
+
       if (dump_file)
 	fprintf (dump_file, "Splitting bb %i before %i insns\n",
 		 src2->index, nmatch);
-      redirect_to = split_block (src2, PREV_INSN (newpos2))->dest;
+      redirect_to = split_block (src2, PREV_INSN (info.cur.x_start))->dest;
     }
 
   if (dump_file)
-    fprintf (dump_file,
-	     "Cross jumping from bb %i to bb %i; %i common insns\n",
-	     src1->index, src2->index, nmatch);
+    {
+      fprintf (dump_file, "Cross jumping from bb %i to bb %i; %i common insns",
+	       src1->index, src2->index, nmatch);
+      if (info.cur.local_count)
+	fprintf (dump_file, ", %i local registers", info.cur.local_count);
+       fprintf (dump_file, "\n");
+    }
 
   redirect_to->count += src1->count;
   redirect_to->frequency += src1->frequency;
@@ -1650,17 +1427,12 @@   update_br_prob_note (redirect_to);
 
   /* Edit SRC1 to go to REDIRECT_TO at NEWPOS1.  */
 
-  /* Skip possible basic block header.  */
-  if (LABEL_P (newpos1))
-    newpos1 = NEXT_INSN (newpos1);
-
-  if (NOTE_P (newpos1))
-    newpos1 = NEXT_INSN (newpos1);
-
-  redirect_from = split_block (src1, PREV_INSN (newpos1))->src;
+  redirect_from = split_block (src1, PREV_INSN (y_active))->src;
   to_remove = single_succ (redirect_from);
 
   redirect_edge_and_branch_force (single_succ_edge (redirect_from), redirect_to);
+  COPY_REG_SET (redirect_from->il.rtl->global_live_at_end,
+		redirect_to->il.rtl->global_live_at_start);
   delete_basic_block (to_remove);
 
   update_forwarder_flag (redirect_from);
@@ -1675,7 +1447,7 @@     update_forwarder_flag (src2);
    any changes made.  */
 
 static bool
-try_crossjump_bb (int mode, basic_block bb)
+try_crossjump_bb (int mode, basic_block bb, bool first_pass)
 {
   edge e, e2, fallthru;
   bool changed;
@@ -1813,21 +1585,20 @@ 	  if (try_crossjump_to_edge (mode, e, e
 static bool
 try_optimize_cfg (int mode)
 {
+  bool first_crossjump_pass = true;
   bool changed_overall = false;
   bool changed;
+  bool changed_since_crossjump = true;
   int iterations = 0;
   basic_block bb, b, next;
 
-  if (mode & CLEANUP_CROSSJUMP)
-    add_noreturn_fake_exit_edges ();
-
   if (mode & (CLEANUP_UPDATE_LIFE | CLEANUP_CROSSJUMP | CLEANUP_THREADING))
     clear_bb_flags ();
 
   FOR_EACH_BB (bb)
     update_forwarder_flag (bb);
 
-  if (! targetm.cannot_modify_jumps_p ())
+  if (!targetm.cannot_modify_jumps_p ())
     {
       first_pass = true;
       /* Attempt to merge blocks as made possible by edge removal.  If
@@ -1982,11 +1753,6 @@ 		  update_forwarder_flag (b);
 	      if (try_forward_edges (mode, b))
 		changed_here = true;
 
-	      /* Look for shared code between blocks.  */
-	      if ((mode & CLEANUP_CROSSJUMP)
-		  && try_crossjump_bb (mode, b))
-		changed_here = true;
-
 	      /* Don't get confused by the index shift caused by
 		 deleting blocks.  */
 	      if (!changed_here)
@@ -1995,23 +1761,43 @@ 	      if (!changed_here)
 		changed = true;
 	    }
 
-	  if ((mode & CLEANUP_CROSSJUMP)
-	      && try_crossjump_bb (mode, EXIT_BLOCK_PTR))
-	    changed = true;
-
 #ifdef ENABLE_CHECKING
 	  if (changed)
 	    verify_flow_info ();
 #endif
 
+	  changed_since_crossjump |= changed;
+
+	  if ((mode & CLEANUP_CROSSJUMP)
+	      && changed_since_crossjump
+	      && !changed)
+	    {
+	      update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
+						(PROP_DEATH_NOTES
+						 | ((mode & CLEANUP_POST_REGSTACK)
+						    ? PROP_POST_REGSTACK : 0)));
+	      add_noreturn_fake_exit_edges ();
+
+	      for (b = ENTRY_BLOCK_PTR->next_bb; b != EXIT_BLOCK_PTR;)
+		{
+		  if (try_crossjump_bb (mode, b, first_crossjump_pass))
+		    changed = 1;
+		  else
+		    b = b->next_bb;
+		}
+	      changed |= try_crossjump_bb (mode, EXIT_BLOCK_PTR,
+					   first_crossjump_pass);
+	      remove_fake_exit_edges ();
+	      changed_since_crossjump = false;
+	      first_crossjump_pass = false;
+	    }
+
 	  changed_overall |= changed;
 	  first_pass = false;
 	}
       while (changed);
-    }
 
-  if (mode & CLEANUP_CROSSJUMP)
-    remove_fake_exit_edges ();
+    }
 
   FOR_ALL_BB (b)
     b->flags &= ~(BB_FORWARDER_BLOCK | BB_NONTHREADABLE_BLOCK);
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/cfgrtl.c gcc-4.1.1/gcc/cfgrtl.c
--- gcc-4.1.1.orig/gcc/cfgrtl.c	2006-01-23 10:01:36.000000000 +0000
+++ gcc-4.1.1/gcc/cfgrtl.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Control flow graph manipulation code for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -791,9 +792,10 @@       if (dump_file)
 	fprintf (dump_file, "Replacing insn %i by jump %i\n",
 		 INSN_UID (insn), INSN_UID (BB_END (src)));
 
-
       delete_insn_chain (kill_from, insn);
 
+      src->flags |= BB_DIRTY;
+
       /* Recognize a tablejump that we are converting to a
 	 simple jump and remove its associated CODE_LABEL
 	 and ADDR_VEC or ADDR_DIFF_VEC.  */
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/ChangeLog gcc-4.1.1/gcc/ChangeLog
--- gcc-4.1.1.orig/gcc/ChangeLog	2006-05-25 00:42:18.000000000 +0100
+++ gcc-4.1.1/gcc/ChangeLog	2006-08-10 09:56:05.000000000 +0100
@@ -1,4 +1,3 @@
-2006-05-24  Release Manager
 
 	* GCC 4.1.1 released.
 
@@ -8,6 +7,58 @@ 	* doc/install.texi (Configuration): Rem
 	FAQ which was hijacked.
 	(Building): Ditto.
 
+ *** patches from gcc-patches *** :
+
+http://gcc.gnu.org/ml/gcc-patches/2006-04/msg00194.html
+2006-04-05  Rask Ingemann Lambertsen <rask@sygehus.dk>
+            J"orn Rennecke <joern.rennecke@st.com>
+
+	* combine.c (likely_spilled_retval_1): Fix masking operation.
+	(likely_spilled_retval_p): Use proper pattern for call to
+	likely_spilled_retval_1.
+
+ *** Patches from mainline *** :
+
+2006-03-28  Kaz Kojima  <kkojima@gcc.gnu.org>
+
+	* config/sh/sh.md (udivsi3_i4_int): Clobber MACH_REG and MACL_REG.
+	(divsi3_i4_int): Likewise.
+
+2006-03-23  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/divtab-sh4.c, config/sh/divcost-analysis: New files.
+	* config/sh/lib1funcs.asm (div_table): Add !__SH5__ variant.
+	* config/sh/t-sh (LIB1ASMFUNCS): Add _div_table.
+	* config/sh/sh.opt (mdiv=): Amend description.
+	* config/sh/sh.h (TARGET_DIVIDE_CALL_DIV1): New macro.
+	(TARGET_DIVIDE_CALL_FP, TARGET_DIVIDE_CALL_TABLE): Likewise.
+	(sh_divide_strategy_e): Add new members SH_DIV_CALL_DIV1,
+	SH_DIV_CALL_FP, SH_DIV_CALL_TABLE and SH_DIV_INTRINSIC.
+	(OVERRIDE_OPTIONS): Also process sh_div_str for TARGET_SH1.
+	Calculate sh_divsi3_libfunc using TARGET_DIVIDE_* macros.
+	* config/sh/sh.md (udivsi3_i4_int, divsi3_i4_int): New patterns.
+	(udivsi3, divsi3): Use them.  Check TARGET_DIVIDE_CALL_TABLE /
+	TARGET_DIVIDE_CALL_FP.
+
+2006-03-15  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/predicates.md (cache_address_operand): Special.
+	(ua_address_operand): Likewise.
+
+2006-03-10  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config.gcc (sh*-superh-elf, sh*elf (newlib)): Use newlib.h
+	when building with libgloss.
+	(sh*elf): Implement --without-fp option.
+	(sh64-superh-linux*): Don't multilib. 
+
+2005-12-13  J"orn Rennecke <joern.rennecke@st.com>
+
+	* rtlhooks.c (gen_lowpart_general): Handle SUBREGs of floating point
+	values.
+
+ *** Patches from gcc 4.1 branch *** :
+
 2006-05-17  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* Makefile.in: Undo the last 2 changes.
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/ChangeLog.STM gcc-4.1.1/gcc/ChangeLog.STM
--- gcc-4.1.1.orig/gcc/ChangeLog.STM	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/ChangeLog.STM	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,524 @@
+2006-07-04  J"orn Rennecke  <joern.rennecke@st.com>
+
+	PR tree-optimization/28144
+	* fold-const.c (fold_convert_const_int_from_real): Fix endianness in
+	real_from_integer calls; adjust high word for lower bound.
+
+2006-07-04  Andrew Stubbs  <andrew.stubbs@st.com>
+
+	Fix INSbl24460:
+	* config/sh/crt1.asm (vbr_start): Move to new section .test.vbr.
+	Remove pointless handler at VBR+0.
+	(vbr_200, vbr_300, vbr_500): Remove pointless handler.
+	(vbr_600): Save and restore mach and macl, fpul and fpscr and fr0 to
+	fr7. Make sure the timer handler is called with the correct FPU
+	precision setting, according to the ABI.
+
+2006-06-23  J"orn Rennecke <joern.rennecke@st.com>
+
+	PR tree-optimization/28144
+	* fold-const.c (fold_convert_const_int_from_real): When converting
+	to a type with a precision less than 32, use INT_MIN / INT_MAX
+	for saturation bounds.
+
+2006-06-23  J"orn Rennecke <joern.rennecke@st.com>
+
+	* testsuite/g++.dg/eh/alias.C: New test.
+
+2006-06-14  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/sh.opt (m2a-single, m2a-single-only): Fix Condition.
+	* config/sh/sh.h (SUPPORT_SH2A_NOFPU): Fix condition.
+	(SUPPORT_SH2A_SINGLE_ONLY, SUPPORT_SH2A_SINGLE_ONLY): Likewise.
+
+2006-06-14  J"orn Rennecke <joern.rennecke@st.com>
+
+	* Makefile.in (version.o): Depend on $(OBJS) except for version.o .
+
+2006-06-13  J"orn Rennecke <joern.rennecke@st.com>
+
+	* t-sh (MULTILIB_MATCHES): Add and m4-100-nofpu,m4-200-nofpu.
+
+2006-06-09  J"orn Rennecke <joern.rennecke@st.com>
+
+	* sh.md (cmpgeusi_t): Change into define_insn_and_split.  Accept
+	zero as second operand.
+
+2006-06-08  J"orn Rennecke <joern.rennecke@st.com>
+
+	* longlong.h (__sh__ udiv_qrnnd): Add "pr" clobber.
+
+2006-06-07  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/lib1funcs.h (SL, SL1): Define.
+	* config/sh/lib1funcs.asm (__udiv_qrnnd16): Detect truncation-causes
+	overflow.
+
+2006-06-06  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/t-sh (LIB1ASMFUNCS): Add _udiv_qrnnd16
+	* config/sh/sh.c (print_operand): Add !SHMEDIA functionality to 'M'.
+	* config/sh/lib1funcs.asm (__udiv_qrnnd16): New hidden function.
+	* longlong.h (__sh__): Define umul_ppmm, udiv_qrnnd and sub_ddmmss.
+	* config/sh/t-sh ($(T)unwind-dw2-Os-4-200.o): New rule.
+	(OBJS_Os_4_200): New variable.
+	($(T)libgcc-Os-4-200.a): Use it.
+	* sh.md (udivsi3): For TARGET_DIVIDE_CALL_TABLE, avoid function call
+	when dividing 1.
+
+2006-05-09  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/sh.c (expand_cbranchdi4): Avoid calling
+	swap_condition (CODE_FOR_nothing).
+
+2006-05-03  Andrew Stubbs  <andrew.stubbs@st.com>
+            J"orn Rennecke <joern.rennecke@st.com>
+
+	* gcc.c (process_command): Try to set gcc_exec_prefix with
+	make_relative_prefix_ignore_links before resolving to
+	make_relative_prefix.
+	If gcc_exec_prefix has been pre-set, use
+	make_relative_prefix_ignore_links to calculate gcc_libexec_prefix.
+
+2006-04-28  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/divtab-sh4-300.c, config/sh/lib1funcs-4-300.asm:
+	Fixed some bugs related to nagative values, in particular -0
+	and overflow at -0x80000000.
+	* config/sh/divcost-analysis: added sh4-300 figures.
+	* testsuite/gcc.c-torture/execute/arith-rand-ll.c:
+	Also test for bogus rest sign.
+
+2006-04-27  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/t-sh (MULTILIB_MATCHES): Add -m4-300* / -m4-340 options.
+
+2006-04-27  J"orn Rennecke <joern.rennecke@st.com>
+
+	* builtins.c (get_pointer_alignment): Fix bug in last change.
+
+2006-04-26  J"orn Rennecke <joern.rennecke@st.com>
+
+	* sh.c (expand_cbranchdi4): Avoid generating >= 0U tests.
+
+2006-04-26  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/t-sh (OPT_EXTRA_PARTS): Add libgcc-4-300.a.
+	($(T)div_table-4-300.o, $(T)libgcc-4-300.a): New rules.
+	* config/sh/divtab-sh4-300.c, config/sh/lib1funcs-4-300.asm: New files.
+	* config/sh/embed-elf.h (LIBGCC_SPEC): Use -lgcc-4-300 for -m4-300* /
+	-m4-340.
+
+	* config/sh/sh.opt: Amend -mdiv= option description.
+
+2006-04-24  J"orn Rennecke <joern.rennecke@st.com>
+
+	* sh.md (mulr03, mulr03+1, mulr03+2): New patterns.
+	(mulsi3) Use mulr03 for TARGET_R0R3_TO_REG_MUL.
+	* sh.h (CONDITIONAL_REGISTER_USAGE): If -mr0r3-to-reg-mul is not in
+	effect, set regno_reg_class for R1_REG .. R3_REG to GENERAL_REGS.
+	(OVERRIDE_OPTIONS): Initilize TARGET_R0R3_TO_REG_MUL if it has
+	not been set by an option.
+	(enum reg_class, REG_CLASS_NAMES, REG_CLASS_CONTENTS): Add R0R3_REGS.
+	(REG_CLASS_FROM_CONSTRAINT): Decode R03.
+	* sh.opt (mlate-r0r3-to-reg-mul, mr0r3-to-reg-mul): New options.
+
+	SH4-300 scheduling description & fixes to SH4-[12]00 description:
+	* sh.md: New instruction types: fstore, movi8, fpscr_toggle, gp_mac,
+	mac_mem, mem_mac, dfp_mul, fp_cmp.
+	(insn_class, dfp_comp, any_fp_comp): Update.
+	(push_fpul, movsf_ie, fpu_switch, toggle_sz, toggle_pr): Update type.
+	(cmpgtsf_t, "cmpeqsf_t, cmpgtsf_t_i4, cmpeqsf_t_i4): Likewise.
+	(muldf3_i): Likewise.
+	(movsi_i): Split rI08 alternative into two separate alternatives.
+	Update type.
+	(movsi_ie, movsi_i_lowpart): Likewise.
+	(movqi_i): Split ri alternative into two separate alternatives.
+	Update type.
+	* sh1.md (sh1_load_store, sh1_fp): Update.
+	* sh4.md (sh4_store, sh4_mac_gp, fp_arith, fp_double_arith): Update.
+	(mac_mem, sh4_fpscr_toggle): New insn_reservations.
+	* sh4a.md (sh4a_mov, sh4a_load, sh4a_store, sh4a_fp_arith): Update.
+	(sh4a_fp_double_arith): Likewise.
+	* sh4-300.md: New file.
+	* sh.c (sh_handle_option): Handle m4-300* options.
+	(sh_adjust_cost): Fix latency of auto-increments.
+	Handle SH4-300 differently than other SH4s.  Check for new insn types.
+	* sh.h (OVERRIDE_OPTIONS): Initilize sh_branch_cost if it has not been
+	set by an option.
+	* sh.opt (m4-300, m4-100-nofpu, m4-200-nofpu): New options.
+	(m4-300-nofpu, -m4-340, m4-300-single, m4-300-single-only): Likewise.
+	(mbranch-cost=, mload-latency=): Likewise.
+	* superh.h (STARTFILE_SPEC): Take -m4-340 into account.
+
+	* sh.md (mulsf3): Remove special expansion code.
+	(mulsf3_ie): Now a define_insn_and_split.
+	(macsf3): Allow for TARGET_SH4.
+
+	* config/sh/predicates.md (less_comparison_operator): Remove
+	redundant code.
+
+	* sh.md (cbranchsi4, cbranchdi4, cbranchdi4_i): New patterns.
+	* sh.c (prepare_cbranch_operands, expand_cbranchsi4): New functions.
+	(expand_cbranchdi4): Likewise.
+	(sh_rtx_costs): Give lower cost for certain CONST_INT values and for
+	CONST_DOUBLE if the outer code is COMPARE.
+	* sh.h (OPTIMIZATION_OPTIONS): If not optimizing for size, set
+	TARGET_CBRANCHDI4 and TARGET_EXPAND_CBRANCHDI4.
+	(OVERRIDE_OPTIONS): For TARGET_SHMEDIA, clear TARGET_CBRANCHDI4.
+	(LEGITIMATE_CONSTANT_P): Also allow DImode and VOIDmode CONST_DOUBLEs.
+	Remove redundant fp_{zero,one}_operand checks.
+	* sh.opt (mcbranchdi, mexpand-cbranchdi, mcmpeqdi): New options.
+	* sh-protos.h (prepare_cbranch_operands, expand_cbranchsi4): Declare.
+	(expand_cbranchdi4): Likewise.
+
+2006-04-20  J"orn Rennecke <joern.rennecke@st.com>
+
+	PR middle-end/27226
+	* builtins.c (get_pointer_alignment): Use get_inner_reference.
+
+	* sh.h (LEGITIMATE_CONSTANT_P): Allow VOIDmode CONST_DOUBLEs.
+
+2006-04-20  J"orn Rennecke <joern.rennecke@st.com>
+
+	* sh.h (LOCAL_ALIGNMENT): Use DATA_ALIGNMENT.
+
+2006-04-11  J"orn Rennecke <joern.rennecke@st.com>
+
+	PR target/27060
+	http://gcc.gnu.org/ml/gcc-patches/2006-04/msg00412.html
+	* config/sh/lib1funcs.h: New file, broken out of:
+	* config/sh/lib1funcs.asm.
+	* config/sh/lib1funcs.h (DR00, DR01, DR20, DR21, DR40, DR41):
+	New macros.
+	* config/sh/lib1funcs.asm (udivsi3_i4): Use them.
+	* config/sh/lib1funcs-Os-4-200.asm: New file.
+	* config/sh/embed-elf.h (LIBGCC_SPEC): Use -lgcc-Os-4-200.
+	* config/sh/t-sh (OPT_EXTRA_PARTS): New variable.
+	(EXTRA_MULTILIB_PARTS): Include it.
+	($(T)sdivsi3_i4i-Os-4-200.o): New rule.
+	($(T)udivsi3_i4i-Os-4-200.o, $(T)libgcc-Os-4-200.a): Likewise.
+	* config/sh/t-superh (EXTRA_MULTILIB_PARTS): Include OPT_EXTRA_PARTS.
+	* config/sh/sh.h (OVERRIDE_OPTIONS): Recognize -mdiv=call-table for
+	TARGET_SH2.
+
+2006-04-11  J"orn Rennecke <joern.rennecke@st.com>
+
+	* gthr-generic.h: Update to match
+	http://gcc.gnu.org/ml/gcc-patches/2006-04/msg00237.html .
+	* gthr-generic.c, gthr-objc-generic.c: Likewise.
+	* Makefile.in configure.ac: Likewise.
+	* configure: Regenerate.
+
+2006-04-05  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/lib1funcs.h: New file, broken out of:
+	* config/sh/lib1funcs.asm.
+	* config/sh/lib1funcs-Os-4-200.asm: New file.
+
+2006-03-27  Andrew Stubbs  <andrew.stubbs@st.com>
+
+	* gcc.c (read_specs): Add Cygwin path support for MinGW.
+	(find_a_file, process_file): Likewise.
+	* opts.c (common_handle_option): Likewise.
+	* prefix.c (update_path): Likewise.
+	* c-opts.c (c_common_handle_option): Likewise.
+	(check_deps_environment_vars): Likewise.
+	* c-incpath.c (add_path): Likewise.
+	* collect2.c (find_a_file, add_prefix): Likewise.
+	* Makefile.in (INSTALL_HEADERS): Disable the broken install-mkheaders.
+
+2006-03-27  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/t-sh ($(T)libic_invalidate_array_4-100.a): Fix rule
+	to use lib prefix for target.
+	($(T)libic_invalidate_array_4-200.a): Likewise.
+	($(T)libic_invalidate_array_4a.a): Likewise.
+
+2006-03-24  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/superh.opt: New file.
+	* config/sh/sh.c (boardtype, osruntime): Remove.
+	* config/sh/superh.h (SUBTARGET_OPTIONS): Remove.
+	* config.gcc (sh*-superh-elf): Add sh/superh.opt to extra_options.
+
+2006-03-24  J"orn Rennecke <joern.rennecke@st.com>
+
+	* t-sh (IC_EXTRA_PARTS): Replace ic_invalidate_array_* parts with
+	libic_invalidate_array_* parts.  Rename affected rules.
+	* embed-elf.h (LIBGCC_SPEC): Update.
+
+2006-03-24  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config.gcc (sh*-*-*): Don't use c-c ranges for tr.  Quote sed
+	arguments with ^ and/or [].
+
+2006-03-23  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config.gcc (sh-*-*): Add quoting to account for quirk of
+	Solaris /bin/sh.
+	Replace == with = in enable_incomplete_targets test.
+
+	* configure.ac (extra_libgcc_srcs setting): Fix test to use test.
+	* configure: Regenrate.
+
+2006-03-22  J"orn Rennecke <joern.rennecke@st.com>
+
+	* superh.h (SUBTARGET_LINK_SPEC): Replace LITTLE_ENDIAN_BIT with
+	MASK_LITTLE_ENDIAN.
+
+2006-03-21  J"orn Rennecke <joern.rennecke@st.com>
+
+	* config.gcc (sh*-superh-elf): Add sh/superh.h to tm_file.
+	* config/sh/sh.opt: Added to some comments.
+	* config/sh/superh.h: Removed some chaff.
+
+2006-03-21  Andrew Stubbs <andrew.stubbs@st.com>
+	    J"orn Rennecke <joern.rennecke@st.com>
+
+	* config/sh/sh.opt: Add m4-[1234]00* options.
+	* config/sh/sh.c (sh_handle_option): Likewise.
+	* config/sh/t-sh (IC_EXTRA_PARTS, EXTRA_MULTILIB_PARTS): Define.
+	(ic_invalidate_array_4-100.o): New rule.
+	($(T)ic_invalidate_array_4-100.a): Likewise.
+	(ic_invalidate_array_4-200.o): Likewise.
+	($(T)ic_invalidate_array_4-200.a): Likewise.
+	* config/sh/t-elf (EXTRA_MULTILIB_PARTS): Add IC_EXTRA_PARTS.
+	* config/sh/embed-elf.h (LIBGCC_SPEC): Add clauses for m4-100*,
+	m4-200*, m4-300* and m4a*.
+	* config/sh/crt1.asm: Merged in profiling code.
+	* config/sh/superh.h (STARTFILE_SPEC): Override.
+	* config/sh/t-superh: Override EXTRA_MULTILIB_PARTS.
+	Add rules for $(T)crt1-mmu.o, $(T)gcrt1-mmu.o and $(T)gcrt1.o.
+	* config.gcc (sh*-superh-elf): Add t-superh to tmake_file.
+
+	* t-sh (MULTILIB_MATCHES): Add sh4-[1245]00* variants.
+	* config/sh/t-superh: Removed now-redundant MULTILIB_OPTIONS /
+	MULTILIB_DIRNAMES / MULTILIB_MATCHES settings.
+
+2006-03-21  J"orn Rennecke <joern.rennecke@st.com>
+
+	Apply patch to re-instate struct-equiv code for crossjump
+	matching:
+	http://gcc.gnu.org/ml/gcc-patches/2006-02/msg01488.html
+	Bernd Schmidt  <bernds@redhat.com>
+	* cfgcleanup.c
+	* cfgrtl.c
+	* cfgcleanup.c
+	* basic-block.h
+	* cfgcleanup.c
+	* struct-equiv.c
+
+2006-03-21  J"orn Rennecke <joern.rennecke@st.com>
+
+	* struct-equiv.c (note_local_live): Replace secondary_reload_class
+	call with SECONDARY_OUTPUT_RELOAD_CLASS use.
+
+2006-03-17  J"orn Rennecke <joern.rennecke@st.com>
+
+	* sh.opt (mpretend-cmove): New option.
+	* sh.h (OPERRIDE_OPTIONS): Switch it off if not TARGET_SH1.
+	* sh.md (movsicc_t_false, movsicc_t_tru): New patterns.
+	(movsicc): Add TARGET_PRETEND_CMOVE code.
+
+2006-03-15  J"orn Rennecke <joern.rennecke@st.com>
+
+	* version.c (VERSUFFIX, bug_report_url): Customize for STM.
+
+2006-03-10  J"orn Rennecke <joern.rennecke@st.com>
+
+	http://gcc.gnu.org/ml/gcc-patches/2006-03/msg00602.html
+	* regmove.c (init_add_limits): Check find_matches to verify a
+	three-address-add instruction is genuine.
+
+2006-03-10  J"orn Rennecke <joern.rennecke@st.com>
+            Zack Weinberg <zack@codesourcery.com>
+
+	http://gcc.gnu.org/ml/gcc-patches/2006-03/msg00598.html
+	* c-incpath.c (add_path): If HAVE_DOS_BASED_FILESYSTEM is defined,
+	remove any trailing slashes except for the first one after a colon.
+
+2006-03-09  J"orn Rennecke <joern.rennecke@st.com>
+
+	http://gcc.gnu.org/ml/gcc-patches/2006-03/msg00540.html
+	* struct-equiv.c (rtx_equiv_p): Fix POST_MODIFY case.
+
+2006-03-09  J"orn Rennecke <joern.rennecke@st.com>
+
+	Merge struct-equiv code from mainline:
+
+	2006-03-04  Kazu Hirata  <kazu@codesourcery.com>
+	  * struct-equiv.c: Fix comment typos.  Follow spelling conventions.
+	2006-01-12  Ulrich Weigand  <uweigand@de.ibm.com>
+	  * struct-equiv.c (find_dying_inputs): Fix off-by-one bug.
+	2005-12-19  J"orn Rennecke <joern.rennecke@st.com>
+	  * cfgcleanup.c: Temporarily revert patches for PR 20070 till Bernd
+	  comes back.
+	2005-12-19  J"orn Rennecke <joern.rennecke@st.com>
+	  * struct-equiv.c (struct_equiv_improve_checkpoint): Fix sets_cc0_p
+	  check.
+	2005-12-17  Kazu Hirata  <kazu@codesourcery.com>
+	  PR rtl-optimization/25456
+	  * struct-equiv.c (struct_equiv_improve_checkpoint): Replace
+	  info->x_start with p->x_start.
+	2005-12-16  Kazu Hirata  <kazu@codesourcery.com>
+	  * struct-equiv.c: Fix comment typos.
+	2005-12-14  J"orn Rennecke <joern.rennecke@st.com>
+	  * struct-equiv.c (note_local_live): Handle hard regs with different
+	  hard_regno_nregs.
+	2005-12-14  J"orn Rennecke <joern.rennecke@st.com>
+	  * struct-equiv.c (rtx_equiv_p): Allow arbitrary RVALUE values for
+	  PARALLELs with a mode.
+	2005-12-14  J"orn Rennecke <joern.rennecke@st.com>
+	  PR bootstrap/25397:
+	  * struct-equiv.c (struct_equiv_init): Fix off-by-one error in clearing
+	  of STACK_REGS bits.
+	  * struct-euiv.c (rtx_equiv_p): Remove SUBREG case.
+	2005-12-13  J"orn Rennecke <joern.rennecke@st.com>
+	  PR rtl-optimization/20070 / part1
+	  * flow.c (update_life_info): If PROP_POST_REGSTACK is set, call
+	  count_or_remove_death_notes with kill == -1.
+	  (mark_set_1): Don't add REG_DEAD / REG_UNUSED notes for stack
+	  registers if PROP_POST_REGSTACK is set.
+	  (mark_used_reg): Likewise.
+	  (count_or_remove_death_notes): If kill is -1, don't remove REG_DEAD /
+	  REG_UNUSED notes for stack regs.
+	  * cfgcleanup.c (condjump_equiv_p): Change parameters and processing
+	  to match rtx_equiv_p machinery.  Change caller.
+	  (outgoing_edges_match): Likewise.
+	  (try_crossjump_to_edge): Use struct_equiv_block_eq
+	  instead of flow_find_cross_jump.
+	  * basic-block.h (PROP_POST_REGSTACK, STRUCT_EQUIV_START): Define.
+	  (STRUCT_EQUIV_RERUN, STRUCT_EQUIV_FINAL): Likewise.
+	  (STRUCT_EQUIV_NEED_FULL_BLOCK, STRUCT_EQUIV_MATCH_JUMPS): Likewise.
+	  (STRUCT_EQUIV_MAX_LOCAL): Likewise.
+	  (struct struct_equiv_checkpoint, struct equiv_info): Likewise.
+	  (insns_match_p): Update prototype.
+	  (flow_find_cross_jump): Remove prototype.
+	  (struct_equiv_block_eq, struct_equiv_init): Declare.
+	  (rtx_equiv_p, condjump_equiv_p): Likewise.
+	  * struct-equiv.c: Include reload.h.
+	  (IMPOSSIBLE_MOVE_FACTOR): Define.
+	  (assign_reg_reg_set, struct_equiv_make_checkpoint): New functions.
+	  (struct_equiv_improve_checkpoint): Likewise.
+	  (struct_equiv_restore_checkpoint, rtx_equiv_p): Likewise.
+	  (set_dest_equiv_p, set_dest_addr_equiv_p, struct_equiv_init): Likewise.
+	  (struct_equiv_merge, find_dying_input): Likewise.
+	  (resolve_input_conflict, note_local_live): Likewise.
+	  (death_notes_match_p): Change parameters and processing
+	  to match rtx_equiv_p machinery.  Change caller.
+	  (insns_match_p): Likewise.
+	  (flow_find_cross_jump): Replace with:
+	  (struct_equiv_block_eq).
+	  Back out this change:
+	  2005-03-07  Kazu Hirata  <kazu@cs.umass.edu>
+	    * recog.c (verify_changes): Make it static.
+	    * recog.h: Remove the corresponding prototype.
+	2005-12-12  J"orn Rennecke <joern.rennecke@st.com>
+	  * cfgcleanup.c (condjump_equiv_p, try_crossjump_to_edge):
+	  Fix whitespace in vincinity of to-be-installed changes.
+	  * struct-equiv.c (merge_memattrs, death_notes_match_p): Fix whitespace.
+	  (insns_match_p): Likewise.
+	2005-12-07  J"orn Rennecke <joern.rennecke@st.com>
+	  Preparation for PR rtl-optimization/20070 / part1
+	  * basic-block.h (insns_match_p, flow_find_cross_jump): Declare.
+	  * cfgcleanup.c (condjump_equiv_p): New function, broken out of
+	  outgoing_edges_match.
+	  (outgoing_edges_match): Use condjump_equiv_p.
+	  (merge_memattrs, insns_match_p, flow_find_cross_jump): Move from here
+	  into..
+	  * struct-equiv.c: New file.
+	  (death_notes_match_p) New function, broken out of insns_match_p.
+	  * Makefile.in (OBJS-common): Add struct-equiv.o.
+	  (struct-equiv.o): New target.
+
+2006-03-09  J"orn Rennecke <joern.rennecke@st.com>
+
+	* configure.ac: Unset is_release.
+	* configure: Regenerate.
+
+2006-03-09  Andrew Stubbs <andrew.stubbs@st.com>
+	    J"orn Rennecke <joern.rennecke@st.com>
+
+	http://gcc.gnu.org/ml/gcc-patches/2006-03/msg00538.html
+	* configure.ac (.eh_frame data check): Use diff -b.
+	* configure: Regenerate.
+
+2006-01-20  J"orn Rennecke <joern.rennecke@st.com>
+
+	http://gcc.gnu.org/ml/gcc-patches/2006-01/msg01387.html
+	* postreload.c (reload_combine): For every new use of REG_SUM, record
+	the use of BASE.
+
+2006-01-17  Antony King <anthony.king@st.com>
+            J"orn Rennecke <joern.rennecke@st.com>
+
+	* configure.ac: Recognize 'generic' value for threads.
+	Check for existance of a *.c and gthr-objc-*.c file for thread support.
+	Substiture in extra_libgcc_srcs and extra_libgcc_static_srcs.
+	* configure: Regenerate.
+	* Makefile.in (LIB2ADD): Add @extra_libgcc_srcs@.
+	(LIB2ADD_ST): Add @extra_libgcc_static_srcs@.
+	* gthr-generic.h: New file.
+	* gthr-generic.c: New file.
+	* gthr-objc-generic.c: New file.
+
+2005-09-15  J"orn Rennecke <joern.rennecke@st.com>
+	    Bernd Schmidt  <bernds@redhat.com>
+
+	PR rtl-optimization/20211
+	http://gcc.gnu.org/ml/gcc-patches/2005-09/msg01176.html
+	* common.opt: Add optimize-related-values entry.
+	* opts.c (decode_options): Set flag_optimize_related_values.
+	* optabs.c (gen_add3_insn): If direct addition is not possible,
+	try to move the constant into the destination register first.
+	* regmove.c (obstack.h, ggc.h, optabs.h): Include.
+	(related, rel_use_chain, rel_mod, rel_use): New structures.
+	(related_baseinfo, update): Likewise.
+	(lookup_related, rel_build_chain): New functions.
+	(recognize_related_for_insn, record_reg_use, create_rel_use): Likewise.
+	(new_reg_use, rel_record_mem, new_base, invalidate_related): Likewise.
+	(find_related, find_related_toplev, chain_starts_earlier): Likewise.
+	(chain_ends_later, mod_before, remove_setting_insns): Likewise.
+	(perform_addition, modify_address): Likewise.
+	(optimize_related_values_1, optimize_related_values_0): Likewise.
+	(optimize_related_values, count_sets, link_chains): Likewise.
+	(init_add_limits): Likewise.
+	(REL_USE_HASH_SIZE, REL_USE_HASH, rel_alloc, rel_new): New macros.
+	(regno_related, rel_base_list, unrelatedly_used): New variables.
+	(related_obstack, add_limits): Likewise.
+	(regmove_optimize): Call optimize_related_values.
+	Include gt-regmove.h.
+	(have_3addr_const_add): New variable.
+	* Makefile.in (gt-regmove.h): New rule.
+	(regmove.o): Depend on $(OPTABS_H) and gt-regmove.h.
+	(GTFILES): Add regmove.c.
+	* doc/invoke.texi: Document -foptimize-related-values.
+
+2005-09-15  J"orn Rennecke <joern.rennecke@st.com>
+
+	* regmove.c (discover_flags_reg): Use the PATTERN of an INSN.
+
+	* regmove.c (fixup_match_1): When moving a death note, check if
+	it needs changing into a REG_UNUSED note.
+
+2005-06-02  J"orn Rennecke <joern.rennecke@st.com>
+
+	* sh.c (max_labelno_before_reorg): New variable.
+	(sh_reorg): Initialize it.
+	(find_barrier): Check max_labelno_before_reorg before using
+	label_to_alignment.  Take length of explicit alignment insns
+	into account.  When seeing a UNSPECV_CONST_END, return it.
+
+	* sh.c (fixup_mova): Set mode of affected label to QImode.
+	(untangle_mova): New function.
+	(find_barrier): Use it.  Check mode of label before decrementing
+	num_mova.
+	(sh_reorg): Likewise.
+	Set mode of all insns back to VOIDmode.
+
+	* sh.c (MOVA_LABELREF): New macro.
+	(mova_p, fixup_mova, sh_reorg): Use it.
+	(find_barrier, sh_reorg): Don't count num_mova back to 0 unless
+	ADDR_DIFF_VEC matches mova.
+
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/c-incpath.c gcc-4.1.1/gcc/c-incpath.c
--- gcc-4.1.1.orig/gcc/c-incpath.c	2005-06-25 03:02:01.000000000 +0100
+++ gcc-4.1.1/gcc/c-incpath.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Set up combined include path chain for the preprocessor.
    Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
    Broken out of cppinit.c and cppfiles.c and rewritten Mar 2003.
 
@@ -338,8 +339,23 @@      trailing or otherwise, cause no pro
   char* c;
   for (c = path; *c; c++)
     if (*c == '\\') *c = '/';
+
+/* The native stat() on NT4 accepts trailing slashes, but not
+    backslashes.  Mingw's stat on Windows 2000/XP doesn't accept
+    either trailing slashes or backslashes.  (C:/ and C:\ are of
+    course fine.)  It is harmless to remove trailing slashes on
+    systems that do accept them, so we do it unconditionally.  */
+  while (c > path+1 && c[-1] == '/')
+    c--;
+  if (c == path+2 
+      && ISALPHA (path[0]) && path[1] == ':' && path[2] == '/')
+    c++;
+  if (*c == '/')
+    *c = '\0';
 #endif
 
+  CYGPATH_REPLACE (&path);
+
   p = xmalloc (sizeof (cpp_dir));
   p->next = NULL;
   p->name = path;
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/collect2.c gcc-4.1.1/gcc/collect2.c
--- gcc-4.1.1.orig/gcc/collect2.c	2005-08-19 02:20:34.000000000 +0100
+++ gcc-4.1.1/gcc/collect2.c	2006-08-10 09:56:05.000000000 +0100
@@ -5,6 +5,7 @@    Copyright (C) 1992, 1993, 1994, 1995,
    Contributed by Chris Smith (csmith@convex.com).
    Heavily modified by Michael Meissner (meissner@cygnus.com),
    Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com).
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -570,7 +571,10 @@ find_a_file (struct path_prefix *pprefix
 {
   char *temp;
   struct prefix_list *pl;
-  int len = pprefix->max_len + strlen (name) + 1;
+  int len;
+
+  CYGPATH (name);
+  len = pprefix->max_len + strlen (name) + 1;
 
   if (debug)
     fprintf (stderr, "Looking for '%s'\n", name);
@@ -596,6 +600,7 @@ 	  strcpy (temp, name);
 	  if (debug)
 	    fprintf (stderr, "  - found: absolute path\n");
 
+	  CYGPATH_FREE (name);
 	  return temp;
 	}
 
@@ -606,7 +611,10 @@       strcpy (temp, name);
 	strcat (temp, HOST_EXECUTABLE_SUFFIX);
 
 	if (access (temp, X_OK) == 0)
-	  return temp;
+	  {
+	    CYGPATH_FREE (name);
+	    return temp;
+	  }
 #endif
 
       if (debug)
@@ -623,7 +631,10 @@ 	strcat (temp, name);
 	if (stat (temp, &st) >= 0
 	    && ! S_ISDIR (st.st_mode)
 	    && access (temp, X_OK) == 0)
-	  return temp;
+	  {
+	    CYGPATH_FREE (name);
+	    return temp;
+	  }
 
 #ifdef HOST_EXECUTABLE_SUFFIX
 	/* Some systems have a suffix for executable files.
@@ -633,7 +644,10 @@ 	strcat (temp, HOST_EXECUTABLE_SUFFIX);
 	if (stat (temp, &st) >= 0
 	    && ! S_ISDIR (st.st_mode)
 	    && access (temp, X_OK) == 0)
-	  return temp;
+	  {
+	    CYGPATH_FREE (name);
+	    return temp;
+	  }
 #endif
       }
 
@@ -641,6 +655,7 @@   if (debug && pprefix->plist == NULL)
     fprintf (stderr, "  - failed: no entries in prefix list\n");
 
   free (temp);
+  CYGPATH (name);
   return 0;
 }
 
@@ -663,6 +678,7 @@       for (pl = pprefix->plist; pl->next
 
   /* Keep track of the longest prefix.  */
 
+  CYGPATH (prefix);
   len = strlen (prefix);
   if (len > pprefix->max_len)
     pprefix->max_len = len;
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/combine.c gcc-4.1.1/gcc/combine.c
--- gcc-4.1.1.orig/gcc/combine.c	2006-02-24 01:37:22.000000000 +0000
+++ gcc-4.1.1/gcc/combine.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Optimize by combining instructions for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -1601,7 +1602,7 @@   if (regno < info->regno)
     new_mask >>= info->regno - regno;
   else
     new_mask <<= regno - info->regno;
-  info->mask &= new_mask;
+  info->mask &= ~new_mask;
 }
 
 /* Return nonzero iff part of the return value is live during INSN, and
@@ -1637,7 +1638,8 @@   mask = (2U << (nregs - 1)) - 1;
   info.nregs = nregs;
   info.mask = mask;
   for (p = PREV_INSN (use); info.mask && p != insn; p = PREV_INSN (p))
-    note_stores (PATTERN (insn), likely_spilled_retval_1, &info);
+    if (INSN_P (p))
+      note_stores (PATTERN (p), likely_spilled_retval_1, &info);
   mask = info.mask;
 
   /* Check if any of the (probably) live return value registers is
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/common.opt gcc-4.1.1/gcc/common.opt
--- gcc-4.1.1.orig/gcc/common.opt	2006-05-17 19:38:58.000000000 +0100
+++ gcc-4.1.1/gcc/common.opt	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 ; Options for the language- and target-independent parts of the compiler.
 
 ; Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+; Copyright (c) 2006  STMicroelectronics.
 ;
 ; This file is part of GCC.
 ;
@@ -606,6 +607,10 @@ foptimize-register-move
 Common Report Var(flag_regmove)
 Do the full register move optimization pass
 
+foptimize-related-values
+Common Report Var(flag_optimize_related_values)
+Enable additional regmove optimization for base reg + offset expressions
+
 foptimize-sibling-calls
 Common Report Var(flag_optimize_sibling_calls)
 Optimize sibling and tail recursive calls
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/crt1.asm gcc-4.1.1/gcc/config/sh/crt1.asm
--- gcc-4.1.1.orig/gcc/config/sh/crt1.asm	2005-06-25 02:22:41.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/crt1.asm	2006-08-10 09:56:05.000000000 +0100
@@ -1,5 +1,6 @@
 /* Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
    This file was pretty much copied from newlib.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -688,6 +689,11 @@ 	! this will only have a value if it has
 	.section .bss
 old_vbr:
 	.long 0
+#ifdef PROFILE
+profiling_enabled:
+	.long 0
+#endif
+
 
 	.section .text
 	.global	start
@@ -764,6 +770,30 @@ 	! Set status register (sr)
 	jsr	@r0
 	nop
 
+#ifdef PROFILE
+	! arrange for exit to call _mcleanup (via stop_profiling)
+	mova    stop_profiling,r0
+	mov.l   atexit_k,r1
+	jsr     @r1
+	mov	r0, r4
+
+	! Call profiler startup code
+	mov.l monstartup_k, r0
+	mov.l start_k, r4
+	mov.l etext_k, r5
+	jsr @r0
+	nop
+
+	! enable profiling trap
+	! until now any trap 33s will have been ignored
+	! This means that all library functions called before this point
+	! (directly or indirectly) may have the profiling trap at the start.
+	! Therefore, only mcount itself may not have the extra header.
+	mov.l	profiling_enabled_k2, r0
+	mov	#1, r1
+	mov.l	r1, @r0
+#endif /* PROFILE */
+
 	! call init
 	mov.l	init_k,r0
 	jsr	@r0
@@ -780,6 +810,32 @@ 	! Set status register (sr)
 	jsr	@r0
 	nop
 	
+		.balign 4
+#ifdef PROFILE
+stop_profiling:
+	# stop mcount counting
+	mov.l	profiling_enabled_k2, r0
+	mov	#0, r1
+	mov.l	r1, @r0
+
+	# call mcleanup
+	mov.l	mcleanup_k, r0
+	jmp	@r0
+	nop
+		
+		.balign 4
+mcleanup_k:
+	.long __mcleanup
+monstartup_k:
+	.long ___monstartup
+profiling_enabled_k2:
+	.long profiling_enabled
+start_k:
+	.long _start
+etext_k:
+	.long __etext
+#endif /* PROFILE */
+
 	.align 2
 #if defined (__SH_FPU_ANY__)
 set_fpscr_k:
@@ -818,10 +874,18 @@ sr_initial_rtos:
 rtos_start_fn:
 	.long ___rtos_profiler_start_timer
 	
+#ifdef PROFILE
+sr_initial_bare:
+	! Privileged mode RB 1 BL 0. Keep BL 0 to allow default trap handlers to work.
+	! For bare machine, we need to enable interrupts to get profiling working
+	.long 0x60000001
+#else
+
 sr_initial_bare:
 	! Privileged mode RB 1 BL 0. Keep BL 0 to allow default trap handlers to work.
 	! Keep interrupts disabled - the application will enable as required.
 	.long 0x600000f1
+#endif
 
 	! supplied for backward compatibility only, in case of linking
 	! code whose main() was compiled with an older version of GCC.
@@ -831,66 +895,99 @@ ___main:
 	nop
 #ifdef VBR_SETUP
 ! Exception handlers	
-	.balign 256
+	.section .text.vbr, "ax"
 vbr_start:
-	mov.l 2f, r0     ! load the old vbr setting (if any)
-	mov.l @r0, r0
-	cmp/eq #0, r0
-	bf 1f
-	! no previous vbr - jump to own generic handler
-	bra handler
-	nop
-1:	! there was a previous handler - chain them
-	jmp @r0
-	nop
-	.balign 4
-2:
-	.long old_vbr
 
-	.balign 256
+	.org 0x100
 vbr_100:
-	! Non profiling case.
-handler_100:
-	mov.l 2f, r0     ! load the old vbr setting (if any)
+	#ifdef PROFILE
+	! Note on register usage.
+	! we use r0..r3 as scratch in this code. If we are here due to a trapa for profiling
+	! then this is OK as we are just before executing any function code.
+	! The other r4..r7 we save explicityl on the stack
+	! Remaining registers are saved by normal ABI conventions and we assert we do not
+	! use floating point registers.
+	mov.l expevt_k1, r1
+	mov.l @r1, r1
+	mov.l event_mask, r0
+	and r0,r1
+	mov.l trapcode_k, r2
+	cmp/eq r1,r2
+	bt 1f
+	bra handler_100   ! if not a trapa, go to default handler
+	nop
+1:	
+	mov.l trapa_k, r0
 	mov.l @r0, r0
-	cmp/eq #0, r0
-	bf 1f
-	! no previous vbr - jump to own generic handler
-	bra handler
-	nop	
-1:	! there was a previous handler - chain them
-	add #0x7f, r0	 ! 0x7f
-	add #0x7f, r0	 ! 0xfe
-	add #0x2, r0     ! add 0x100 without corrupting another register
-	jmp @r0
+	shlr2 r0      ! trapa code is shifted by 2.
+	cmp/eq #33, r0
+	bt 2f
+	bra handler_100
 	nop
-	.balign 4
 2:	
-	.long old_vbr
+	
+	! If here then it looks like we have trap #33
+	! Now we need to call mcount with the following convention
+	! Save and restore r4..r7
+	mov.l	r4,@-r15
+	mov.l	r5,@-r15
+	mov.l	r6,@-r15
+	mov.l	r7,@-r15
+	sts.l	pr,@-r15
 
-	.balign 256
-vbr_200:
-	mov.l 2f, r0     ! load the old vbr setting (if any)
+	! r4 is frompc.
+	! r5 is selfpc
+	! r0 is the branch back address.
+	! The code sequence emitted by gcc for the profiling trap is
+	! .align 2
+	! trapa #33
+	! .align 2
+	! .long lab Where lab is planted by the compiler. This is the address
+	! of a datum that needs to be incremented. 
+	sts pr,  r4     ! frompc
+	stc spc, r5	! selfpc
+	mov #2, r2
+	not r2, r2      ! pattern to align to 4
+	and r2, r5      ! r5 now has aligned address
+!	add #4, r5      ! r5 now has address of address
+	mov r5, r2      ! Remember it.
+!	mov.l @r5, r5   ! r5 has value of lable (lab in above example)
+	add #8, r2
+	ldc r2, spc     ! our return address avoiding address word
+
+	! only call mcount if profiling is enabled
+	mov.l profiling_enabled_k, r0
 	mov.l @r0, r0
 	cmp/eq #0, r0
-	bf 1f
-	! no previous vbr - jump to own generic handler
-	bra handler
-	nop	
-1:	! there was a previous handler - chain them
-	add #0x7f, r0	 ! 0x7f
-	add #0x7f, r0	 ! 0xfe
-	add #0x7f, r0	 ! 0x17d
-	add #0x7f, r0    ! 0x1fc
-	add #0x4, r0     ! add 0x200 without corrupting another register
-	jmp @r0
+	bt 3f
+	! call mcount
+	mov.l mcount_k, r2
+	jsr @r2
+	nop
+3:
+	lds.l @r15+,pr
+	mov.l @r15+,r7
+	mov.l @r15+,r6
+	mov.l @r15+,r5
+	mov.l @r15+,r4
+	rte
 	nop
 	.balign 4
-2:
-	.long old_vbr
-
-	.balign 256
-vbr_300:
+event_mask:
+	.long 0xfff
+trapcode_k:	
+	.long 0x160
+expevt_k1:
+	.long 0xff000024 ! Address of expevt
+trapa_k:	
+	.long 0xff000020
+mcount_k:
+	.long __call_mcount
+profiling_enabled_k:
+	.long profiling_enabled
+#endif
+	! Non profiling case.
+handler_100:
 	mov.l 2f, r0     ! load the old vbr setting (if any)
 	mov.l @r0, r0
 	cmp/eq #0, r0
@@ -901,18 +998,14 @@ 	mov.l 2f, r0     ! load the old vbr set
 1:	! there was a previous handler - chain them
 	add #0x7f, r0	 ! 0x7f
 	add #0x7f, r0	 ! 0xfe
-	add #0x7f, r0	 ! 0x17d
-	add #0x7f, r0    ! 0x1fc
-	add #0x7f, r0	 ! 0x27b
-	add #0x7f, r0    ! 0x2fa
-	add #0x6, r0     ! add 0x300 without corrupting another register
+	add #0x2, r0     ! add 0x100 without corrupting another register
 	jmp @r0
 	nop
 	.balign 4
-2:
+2:	
 	.long old_vbr
 
-	.balign 256	
+	.org 0x400
 vbr_400:	! Should be at vbr+0x400
 	mov.l 2f, r0     ! load the old vbr setting (if any)
 	mov.l @r0, r0
@@ -920,15 +1013,13 @@ 	mov.l 2f, r0     ! load the old vbr set
 	! no previous vbr - jump to own generic handler
 	bt handler
 	! there was a previous handler - chain them
-	add #0x7f, r0	 ! 0x7f
-	add #0x7f, r0	 ! 0xfe
-	add #0x7f, r0	 ! 0x17d
-	add #0x7f, r0    ! 0x1fc
-	add #0x7f, r0	 ! 0x27b
-	add #0x7f, r0    ! 0x2fa
-	add #0x7f, r0	 ! 0x379
-	add #0x7f, r0    ! 0x3f8
-	add #0x8, r0     ! add 0x400 without corrupting another register
+	rotcr r0
+	rotcr r0
+	add #0x7f, r0	 ! 0x1fc
+	add #0x7f, r0	 ! 0x3f8
+	add #0x02, r0	 ! 0x400
+	rotcl r0
+	rotcl r0	 ! Add 0x400 without corrupting another register
 	jmp @r0
 	nop
 	.balign 4
@@ -957,57 +1048,102 @@ handler:
 	jmp @r2
 	nop
 
-	.balign 256
-vbr_500:
-	mov.l 2f, r0     ! load the old vbr setting (if any)
-	mov.l @r0, r0
-	cmp/eq #0, r0
-	! no previous vbr - jump to own generic handler
-	bt handler
-	! there was a previous handler - chain them
-	add #0x7f, r0	 ! 0x7f
-	add #0x7f, r0	 ! 0xfe
-	add #0x7f, r0	 ! 0x17d
-	add #0x7f, r0    ! 0x1fc
-	add #0x7f, r0	 ! 0x27b
-	add #0x7f, r0    ! 0x2fa
-	add #0x7f, r0	 ! 0x379
-	add #0x7f, r0    ! 0x3f8
-	add #0x7f, r0	 ! 0x477
-	add #0x7f, r0    ! 0x4f6
-	add #0xa, r0     ! add 0x500 without corrupting another register
-	jmp @r0
+	.org 0x600
+vbr_600:
+#ifdef PROFILE	
+	! Should be at vbr+0x600
+	! Now we are in the land of interrupts so need to save more state. 
+	! Save register state
+	mov.l interrupt_stack_k, r15 ! r15 has been saved to sgr.
+	mov.l	r0,@-r15	
+	mov.l	r1,@-r15
+	mov.l	r2,@-r15
+	mov.l	r3,@-r15
+	mov.l	r4,@-r15
+	mov.l	r5,@-r15
+	mov.l	r6,@-r15
+	mov.l	r7,@-r15
+	sts.l	pr,@-r15
+	sts.l	mach,@-r15
+	sts.l	macl,@-r15
+#if defined(__SH_FPU_ANY__)
+	! Save fpul and fpscr, save fr0-fr7 in 64 bit mode
+	! and set the pervading precision for the timer_handler
+	mov	#0,r0
+	sts.l	fpul,@-r15
+	sts.l	fpscr,@-r15
+	lds	r0,fpscr	! Clear fpscr
+	fmov	fr0,@-r15
+	fmov	fr1,@-r15
+	fmov	fr2,@-r15
+	fmov	fr3,@-r15
+	mov.l	pervading_precision_k,r0
+	fmov	fr4,@-r15
+	fmov	fr5,@-r15
+	mov.l	@r0,r0
+	fmov	fr6,@-r15
+	fmov	fr7,@-r15
+	lds	r0,fpscr
+#endif /* __SH_FPU_ANY__ */
+	! Pass interrupted pc to timer_handler as first parameter (r4).
+	stc    spc, r4
+	mov.l timer_handler_k, r0
+	jsr @r0
+	nop
+#if defined(__SH_FPU_ANY__)
+	mov	#0,r0
+	lds	r0,fpscr	! Clear the fpscr
+	fmov	@r15+,fr7
+	fmov	@r15+,fr6
+	fmov	@r15+,fr5
+	fmov	@r15+,fr4
+	fmov	@r15+,fr3
+	fmov	@r15+,fr2
+	fmov	@r15+,fr1
+	fmov	@r15+,fr0
+	lds.l	@r15+,fpscr
+	lds.l	@r15+,fpul
+#endif /* __SH_FPU_ANY__ */
+	lds.l @r15+,macl
+	lds.l @r15+,mach
+	lds.l @r15+,pr
+	mov.l @r15+,r7
+	mov.l @r15+,r6
+	mov.l @r15+,r5
+	mov.l @r15+,r4
+	mov.l @r15+,r3
+	mov.l @r15+,r2
+	mov.l @r15+,r1
+	mov.l @r15+,r0
+	stc sgr, r15    ! Restore r15, destroyed by this sequence. 
+	rte
 	nop
 	.balign 4
-2:
-	.long old_vbr
-
-	.balign 256
-vbr_600:
-	mov.l 2f, r0     ! load the old vbr setting (if any)
+pervading_precision_k:
+#define CONCAT1(A,B) A##B
+#define CONCAT(A,B) CONCAT1(A,B)
+	.long CONCAT(__USER_LABEL_PREFIX__,__fpscr_values)+4
+#else
+	mov.l 2f, r0     ! Load the old vbr setting (if any).
 	mov.l @r0, r0
 	cmp/eq #0, r0
 	! no previous vbr - jump to own handler
 	bt chandler
 	! there was a previous handler - chain them
-	add #0x7f, r0	 ! 0x7f
-	add #0x7f, r0	 ! 0xfe
-	add #0x7f, r0	 ! 0x17d
-	add #0x7f, r0    ! 0x1fc
-	add #0x7f, r0	 ! 0x27b
-	add #0x7f, r0    ! 0x2fa
-	add #0x7f, r0	 ! 0x379
-	add #0x7f, r0    ! 0x3f8
-	add #0x7f, r0	 ! 0x477
-	add #0x7f, r0    ! 0x4f6
-	add #0x7f, r0	 ! 0x575
-	add #0x7f, r0    ! 0x5f4
-	add #0xc, r0     ! add 0x600 without corrupting another register
+	rotcr r0
+	rotcr r0
+	add #0x7f, r0	 ! 0x1fc
+	add #0x7f, r0	 ! 0x3f8
+	add #0x7f, r0	 ! 0x5f4
+	add #0x03, r0	 ! 0x600
+	rotcl r0
+	rotcl r0	 ! Add 0x600 without corrupting another register
 	jmp @r0
 	nop
 	.balign 4
 2:
 	.long old_vbr
+#endif	 /* PROFILE code */
 chandler:
 	mov.l expevt_k, r4
 	mov.l @r4, r4 ! r4 is value of expevt hence making this the return code
@@ -1020,6 +1156,12 @@ limbo:
 	bra limbo
 	nop
 	.balign 4
+#ifdef PROFILE
+interrupt_stack_k:
+	.long __timer_stack	! The high end of the stack
+timer_handler_k:
+	.long __profil_counter
+#endif
 expevt_k:
 	.long 0xff000024 ! Address of expevt
 chandler_k:	
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/divcost-analysis gcc-4.1.1/gcc/config/sh/divcost-analysis
--- gcc-4.1.1.orig/gcc/config/sh/divcost-analysis	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/divcost-analysis	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,81 @@
+Analysis of cycle costs for SH4:
+
+-> udiv_le128:            5
+-> udiv_ge64k:            6
+-> udiv udiv_25:         10
+-> pos_divisor:           3
+-> pos_result linear:     5
+-> pos_result - -:        5
+-> div_le128:             7
+-> div_ge64k:             9
+sdivsi3 -> udiv_25             13
+udiv25 -> div_ge64k_end:       15
+div_ge64k_end -> rts:          13
+div_le128 -> div_le128_2:       2, r1 latency 3
+udiv_le128 -> div_le128_2:      2, r1 latency 3
+(u)div_le128 -> div_by_1:       9
+(u)div_le128 -> rts:           17
+div_by_1(_neg) -> rts:          4
+div_ge64k -> div_r8:            2
+div_ge64k -> div_ge64k_2:       3
+udiv_ge64k -> udiv_r8:          3
+udiv_ge64k -> div_ge64k_2:      3 + LS
+(u)div_ge64k -> div_ge64k_end: 13
+div_r8 -> div_r8_2:             2
+udiv_r8 -> div_r8_2:            2 + LS
+(u)div_r8 -> rts:              21
+
+-> - + neg_result:             5
+-> + - neg_result:             5
+-> div_le128_neg:              7
+-> div_ge64k_neg:              9
+-> div_r8_neg:                11
+-> <64k div_ge64k_neg_end:    28
+-> >=64k div_ge64k_neg_end:   22
+div_ge64k_neg_end ft -> rts:  14
+div_r8_neg_end -> rts:         4
+div_r8_neg -> div_r8_neg_end: 18
+div_le128_neg -> div_by_1_neg: 4
+div_le128_neg -> rts          18
+
+         sh4-200    absolute divisor range:
+            1  [2..128]  [129..64K) [64K..|divident|/256] >=64K,>|divident/256|
+udiv       18     22         38            32                   30
+sdiv pos:  20     24         41            35                   32
+sdiv neg:  15     25         42            36                   33
+
+         sh4-300    absolute divisor range:
+                 8 bit      16 bit       24 bit              > 24 bit
+udiv              15         35            28                   25
+sdiv              14         36            34                   31
+
+
+fp-based:
+
+unsigned: 42 + 3 + 3 (lingering ftrc latency + sts fpul,rx) at caller's site
+signed: 33 + 3 + 3 (lingering ftrc latency + sts fpul,rx) at caller's site
+
+call-div1:    divisor range:
+              [1..64K)  >= 64K
+unsigned:       63        58
+signed:         76        76
+
+SFUNC_STATIC call overhead:
+mov.l 0f,r1
+bsrf r1
+
+SFUNC_GOT call overhead - current:
+mov.l 0f,r1
+mova 0f,r0
+mov.l 1f,r2
+add r1,r0
+mov.l @(r0,r2),r0
+jmp @r0
+; 3 cycles worse than SFUNC_STATIC
+
+SFUNC_GOT call overhead - improved assembler:
+mov.l 0f,r1
+mova 0f,r0
+mov.l @(r0,r1),r0
+jmp @r0
+; 2 cycles worse than SFUNC_STATIC
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/divtab-sh4-300.c gcc-4.1.1/gcc/config/sh/divtab-sh4-300.c
--- gcc-4.1.1.orig/gcc/config/sh/divtab-sh4-300.c	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/divtab-sh4-300.c	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,82 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2006 STMicroelectronics
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Calculate division table for ST40-300 integer division
+   Contributed by Joern Rernnecke
+   joern.rennecke@st.com  */
+
+#include <stdio.h>
+#include <math.h>
+
+int
+main ()
+{
+  int i, j;
+  double q, r, err, max_err = 0, max_s_err = 0;
+
+  puts("/* This table has been generated by divtab-sh4.c.  */");
+  puts ("\t.balign 4");
+  for (i = -128; i < 128; i++)
+    {
+      int n = 0;
+      if (i == 0)
+	{
+	  /* output some dummy number for 1/0.  */
+	  puts ("LOCAL(div_table_clz):\n\t.byte\t0");
+	  continue;
+	}
+      for (j = i < 0 ? -i : i; j < 128; j += j)
+	n++;
+      printf ("\t.byte\t%d\n", n - 7);
+    }
+  puts("\
+/* 1/-128 .. 1/127, normalized.  There is an implicit leading 1 in bit 32,\n\
+   or in bit 33 for powers of two.  */\n\
+	.balign 4");
+  for (i = -128; i < 128; i++)
+    {
+      if (i == 0)
+	{
+	  puts ("LOCAL(div_table_inv):\n\t.long\t0x0");
+	  continue;
+	}
+      j = i < 0 ? -i : i;
+      while (j < 64)
+	j += j;
+      q = 4.*(1<<30)*128/j;
+      r = ceil (q);
+      printf ("\t.long\t0x%X\n", (unsigned) r);
+      err = r - q;
+      if (err > max_err)
+	max_err = err;
+      err = err * j / 128;
+      if (err > max_s_err)
+	max_s_err = err;
+    }
+  printf ("\t/* maximum error: %f scaled: %f*/\n", max_err, max_s_err);
+  exit (0);
+}
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/divtab-sh4.c gcc-4.1.1/gcc/config/sh/divtab-sh4.c
--- gcc-4.1.1.orig/gcc/config/sh/divtab-sh4.c	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/divtab-sh4.c	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,91 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Calculate division table for SH2..4 integer division
+   Contributed by Joern Rernnecke
+   joern.rennecke@superh.com  */
+
+#include <stdio.h>
+#include <math.h>
+
+int
+main ()
+{
+  int i, j;
+  double q, r, err, max_err = 0, max_s_err = 0;
+
+  puts("/* This table has been generated by divtab-sh4.c.  */");
+  puts ("\t.balign 4");
+  puts ("LOCAL(div_table_clz):");
+  /* output some dummy number for 1/0.  */
+  printf ("\t.byte\t%d\n", 0);
+  for (i = 1; i <= 128; i++)
+    {
+      int n = 0;
+      if (i == 128)
+	puts ("\
+/* Lookup table translating positive divisor to index into table of\n\
+   normalized inverse.  N.B. the '0' entry is also the last entry of the\n\
+ previous table, and causes an unaligned access for division by zero.  */\n\
+LOCAL(div_table_ix):");
+      for (j = i; j <= 128; j += j)
+	n++;
+      printf ("\t.byte\t%d\n", n - 7);
+    }
+  for (i = 1; i <= 128; i++)
+    {
+      j = i < 0 ? -i : i;
+      while (j < 128)
+	j += j;
+      printf ("\t.byte\t%d\n", j * 2 - 96*4);
+    }
+  puts("\
+/* 1/64 .. 1/127, normalized.  There is an implicit leading 1 in bit 32.  */\n\
+	.balign 4\n\
+LOCAL(zero_l):");
+  for (i = 64; i < 128; i++)
+    {
+      if (i == 96)
+	puts ("LOCAL(div_table):");
+      q = 4.*(1<<30)*128/i;
+      r = ceil (q);
+      /* The value for 64 is actually differently scaled that it would
+	 appear from this calculation.  The implicit part is %01, not 10.
+	 Still, since the value in the table is 0 either way, this
+	 doesn't matter here.  Still, the 1/64 entry is effectively a 1/128
+	 entry.  */
+      printf ("\t.long\t0x%X\n", (unsigned) r);
+      err = r - q;
+      if (err > max_err)
+	max_err = err;
+      err = err * i / 128;
+      if (err > max_s_err)
+	max_s_err = err;
+    }
+  printf ("\t/* maximum error: %f scaled: %f*/\n", max_err, max_s_err);
+  exit (0);
+}
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/embed-elf.h gcc-4.1.1/gcc/config/sh/embed-elf.h
--- gcc-4.1.1.orig/gcc/config/sh/embed-elf.h	2005-07-13 17:28:25.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/embed-elf.h	2006-08-10 09:56:05.000000000 +0100
@@ -2,6 +2,7 @@
    non-Linux embedded targets.
    Copyright (C) 2002, 2003 Free Software Foundation, Inc.
    Contributed by J"orn Rennecke <joern.rennecke@superh.com>
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -24,3 +25,16 @@ Boston, MA 02110-1301, USA.  */
 #define USER_LABEL_PREFIX "_"
 
 #undef TARGET_POSIX_IO
+
+/* While the speed-optimized implementations of udivsi3_i4i / sdivsi3_i4i
+   in libgcc are not available for SH2, the space-optimized ones in
+   libgcc-Os-4-200 are.  Thus, when not optimizing for space, link
+   libgcc-Os-4-200 after libgcc, so that -mdiv=call-table works for -m2.  */
+#define LIBGCC_SPEC "%{!shared: \
+  %{m4-100*:-lic_invalidate_array_4-100} \
+  %{m4-200*:-lic_invalidate_array_4-200} \
+  %{m4-300*|-m4-340:-lic_invalidate_array_4a %{!Os: -lgcc-4-300}} \
+  %{m4a*:-lic_invalidate_array_4a}} \
+  %{Os: -lgcc-Os-4-200} \
+  -lgcc \
+  %{!Os: -lgcc-Os-4-200}"
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/lib1funcs-4-300.asm gcc-4.1.1/gcc/config/sh/lib1funcs-4-300.asm
--- gcc-4.1.1.orig/gcc/config/sh/lib1funcs-4-300.asm	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/lib1funcs-4-300.asm	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,939 @@
+/* Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006 STMicroelectronics
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+/* libgcc routines for the STMicroelectronics ST40-300 CPU.
+   Contributed by J"orn Rennecke joern.rennecke@st.com.  */
+
+#include "lib1funcs.h"
+
+#ifdef L_div_table
+#if defined (__SH3__) || defined (__SH3E__) || defined (__SH4__) || defined (__SH4_SINGLE__) || defined (__SH4_SINGLE_ONLY__) || defined (__SH4_NOFPU__)
+/* This code used shld, thus is not suitable for SH1 / SH2.  */
+
+/* Signed / unsigned division without use of FPU, optimized for SH4-300.
+   Uses a lookup table for divisors in the range -128 .. +127, and
+   div1 with case distinction for larger divisors in three more ranges.
+   The code is lumped together with the table to allow the use of mova.  */
+#ifdef __LITTLE_ENDIAN__
+#define L_LSB 0
+#define L_LSWMSB 1
+#define L_MSWLSB 2
+#else
+#define L_LSB 3
+#define L_LSWMSB 2
+#define L_MSWLSB 1
+#endif
+
+	.global	GLOBAL(udivsi3_i4i)
+	.global	GLOBAL(sdivsi3_i4i)
+	FUNC(GLOBAL(udivsi3_i4i))
+	FUNC(GLOBAL(sdivsi3_i4i))
+
+	.balign 4
+LOCAL(div_ge8m): ! 10 cycles up to here
+	rotcr r1 ! signed shift must use original sign from r4
+	div0s r5,r4
+	mov #24,r7
+	shld r7,r6
+	shad r0,r1
+	rotcl r6
+	div1 r5,r1
+	swap.w r5,r0 ! detect -0x80000000 : 0x800000
+	rotcl r6
+	swap.w r4,r7
+	div1 r5,r1
+	swap.b r7,r7
+	rotcl r6
+	or r7,r0
+	div1 r5,r1
+	swap.w r0,r7
+	rotcl r6
+	or r7,r0
+	div1 r5,r1
+	add #-0x80,r0
+	rotcl r6
+	extu.w r0,r0
+	div1 r5,r1
+	neg r0,r0
+	rotcl r6
+	swap.w r0,r0
+	div1 r5,r1
+	mov.l @r15+,r7
+	and r6,r0
+	rotcl r6
+	div1 r5,r1
+	shll2 r0
+	rotcl r6
+	exts.b r0,r0
+	div1 r5,r1
+	swap.w r0,r0
+	exts.w r0,r1
+	exts.b r6,r0
+	mov.l @r15+,r6
+	rotcl r0
+	rts
+	sub r1,r0
+	! 31 cycles up to here
+
+	.balign 4
+LOCAL(udiv_ge64k): ! 3 cycles up to here
+	mov r4,r0
+	shlr8 r0
+	div0u
+	cmp/hi r0,r5
+	bt LOCAL(udiv_r8)
+	mov.l r5,@-r15
+	shll8 r5
+	! 7 cycles up to here
+	.rept 8
+	div1 r5,r0
+	.endr
+	extu.b r4,r1 ! 15 cycles up to here
+	extu.b r0,r6
+	xor r1,r0
+	xor r6,r0
+	swap.b r6,r6
+	.rept 8
+	div1 r5,r0
+	.endr ! 25 cycles up to here
+	extu.b r0,r0
+	mov.l @r15+,r5
+	or r6,r0
+	mov.l @r15+,r6
+	rts
+	rotcl r0 ! 28 cycles up to here
+
+	.balign 4
+LOCAL(udiv_r8): ! 6 cycles up to here
+	mov.l r4,@-r15
+	shll16 r4
+	shll8 r4
+	!
+	shll r4
+	mov r0,r1
+	div1 r5,r1
+	mov r4,r0
+	rotcl r0
+	mov.l @r15+,r4
+	div1 r5,r1
+	! 12 cycles up to here
+	.rept 6
+	rotcl r0; div1 r5,r1
+	.endr
+	mov.l @r15+,r6 ! 24 cycles up to here
+	rts
+	rotcl r0
+
+	.balign 4
+LOCAL(div_ge32k): ! 6 cycles up to here
+	mov.l r7,@-r15
+	swap.w r5,r6
+	exts.b r6,r7
+	exts.w r6,r6
+	cmp/eq r6,r7
+	extu.b r1,r6
+	bf/s LOCAL(div_ge8m)
+	cmp/hi r1,r4 ! copy sign bit of r4 into T
+	rotcr r1 ! signed shift must use original sign from r4
+	div0s r5,r4
+	shad r0,r1
+	shll8 r5
+	div1 r5,r1
+	mov r5,r7 ! detect r4 == 0x80000000 && r5 == 0x8000(00)
+	div1 r5,r1
+	shlr8 r7
+	div1 r5,r1
+	swap.w r4,r0
+	div1 r5,r1
+	swap.b r0,r0
+	div1 r5,r1
+	or r0,r7
+	div1 r5,r1
+	add #-80,r7
+	div1 r5,r1
+	swap.w r7,r0
+	div1 r5,r1
+	or r0,r7
+	extu.b r1,r0
+	xor r6,r1
+	xor r0,r1
+	exts.b r0,r0
+	div1 r5,r1
+	extu.w r7,r7
+	div1 r5,r1
+	neg r7,r7 ! upper 16 bit of r7 == 0 if r4 == 0x80000000 && r5 == 0x8000
+	div1 r5,r1
+	and r0,r7
+	div1 r5,r1
+	swap.w r7,r7 ! 26 cycles up to here.
+	div1 r5,r1
+	shll8 r0
+	div1 r5,r1
+	exts.w r7,r7
+	div1 r5,r1
+	add r0,r0
+	div1 r5,r1
+	sub r7,r0
+	extu.b r1,r1
+	mov.l @r15+,r7
+	rotcl r1
+	mov.l @r15+,r6
+	add r1,r0
+	mov #-8,r1
+	rts
+	shad r1,r5 ! 34 cycles up to here
+
+	.balign 4
+GLOBAL(udivsi3_i4i):
+	mov.l r6,@-r15
+	extu.w r5,r6
+	cmp/eq r5,r6
+	mov #0x7f,r0
+	bf LOCAL(udiv_ge64k)
+	cmp/hi r0,r5
+	bf LOCAL(udiv_le128)
+	mov r4,r1
+	shlr8 r1
+	div0u
+	shlr r1
+	shll16 r6
+	div1 r6,r1
+	extu.b r4,r0 ! 7 cycles up to here
+	.rept 8
+	div1 r6,r1
+	.endr     ! 15 cycles up to here
+	xor r1,r0 ! xor dividend with result lsb
+	.rept 6
+	div1 r6,r1
+	.endr
+	mov.l r7,@-r15 ! 21 cycles up to here
+	div1 r6,r1
+	extu.b r0,r7
+	div1 r6,r1
+	shll8 r7
+	extu.w r1,r0
+	xor r7,r1 ! replace lsb of result with lsb of dividend
+	div1 r6,r1
+	mov #0,r7
+	div1 r6,r1
+	!
+	div1 r6,r1
+	bra LOCAL(div_end)
+	div1 r6,r1 ! 28 cycles up to here
+
+	/* This is link-compatible with a GLOBAL(sdivsi3) call,
+	   but we effectively clobber only r1, macl and mach  */
+        /* Because negative quotients are calculated as one's complements,
+	   -0x80000000 divided by the smallest positive number of a number
+	   range (0x80, 0x8000, 0x800000) causes saturation in the one's
+           complement representation, and we have to suppress the
+	   one's -> two's complement adjustment.  Since positive numbers
+	   don't get such an adjustment, it's OK to also compute one's -> two's
+	   complement adjustment suppression for a dividend of 0.  */
+	.balign 4
+GLOBAL(sdivsi3_i4i):
+	mov.l r6,@-r15
+	exts.b r5,r6
+	cmp/eq r5,r6
+	mov #-1,r1
+	bt/s LOCAL(div_le128)
+	cmp/pz r4
+	addc r4,r1
+	exts.w r5,r6
+	cmp/eq r5,r6
+	mov #-7,r0
+	bf/s LOCAL(div_ge32k)
+	cmp/hi r1,r4 ! copy sign bit of r4 into T
+	rotcr r1
+	shll16 r6  ! 7 cycles up to here
+	shad r0,r1
+	div0s r5,r4
+	div1 r6,r1
+	mov.l r7,@-r15
+	div1 r6,r1
+	mov r4,r0 ! re-compute adjusted dividend
+	div1 r6,r1
+	mov #-31,r7
+	div1 r6,r1
+	shad r7,r0
+	div1 r6,r1
+	add r4,r0 ! adjusted dividend
+	div1 r6,r1
+	mov.l r8,@-r15
+	div1 r6,r1
+	swap.w r4,r8 ! detect special case r4 = 0x80000000, r5 = 0x80
+	div1 r6,r1
+	swap.b r8,r8
+	xor r1,r0 ! xor dividend with result lsb
+	div1 r6,r1
+	div1 r6,r1
+	or r5,r8
+	div1 r6,r1
+	add #-0x80,r8 ! r8 is 0 iff there is a match
+	div1 r6,r1
+	swap.w r8,r7 ! or upper 16 bits...
+	div1 r6,r1
+	or r7,r8 !...into lower 16 bits
+	div1 r6,r1
+	extu.w r8,r8
+	div1 r6,r1
+	extu.b r0,r7
+	div1 r6,r1
+	shll8 r7
+	exts.w r1,r0
+	xor r7,r1 ! replace lsb of result with lsb of dividend
+	div1 r6,r1
+	neg r8,r8 ! upper 16 bits of r8 are now 0xffff iff we want end adjm.
+	div1 r6,r1
+	and r0,r8
+	div1 r6,r1
+	swap.w r8,r7
+	div1 r6,r1
+	mov.l @r15+,r8 ! 58 insns, 29 cycles up to here
+LOCAL(div_end):
+	div1 r6,r1
+	shll8 r0
+	div1 r6,r1
+	exts.w r7,r7
+	div1 r6,r1
+	add r0,r0
+	div1 r6,r1
+	sub r7,r0
+	extu.b r1,r1
+	mov.l @r15+,r7
+	rotcl r1
+	mov.l @r15+,r6
+	rts
+	add r1,r0
+
+	.balign 4
+LOCAL(udiv_le128): ! 4 cycles up to here (or 7 for mispredict)
+	mova LOCAL(div_table_inv),r0
+	shll2 r6
+	mov.l @(r0,r6),r1
+	mova LOCAL(div_table_clz),r0
+	lds r4,mach
+	!
+	!
+	!
+	tst r1,r1
+	!
+	bt 0f
+	dmulu.l r1,r4
+0:	mov.b @(r0,r5),r1
+	clrt
+	!
+	!
+	sts mach,r0
+	addc r4,r0
+	rotcr r0
+	mov.l @r15+,r6
+	rts
+	shld r1,r0
+
+	.balign 4
+LOCAL(div_le128): ! 3 cycles up to here (or 6 for mispredict)
+	mova LOCAL(div_table_inv),r0
+	shll2 r6
+	mov.l @(r0,r6),r1
+	mova LOCAL(div_table_clz),r0
+	neg r4,r6
+	bf 0f
+	mov r4,r6
+0:	lds r6,mach
+	tst r1,r1
+	bt 0f
+	dmulu.l r1,r6
+0:	div0s r4,r5
+	mov.b @(r0,r5),r1
+	bt/s LOCAL(le128_neg)
+	clrt
+	!
+	sts mach,r0
+	addc r6,r0
+	rotcr r0
+	mov.l @r15+,r6
+	rts
+	shld r1,r0
+
+/* Could trap divide by zero for the cost of one cycle more mispredict penalty:
+...
+	dmulu.l r1,r6
+0:	div0s r4,r5
+	bt/s LOCAL(le128_neg)
+	tst r5,r5
+	bt LOCAL(div_by_zero)
+	mov.b @(r0,r5),r1
+	sts mach,r0
+	addc r6,r0
+...
+LOCAL(div_by_zero):
+	trapa #
+	.balign 4
+LOCAL(le128_neg):
+	bt LOCAL(div_by_zero)
+	mov.b @(r0,r5),r1
+	sts mach,r0
+	addc r6,r0
+...  */
+
+	.balign 4
+LOCAL(le128_neg):
+	sts mach,r0
+	addc r6,r0
+	rotcr r0
+	mov.l @r15+,r6
+	shad r1,r0
+	rts
+	neg r0,r0
+	ENDFUNC(GLOBAL(udivsi3_i4i))
+	ENDFUNC(GLOBAL(sdivsi3_i4i))
+
+/* This table has been generated by divtab-sh4.c.  */
+	.balign 4
+	.byte	-7
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-2
+	.byte	-2
+	.byte	-2
+	.byte	-2
+	.byte	-1
+	.byte	-1
+	.byte	0
+LOCAL(div_table_clz):
+	.byte	0
+	.byte	0
+	.byte	-1
+	.byte	-1
+	.byte	-2
+	.byte	-2
+	.byte	-2
+	.byte	-2
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+/* 1/-128 .. 1/127, normalized.  There is an implicit leading 1 in bit 32,
+   or in bit 33 for powers of two.  */
+	.balign 4
+	.long   0x0
+	.long	0x2040811
+	.long	0x4104105
+	.long	0x624DD30
+	.long	0x8421085
+	.long	0xA6810A7
+	.long	0xC9714FC
+	.long	0xECF56BF
+	.long	0x11111112
+	.long	0x135C8114
+	.long	0x15B1E5F8
+	.long	0x18118119
+	.long	0x1A7B9612
+	.long	0x1CF06ADB
+	.long	0x1F7047DD
+	.long	0x21FB7813
+	.long	0x24924925
+	.long	0x27350B89
+	.long	0x29E4129F
+	.long	0x2C9FB4D9
+	.long	0x2F684BDB
+	.long	0x323E34A3
+	.long	0x3521CFB3
+	.long	0x38138139
+	.long	0x3B13B13C
+	.long	0x3E22CBCF
+	.long	0x41414142
+	.long	0x446F8657
+	.long	0x47AE147B
+	.long	0x4AFD6A06
+	.long	0x4E5E0A73
+	.long	0x51D07EAF
+	.long	0x55555556
+	.long	0x58ED2309
+	.long	0x5C9882BA
+	.long	0x60581606
+	.long	0x642C8591
+	.long	0x68168169
+	.long	0x6C16C16D
+	.long	0x702E05C1
+	.long	0x745D1746
+	.long	0x78A4C818
+	.long	0x7D05F418
+	.long	0x81818182
+	.long	0x86186187
+	.long	0x8ACB90F7
+	.long	0x8F9C18FA
+	.long	0x948B0FCE
+	.long	0x9999999A
+	.long	0x9EC8E952
+	.long	0xA41A41A5
+	.long	0xA98EF607
+	.long	0xAF286BCB
+	.long	0xB4E81B4F
+	.long	0xBACF914D
+	.long	0xC0E07039
+	.long	0xC71C71C8
+	.long	0xCD856891
+	.long	0xD41D41D5
+	.long	0xDAE6076C
+	.long	0xE1E1E1E2
+	.long	0xE9131AC0
+	.long	0xF07C1F08
+	.long	0xF81F81F9
+	.long	0x0
+	.long	0x4104105
+	.long	0x8421085
+	.long	0xC9714FC
+	.long	0x11111112
+	.long	0x15B1E5F8
+	.long	0x1A7B9612
+	.long	0x1F7047DD
+	.long	0x24924925
+	.long	0x29E4129F
+	.long	0x2F684BDB
+	.long	0x3521CFB3
+	.long	0x3B13B13C
+	.long	0x41414142
+	.long	0x47AE147B
+	.long	0x4E5E0A73
+	.long	0x55555556
+	.long	0x5C9882BA
+	.long	0x642C8591
+	.long	0x6C16C16D
+	.long	0x745D1746
+	.long	0x7D05F418
+	.long	0x86186187
+	.long	0x8F9C18FA
+	.long	0x9999999A
+	.long	0xA41A41A5
+	.long	0xAF286BCB
+	.long	0xBACF914D
+	.long	0xC71C71C8
+	.long	0xD41D41D5
+	.long	0xE1E1E1E2
+	.long	0xF07C1F08
+	.long	0x0
+	.long	0x8421085
+	.long	0x11111112
+	.long	0x1A7B9612
+	.long	0x24924925
+	.long	0x2F684BDB
+	.long	0x3B13B13C
+	.long	0x47AE147B
+	.long	0x55555556
+	.long	0x642C8591
+	.long	0x745D1746
+	.long	0x86186187
+	.long	0x9999999A
+	.long	0xAF286BCB
+	.long	0xC71C71C8
+	.long	0xE1E1E1E2
+	.long	0x0
+	.long	0x11111112
+	.long	0x24924925
+	.long	0x3B13B13C
+	.long	0x55555556
+	.long	0x745D1746
+	.long	0x9999999A
+	.long	0xC71C71C8
+	.long	0x0
+	.long	0x24924925
+	.long	0x55555556
+	.long	0x9999999A
+	.long	0x0
+	.long	0x55555556
+	.long	0x0
+	.long	0x0
+LOCAL(div_table_inv):
+	.long	0x0
+	.long	0x0
+	.long	0x0
+	.long	0x55555556
+	.long	0x0
+	.long	0x9999999A
+	.long	0x55555556
+	.long	0x24924925
+	.long	0x0
+	.long	0xC71C71C8
+	.long	0x9999999A
+	.long	0x745D1746
+	.long	0x55555556
+	.long	0x3B13B13C
+	.long	0x24924925
+	.long	0x11111112
+	.long	0x0
+	.long	0xE1E1E1E2
+	.long	0xC71C71C8
+	.long	0xAF286BCB
+	.long	0x9999999A
+	.long	0x86186187
+	.long	0x745D1746
+	.long	0x642C8591
+	.long	0x55555556
+	.long	0x47AE147B
+	.long	0x3B13B13C
+	.long	0x2F684BDB
+	.long	0x24924925
+	.long	0x1A7B9612
+	.long	0x11111112
+	.long	0x8421085
+	.long	0x0
+	.long	0xF07C1F08
+	.long	0xE1E1E1E2
+	.long	0xD41D41D5
+	.long	0xC71C71C8
+	.long	0xBACF914D
+	.long	0xAF286BCB
+	.long	0xA41A41A5
+	.long	0x9999999A
+	.long	0x8F9C18FA
+	.long	0x86186187
+	.long	0x7D05F418
+	.long	0x745D1746
+	.long	0x6C16C16D
+	.long	0x642C8591
+	.long	0x5C9882BA
+	.long	0x55555556
+	.long	0x4E5E0A73
+	.long	0x47AE147B
+	.long	0x41414142
+	.long	0x3B13B13C
+	.long	0x3521CFB3
+	.long	0x2F684BDB
+	.long	0x29E4129F
+	.long	0x24924925
+	.long	0x1F7047DD
+	.long	0x1A7B9612
+	.long	0x15B1E5F8
+	.long	0x11111112
+	.long	0xC9714FC
+	.long	0x8421085
+	.long	0x4104105
+	.long	0x0
+	.long	0xF81F81F9
+	.long	0xF07C1F08
+	.long	0xE9131AC0
+	.long	0xE1E1E1E2
+	.long	0xDAE6076C
+	.long	0xD41D41D5
+	.long	0xCD856891
+	.long	0xC71C71C8
+	.long	0xC0E07039
+	.long	0xBACF914D
+	.long	0xB4E81B4F
+	.long	0xAF286BCB
+	.long	0xA98EF607
+	.long	0xA41A41A5
+	.long	0x9EC8E952
+	.long	0x9999999A
+	.long	0x948B0FCE
+	.long	0x8F9C18FA
+	.long	0x8ACB90F7
+	.long	0x86186187
+	.long	0x81818182
+	.long	0x7D05F418
+	.long	0x78A4C818
+	.long	0x745D1746
+	.long	0x702E05C1
+	.long	0x6C16C16D
+	.long	0x68168169
+	.long	0x642C8591
+	.long	0x60581606
+	.long	0x5C9882BA
+	.long	0x58ED2309
+	.long	0x55555556
+	.long	0x51D07EAF
+	.long	0x4E5E0A73
+	.long	0x4AFD6A06
+	.long	0x47AE147B
+	.long	0x446F8657
+	.long	0x41414142
+	.long	0x3E22CBCF
+	.long	0x3B13B13C
+	.long	0x38138139
+	.long	0x3521CFB3
+	.long	0x323E34A3
+	.long	0x2F684BDB
+	.long	0x2C9FB4D9
+	.long	0x29E4129F
+	.long	0x27350B89
+	.long	0x24924925
+	.long	0x21FB7813
+	.long	0x1F7047DD
+	.long	0x1CF06ADB
+	.long	0x1A7B9612
+	.long	0x18118119
+	.long	0x15B1E5F8
+	.long	0x135C8114
+	.long	0x11111112
+	.long	0xECF56BF
+	.long	0xC9714FC
+	.long	0xA6810A7
+	.long	0x8421085
+	.long	0x624DD30
+	.long	0x4104105
+	.long	0x2040811
+	/* maximum error: 0.987342 scaled: 0.921875*/
+
+#endif /* SH3 / SH4 */
+
+#endif /* L_div_table */
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/lib1funcs.asm gcc-4.1.1/gcc/config/sh/lib1funcs.asm
--- gcc-4.1.1.orig/gcc/config/sh/lib1funcs.asm	2005-06-25 02:22:41.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/lib1funcs.asm	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
    2004, 2005
    Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
@@ -38,31 +39,7 @@ Boston, MA 02110-1301, USA.  */
    ELF local label prefixes by J"orn Rennecke
    amylaar@cygnus.com  */
 
-#ifdef __ELF__
-#define LOCAL(X)	.L_##X
-#define FUNC(X)		.type X,@function
-#define HIDDEN_FUNC(X)	FUNC(X); .hidden X
-#define HIDDEN_ALIAS(X,Y) ALIAS (X,Y); .hidden GLOBAL(X)
-#define ENDFUNC0(X)	.Lfe_##X: .size X,.Lfe_##X-X
-#define ENDFUNC(X)	ENDFUNC0(X)
-#else
-#define LOCAL(X)	L_##X
-#define FUNC(X)
-#define HIDDEN_FUNC(X)
-#define HIDDEN_ALIAS(X,Y) ALIAS (X,Y)
-#define ENDFUNC(X)
-#endif
-
-#define	CONCAT(A,B)	A##B
-#define	GLOBAL0(U,X)	CONCAT(U,__##X)
-#define	GLOBAL(X)	GLOBAL0(__USER_LABEL_PREFIX__,X)
-
-#define ALIAS(X,Y)	.global GLOBAL(X); .set GLOBAL(X),GLOBAL(Y)
-
-#ifdef __SH2A__
-#undef FMOVD_WORKS
-#define FMOVD_WORKS
-#endif
+#include "lib1funcs.h"
 
 #if ! __SH5__
 #ifdef L_ashiftrt
@@ -1375,13 +1352,8 @@ GLOBAL(udivsi3_i4):
 #ifdef FMOVD_WORKS
 	fmov.d @r0+,dr4
 #else
-#ifdef __LITTLE_ENDIAN__
-	fmov.s @r0+,fr5
-	fmov.s @r0,fr4
-#else
-	fmov.s @r0+,fr4
-	fmov.s @r0,fr5
-#endif
+	fmov.s @r0+,DR40
+	fmov.s @r0,DR41
 #endif
 	float fpul,dr0
 	xor r1,r5
@@ -1444,13 +1416,8 @@ GLOBAL(udivsi3_i4):
 #ifdef FMOVD_WORKS
 	fmov.d @r0+,dr4
 #else
-#ifdef __LITTLE_ENDIAN__
-	fmov.s @r0+,fr5
-	fmov.s @r0,fr4
-#else
-	fmov.s @r0+,fr4
-	fmov.s @r0,fr5
-#endif
+	fmov.s @r0+,DR40
+	fmov.s @r0,DR41
 #endif
 	float fpul,dr0
 	xor r1,r5
@@ -2141,7 +2108,7 @@ 	ENDFUNC(GLOBAL(ic_invalidate))
 #endif /* L_ic_invalidate */
 
 #ifdef L_ic_invalidate_array
-#if defined(__SH4A__)
+#if defined(__SH4A__) || (defined (__FORCE_SH4A__) && (defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY__) || (defined(__SH4_NOFPU__) && !defined(__SH5__))))
 	/* This is needed when an SH4 dso with trampolines is used on SH4A.  */
 	.global GLOBAL(ic_invalidate_array)
 	FUNC(GLOBAL(ic_invalidate_array))
@@ -3019,8 +2986,8 @@ 	ENDFUNC(GLOBAL(GCC_pop_shmedia_regs_nof
 #endif /* __SH5__ == 32 */
 #endif /* L_push_pop_shmedia_regs */
 
-#if __SH5__
 #ifdef L_div_table
+#if __SH5__
 #if defined(__pic__) && defined(__SHMEDIA__)
 	.global	GLOBAL(sdivsi3)
 	FUNC(GLOBAL(sdivsi3))
@@ -3247,5 +3214,680 @@ 	HIDDEN_ALIAS(div_table_internal,div_tab
 	.word	17738
 	.word	17136
 	.word	16639
+
+#elif defined (__SH3__) || defined (__SH3E__) || defined (__SH4__) || defined (__SH4_SINGLE__) || defined (__SH4_SINGLE_ONLY__) || defined (__SH4_NOFPU__)
+/* This code used shld, thus is not suitable for SH1 / SH2.  */
+
+/* Signed / unsigned division without use of FPU, optimized for SH4.
+   Uses a lookup table for divisors in the range -128 .. +128, and
+   div1 with case distinction for larger divisors in three more ranges.
+   The code is lumped together with the table to allow the use of mova.  */
+#ifdef __LITTLE_ENDIAN__
+#define L_LSB 0
+#define L_LSWMSB 1
+#define L_MSWLSB 2
+#else
+#define L_LSB 3
+#define L_LSWMSB 2
+#define L_MSWLSB 1
+#endif
+
+	.balign 4
+	.global	GLOBAL(udivsi3_i4i)
+	FUNC(GLOBAL(udivsi3_i4i))
+GLOBAL(udivsi3_i4i):
+	mov.w LOCAL(c128_w), r1
+	div0u
+	mov r4,r0
+	shlr8 r0
+	cmp/hi r1,r5
+	extu.w r5,r1
+	bf LOCAL(udiv_le128)
+	cmp/eq r5,r1
+	bf LOCAL(udiv_ge64k)
+	shlr r0
+	mov r5,r1
+	shll16 r5
+	mov.l r4,@-r15
+	div1 r5,r0
+	mov.l r1,@-r15
+	div1 r5,r0
+	div1 r5,r0
+	bra LOCAL(udiv_25)
+	div1 r5,r0
+
+LOCAL(div_le128):
+	mova LOCAL(div_table_ix),r0
+	bra LOCAL(div_le128_2)
+	mov.b @(r0,r5),r1
+LOCAL(udiv_le128):
+	mov.l r4,@-r15
+	mova LOCAL(div_table_ix),r0
+	mov.b @(r0,r5),r1
+	mov.l r5,@-r15
+LOCAL(div_le128_2):
+	mova LOCAL(div_table_inv),r0
+	mov.l @(r0,r1),r1
+	mov r5,r0
+	tst #0xfe,r0
+	mova LOCAL(div_table_clz),r0
+	dmulu.l r1,r4
+	mov.b @(r0,r5),r1
+	bt/s LOCAL(div_by_1)
+	mov r4,r0
+	mov.l @r15+,r5
+	sts mach,r0
+	/* clrt */
+	addc r4,r0
+	mov.l @r15+,r4
+	rotcr r0
+	rts
+	shld r1,r0
+
+LOCAL(div_by_1_neg):
+	neg r4,r0
+LOCAL(div_by_1):
+	mov.l @r15+,r5
+	rts
+	mov.l @r15+,r4
+
+LOCAL(div_ge64k):
+	bt/s LOCAL(div_r8)
+	div0u
+	shll8 r5
+	bra LOCAL(div_ge64k_2)
+	div1 r5,r0
+LOCAL(udiv_ge64k):
+	cmp/hi r0,r5
+	mov r5,r1
+	bt LOCAL(udiv_r8)
+	shll8 r5
+	mov.l r4,@-r15
+	div1 r5,r0
+	mov.l r1,@-r15
+LOCAL(div_ge64k_2):
+	div1 r5,r0
+	mov.l LOCAL(zero_l),r1
+	.rept 4
+	div1 r5,r0
+	.endr
+	mov.l r1,@-r15
+	div1 r5,r0
+	mov.w LOCAL(m256_w),r1
+	div1 r5,r0
+	mov.b r0,@(L_LSWMSB,r15)
+	xor r4,r0
+	and r1,r0
+	bra LOCAL(div_ge64k_end)
+	xor r4,r0
+	
+LOCAL(div_r8):
+	shll16 r4
+	bra LOCAL(div_r8_2)
+	shll8 r4
+LOCAL(udiv_r8):
+	mov.l r4,@-r15
+	shll16 r4
+	clrt
+	shll8 r4
+	mov.l r5,@-r15
+LOCAL(div_r8_2):
+	rotcl r4
+	mov r0,r1
+	div1 r5,r1
+	mov r4,r0
+	rotcl r0
+	mov r5,r4
+	div1 r5,r1
+	.rept 5
+	rotcl r0; div1 r5,r1
+	.endr
+	rotcl r0
+	mov.l @r15+,r5
+	div1 r4,r1
+	mov.l @r15+,r4
+	rts
+	rotcl r0
+
+	ENDFUNC(GLOBAL(udivsi3_i4i))
+
+	.global	GLOBAL(sdivsi3_i4i)
+	FUNC(GLOBAL(sdivsi3_i4i))
+	/* This is link-compatible with a GLOBAL(sdivsi3) call,
+	   but we effectively clobber only r1.  */
+GLOBAL(sdivsi3_i4i):
+	mov.l r4,@-r15
+	cmp/pz r5
+	mov.w LOCAL(c128_w), r1
+	bt/s LOCAL(pos_divisor)
+	cmp/pz r4
+	mov.l r5,@-r15
+	neg r5,r5
+	bt/s LOCAL(neg_result)
+	cmp/hi r1,r5
+	neg r4,r4
+LOCAL(pos_result):
+	extu.w r5,r0
+	bf LOCAL(div_le128)
+	cmp/eq r5,r0
+	mov r4,r0
+	shlr8 r0
+	bf/s LOCAL(div_ge64k)
+	cmp/hi r0,r5
+	div0u
+	shll16 r5
+	div1 r5,r0
+	div1 r5,r0
+	div1 r5,r0
+LOCAL(udiv_25):
+	mov.l LOCAL(zero_l),r1
+	div1 r5,r0
+	div1 r5,r0
+	mov.l r1,@-r15
+	.rept 3
+	div1 r5,r0
+	.endr
+	mov.b r0,@(L_MSWLSB,r15)
+	xtrct r4,r0
+	swap.w r0,r0
+	.rept 8
+	div1 r5,r0
+	.endr
+	mov.b r0,@(L_LSWMSB,r15)
+LOCAL(div_ge64k_end):
+	.rept 8
+	div1 r5,r0
+	.endr
+	mov.l @r15+,r4 ! zero-extension and swap using LS unit.
+	extu.b r0,r0
+	mov.l @r15+,r5
+	or r4,r0
+	mov.l @r15+,r4
+	rts
+	rotcl r0
+
+LOCAL(div_le128_neg):
+	tst #0xfe,r0
+	mova LOCAL(div_table_ix),r0
+	mov.b @(r0,r5),r1
+	mova LOCAL(div_table_inv),r0
+	bt/s LOCAL(div_by_1_neg)
+	mov.l @(r0,r1),r1
+	mova LOCAL(div_table_clz),r0
+	dmulu.l r1,r4
+	mov.b @(r0,r5),r1
+	mov.l @r15+,r5
+	sts mach,r0
+	/* clrt */
+	addc r4,r0
+	mov.l @r15+,r4
+	rotcr r0
+	shld r1,r0
+	rts
+	neg r0,r0
+
+LOCAL(pos_divisor):
+	mov.l r5,@-r15
+	bt/s LOCAL(pos_result)
+	cmp/hi r1,r5
+	neg r4,r4
+LOCAL(neg_result):
+	extu.w r5,r0
+	bf LOCAL(div_le128_neg)
+	cmp/eq r5,r0
+	mov r4,r0
+	shlr8 r0
+	bf/s LOCAL(div_ge64k_neg)
+	cmp/hi r0,r5
+	div0u
+	mov.l LOCAL(zero_l),r1
+	shll16 r5
+	div1 r5,r0
+	mov.l r1,@-r15
+	.rept 7
+	div1 r5,r0
+	.endr
+	mov.b r0,@(L_MSWLSB,r15)
+	xtrct r4,r0
+	swap.w r0,r0
+	.rept 8
+	div1 r5,r0
+	.endr
+	mov.b r0,@(L_LSWMSB,r15)
+LOCAL(div_ge64k_neg_end):
+	.rept 8
+	div1 r5,r0
+	.endr
+	mov.l @r15+,r4 ! zero-extension and swap using LS unit.
+	extu.b r0,r1
+	mov.l @r15+,r5
+	or r4,r1
+LOCAL(div_r8_neg_end):
+	mov.l @r15+,r4
+	rotcl r1
+	rts
+	neg r1,r0
+
+LOCAL(div_ge64k_neg):
+	bt/s LOCAL(div_r8_neg)
+	div0u
+	shll8 r5
+	mov.l LOCAL(zero_l),r1
+	.rept 6
+	div1 r5,r0
+	.endr
+	mov.l r1,@-r15
+	div1 r5,r0
+	mov.w LOCAL(m256_w),r1
+	div1 r5,r0
+	mov.b r0,@(L_LSWMSB,r15)
+	xor r4,r0
+	and r1,r0
+	bra LOCAL(div_ge64k_neg_end)
+	xor r4,r0
+
+LOCAL(c128_w):
+	.word 128
+
+LOCAL(div_r8_neg):
+	clrt
+	shll16 r4
+	mov r4,r1
+	shll8 r1
+	mov r5,r4
+	.rept 7
+	rotcl r1; div1 r5,r0
+	.endr
+	mov.l @r15+,r5
+	rotcl r1
+	bra LOCAL(div_r8_neg_end)
+	div1 r4,r0
+
+LOCAL(m256_w):
+	.word 0xff00
+/* This table has been generated by divtab-sh4.c.  */
+	.balign 4
+LOCAL(div_table_clz):
+	.byte	0
+	.byte	1
+	.byte	0
+	.byte	-1
+	.byte	-1
+	.byte	-2
+	.byte	-2
+	.byte	-2
+	.byte	-2
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+/* Lookup table translating positive divisor to index into table of
+   normalized inverse.  N.B. the '0' entry is also the last entry of the
+ previous table, and causes an unaligned access for division by zero.  */
+LOCAL(div_table_ix):
+	.byte	-6
+	.byte	-128
+	.byte	-128
+	.byte	0
+	.byte	-128
+	.byte	-64
+	.byte	0
+	.byte	64
+	.byte	-128
+	.byte	-96
+	.byte	-64
+	.byte	-32
+	.byte	0
+	.byte	32
+	.byte	64
+	.byte	96
+	.byte	-128
+	.byte	-112
+	.byte	-96
+	.byte	-80
+	.byte	-64
+	.byte	-48
+	.byte	-32
+	.byte	-16
+	.byte	0
+	.byte	16
+	.byte	32
+	.byte	48
+	.byte	64
+	.byte	80
+	.byte	96
+	.byte	112
+	.byte	-128
+	.byte	-120
+	.byte	-112
+	.byte	-104
+	.byte	-96
+	.byte	-88
+	.byte	-80
+	.byte	-72
+	.byte	-64
+	.byte	-56
+	.byte	-48
+	.byte	-40
+	.byte	-32
+	.byte	-24
+	.byte	-16
+	.byte	-8
+	.byte	0
+	.byte	8
+	.byte	16
+	.byte	24
+	.byte	32
+	.byte	40
+	.byte	48
+	.byte	56
+	.byte	64
+	.byte	72
+	.byte	80
+	.byte	88
+	.byte	96
+	.byte	104
+	.byte	112
+	.byte	120
+	.byte	-128
+	.byte	-124
+	.byte	-120
+	.byte	-116
+	.byte	-112
+	.byte	-108
+	.byte	-104
+	.byte	-100
+	.byte	-96
+	.byte	-92
+	.byte	-88
+	.byte	-84
+	.byte	-80
+	.byte	-76
+	.byte	-72
+	.byte	-68
+	.byte	-64
+	.byte	-60
+	.byte	-56
+	.byte	-52
+	.byte	-48
+	.byte	-44
+	.byte	-40
+	.byte	-36
+	.byte	-32
+	.byte	-28
+	.byte	-24
+	.byte	-20
+	.byte	-16
+	.byte	-12
+	.byte	-8
+	.byte	-4
+	.byte	0
+	.byte	4
+	.byte	8
+	.byte	12
+	.byte	16
+	.byte	20
+	.byte	24
+	.byte	28
+	.byte	32
+	.byte	36
+	.byte	40
+	.byte	44
+	.byte	48
+	.byte	52
+	.byte	56
+	.byte	60
+	.byte	64
+	.byte	68
+	.byte	72
+	.byte	76
+	.byte	80
+	.byte	84
+	.byte	88
+	.byte	92
+	.byte	96
+	.byte	100
+	.byte	104
+	.byte	108
+	.byte	112
+	.byte	116
+	.byte	120
+	.byte	124
+	.byte	-128
+/* 1/64 .. 1/127, normalized.  There is an implicit leading 1 in bit 32.  */
+	.balign 4
+LOCAL(zero_l):
+	.long	0x0
+	.long	0xF81F81F9
+	.long	0xF07C1F08
+	.long	0xE9131AC0
+	.long	0xE1E1E1E2
+	.long	0xDAE6076C
+	.long	0xD41D41D5
+	.long	0xCD856891
+	.long	0xC71C71C8
+	.long	0xC0E07039
+	.long	0xBACF914D
+	.long	0xB4E81B4F
+	.long	0xAF286BCB
+	.long	0xA98EF607
+	.long	0xA41A41A5
+	.long	0x9EC8E952
+	.long	0x9999999A
+	.long	0x948B0FCE
+	.long	0x8F9C18FA
+	.long	0x8ACB90F7
+	.long	0x86186187
+	.long	0x81818182
+	.long	0x7D05F418
+	.long	0x78A4C818
+	.long	0x745D1746
+	.long	0x702E05C1
+	.long	0x6C16C16D
+	.long	0x68168169
+	.long	0x642C8591
+	.long	0x60581606
+	.long	0x5C9882BA
+	.long	0x58ED2309
+LOCAL(div_table_inv):
+	.long	0x55555556
+	.long	0x51D07EAF
+	.long	0x4E5E0A73
+	.long	0x4AFD6A06
+	.long	0x47AE147B
+	.long	0x446F8657
+	.long	0x41414142
+	.long	0x3E22CBCF
+	.long	0x3B13B13C
+	.long	0x38138139
+	.long	0x3521CFB3
+	.long	0x323E34A3
+	.long	0x2F684BDB
+	.long	0x2C9FB4D9
+	.long	0x29E4129F
+	.long	0x27350B89
+	.long	0x24924925
+	.long	0x21FB7813
+	.long	0x1F7047DD
+	.long	0x1CF06ADB
+	.long	0x1A7B9612
+	.long	0x18118119
+	.long	0x15B1E5F8
+	.long	0x135C8114
+	.long	0x11111112
+	.long	0xECF56BF
+	.long	0xC9714FC
+	.long	0xA6810A7
+	.long	0x8421085
+	.long	0x624DD30
+	.long	0x4104105
+	.long	0x2040811
+	/* maximum error: 0.987342 scaled: 0.921875*/
+
+	ENDFUNC(GLOBAL(sdivsi3_i4i))
+#endif /* SH3 / SH4 */
+
 #endif /* L_div_table */
-#endif /* __SH5__ */
+
+#ifdef L_udiv_qrnnd_16
+#if !__SHMEDIA__
+	HIDDEN_FUNC(GLOBAL(udiv_qrnnd_16))
+	/* r0: rn r1: qn */ /* r0: n1 r4: n0 r5: d r6: d1 */ /* r2: __m */
+	/* n1 < d, but n1 might be larger than d1.  */
+	.global GLOBAL(udiv_qrnnd_16)
+	.balign 8
+GLOBAL(udiv_qrnnd_16):
+	div0u
+	cmp/hi r6,r0
+	bt .Lots
+	.rept 16
+	div1 r6,r0 
+	.endr
+	extu.w r0,r1
+	bt 0f
+	add r6,r0
+0:	rotcl r1
+	mulu.w r1,r5
+	xtrct r4,r0
+	swap.w r0,r0
+	sts macl,r2
+	cmp/hs r2,r0
+	sub r2,r0
+	bt 0f
+	addc r5,r0
+	add #-1,r1
+	bt 0f
+1:	add #-1,r1
+	rts
+	add r5,r0
+	.balign 8
+.Lots:
+	sub r5,r0
+	swap.w r4,r1
+	xtrct r0,r1
+	clrt
+	mov r1,r0
+	addc r5,r0
+	mov #-1,r1
+	SL1(bf, 1b,
+	shlr16 r1)
+0:	rts
+	nop
+	ENDFUNC(GLOBAL(udiv_qrnnd_16))
+#endif /* !__SHMEDIA__ */
+#endif /* L_udiv_qrnnd_16 */
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/lib1funcs.h gcc-4.1.1/gcc/config/sh/lib1funcs.h
--- gcc-4.1.1.orig/gcc/config/sh/lib1funcs.h	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/lib1funcs.h	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,82 @@
+/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005, 2006
+   Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#ifdef __ELF__
+#define LOCAL(X)	.L_##X
+#define FUNC(X)		.type X,@function
+#define HIDDEN_FUNC(X)	FUNC(X); .hidden X
+#define HIDDEN_ALIAS(X,Y) ALIAS (X,Y); .hidden GLOBAL(X)
+#define ENDFUNC0(X)	.Lfe_##X: .size X,.Lfe_##X-X
+#define ENDFUNC(X)	ENDFUNC0(X)
+#else
+#define LOCAL(X)	L_##X
+#define FUNC(X)
+#define HIDDEN_FUNC(X)
+#define HIDDEN_ALIAS(X,Y) ALIAS (X,Y)
+#define ENDFUNC(X)
+#endif
+
+#define	CONCAT(A,B)	A##B
+#define	GLOBAL0(U,X)	CONCAT(U,__##X)
+#define	GLOBAL(X)	GLOBAL0(__USER_LABEL_PREFIX__,X)
+
+#define ALIAS(X,Y)	.global GLOBAL(X); .set GLOBAL(X),GLOBAL(Y)
+
+#ifdef __SH2A__
+#undef FMOVD_WORKS
+#define FMOVD_WORKS
+#endif
+
+#ifdef __LITTLE_ENDIAN__
+#define DR00 fr1
+#define DR01 fr0
+#define DR20 fr3
+#define DR21 fr2
+#define DR40 fr5
+#define DR41 fr4
+#else /* !__LITTLE_ENDIAN__ */
+#define DR00 fr0
+#define DR01 fr1
+#define DR20 fr2
+#define DR21 fr3
+#define DR40 fr4
+#define DR41 fr5
+#endif /* !__LITTLE_ENDIAN__ */
+
+#ifdef __sh1__
+#define SL(branch, dest, in_slot, in_slot_arg2) \
+	in_slot, in_slot_arg2; branch dest
+#define SL1(branch, dest, in_slot) \
+	in_slot; branch dest
+#else /* ! __sh1__ */
+#define SL(branch, dest, in_slot, in_slot_arg2) \
+	branch##.s dest; in_slot, in_slot_arg2
+#define SL1(branch, dest, in_slot) \
+	branch##/s dest; in_slot
+#endif /* !__sh1__ */
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/lib1funcs-Os-4-200.asm gcc-4.1.1/gcc/config/sh/lib1funcs-Os-4-200.asm
--- gcc-4.1.1.orig/gcc/config/sh/lib1funcs-Os-4-200.asm	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/lib1funcs-Os-4-200.asm	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,326 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+/* Moderately Space-optimized libgcc routines for the Renesas SH /
+   STMicroelectronics ST40 CPUs.
+   Contributed by J"orn Rennecke joern.rennecke@st.com.  */
+
+#include "lib1funcs.h"
+
+#ifdef L_udivsi3_i4i
+
+/* 88 bytes; sh4-200 cycle counts:
+   divisor  >= 2G: 11 cycles
+   dividend <  2G: 48 cycles
+   dividend >= 2G: divisor != 1: 54 cycles
+   dividend >= 2G, divisor == 1: 22 cycles */
+#if defined (__SH_FPU_DOUBLE__) || defined (__SH4_SINGLE_ONLY__)
+!! args in r4 and r5, result in r0, clobber r1
+
+	.global GLOBAL(udivsi3_i4i)
+	FUNC(GLOBAL(udivsi3_i4i))
+GLOBAL(udivsi3_i4i):
+	mova L1,r0
+	cmp/pz r5
+	sts fpscr,r1
+	lds.l @r0+,fpscr
+	sts.l fpul,@-r15
+	bf LOCAL(huge_divisor)
+	mov.l r1,@-r15
+	lds r4,fpul
+	cmp/pz r4
+#ifdef FMOVD_WORKS
+	fmov.d dr0,@-r15
+	float fpul,dr0
+	fmov.d dr2,@-r15
+	bt LOCAL(dividend_adjusted)
+	mov #1,r1
+	fmov.d @r0,dr2
+	cmp/eq r1,r5
+	bt LOCAL(div_by_1)
+	fadd dr2,dr0
+LOCAL(dividend_adjusted):
+	lds r5,fpul
+	float fpul,dr2
+	fdiv dr2,dr0
+LOCAL(div_by_1):
+	fmov.d @r15+,dr2
+	ftrc dr0,fpul
+	fmov.d @r15+,dr0
+#else /* !FMOVD_WORKS */
+	fmov.s DR01,@-r15
+	mov #1,r1
+	fmov.s DR00,@-r15
+	float fpul,dr0
+	fmov.s DR21,@-r15
+	bt/s LOCAL(dividend_adjusted)
+	fmov.s DR20,@-r15
+	cmp/eq r1,r5
+	bt LOCAL(div_by_1)
+	fmov.s @r0+,DR20
+	fmov.s @r0,DR21
+	fadd dr2,dr0
+LOCAL(dividend_adjusted):
+	lds r5,fpul
+	float fpul,dr2
+	fdiv dr2,dr0
+LOCAL(div_by_1):
+	fmov.s @r15+,DR20
+	fmov.s @r15+,DR21
+	ftrc dr0,fpul
+	fmov.s @r15+,DR00
+	fmov.s @r15+,DR01
+#endif /* !FMOVD_WORKS */
+	lds.l @r15+,fpscr
+	sts fpul,r0
+	rts
+	lds.l @r15+,fpul
+
+#ifdef FMOVD_WORKS
+	.p2align 3        ! make double below 8 byte aligned.
+#endif
+LOCAL(huge_divisor):
+	lds r1,fpscr
+	add #4,r15
+	cmp/hs r5,r4
+	rts
+	movt r0
+
+	.p2align 2
+L1:
+#ifndef FMOVD_WORKS
+	.long 0x80000
+#else
+	.long 0x180000
+#endif
+	.double 4294967296
+
+	ENDFUNC(GLOBAL(udivsi3_i4i))
+#elif !defined (__sh1__)  /* !__SH_FPU_DOUBLE__ */
+
+#if 0
+/* With 36 bytes, the following would probably be the most compact
+   implementation, but with 139 cycles on an sh4-200, it is extremely slow.  */
+GLOBAL(udivsi3_i4i):
+	mov.l r2,@-r15
+	mov #0,r1
+	div0u
+	mov r1,r2
+	mov.l r3,@-r15
+	mov r1,r3
+	sett
+	mov r4,r0
+LOCAL(loop):
+	rotcr r2
+	;
+	bt/s LOCAL(end)
+	cmp/gt r2,r3
+	rotcl r0
+	bra LOCAL(loop)
+	div1 r5,r1
+LOCAL(end):
+	rotcl r0
+	mov.l @r15+,r3
+	rts
+	mov.l @r15+,r2
+#endif /* 0 */
+
+/* Size: 188 bytes jointly for udivsi3_i4i and sdivsi3_i4i
+   sh4-200 run times:
+   udiv small divisor: 55 cycles
+   udiv large divisor: 52 cycles
+   sdiv small divisor, positive result: 59 cycles
+   sdiv large divisor, positive result: 56 cycles
+   sdiv small divisor, negative result: 65 cycles (*)
+   sdiv large divisor, negative result: 62 cycles (*)
+   (*): r2 is restored in the rts delay slot and has a lingering latency
+        of two more cycles.  */
+	.balign 4
+	.global	GLOBAL(udivsi3_i4i)
+	FUNC(GLOBAL(udivsi3_i4i))
+	FUNC(GLOBAL(sdivsi3_i4i))
+GLOBAL(udivsi3_i4i):
+	sts pr,r1
+	mov.l r4,@-r15
+	extu.w r5,r0
+	cmp/eq r5,r0
+	swap.w r4,r0
+	shlr16 r4
+	bf/s LOCAL(large_divisor)
+	div0u
+	mov.l r5,@-r15
+	shll16 r5
+LOCAL(sdiv_small_divisor):
+	div1 r5,r4
+	bsr LOCAL(div6)
+	div1 r5,r4
+	div1 r5,r4
+	bsr LOCAL(div6)
+	div1 r5,r4
+	xtrct r4,r0
+	xtrct r0,r4
+	bsr LOCAL(div7)
+	swap.w r4,r4
+	div1 r5,r4
+	bsr LOCAL(div7)
+	div1 r5,r4
+	xtrct r4,r0
+	mov.l @r15+,r5
+	swap.w r0,r0
+	mov.l @r15+,r4
+	jmp @r1
+	rotcl r0
+LOCAL(div7):
+	div1 r5,r4
+LOCAL(div6):
+	            div1 r5,r4; div1 r5,r4; div1 r5,r4
+	div1 r5,r4; div1 r5,r4; rts;        div1 r5,r4
+
+LOCAL(divx3):
+	rotcl r0
+	div1 r5,r4
+	rotcl r0
+	div1 r5,r4
+	rotcl r0
+	rts
+	div1 r5,r4
+
+LOCAL(large_divisor):
+	mov.l r5,@-r15
+LOCAL(sdiv_large_divisor):
+	xor r4,r0
+	.rept 4
+	rotcl r0
+	bsr LOCAL(divx3)
+	div1 r5,r4
+	.endr
+	mov.l @r15+,r5
+	mov.l @r15+,r4
+	jmp @r1
+	rotcl r0
+	ENDFUNC(GLOBAL(udivsi3_i4i))
+
+	.global	GLOBAL(sdivsi3_i4i)
+GLOBAL(sdivsi3_i4i):
+	mov.l r4,@-r15
+	cmp/pz r5
+	mov.l r5,@-r15
+	bt/s LOCAL(pos_divisor)
+	cmp/pz r4
+	neg r5,r5
+	extu.w r5,r0
+	bt/s LOCAL(neg_result)
+	cmp/eq r5,r0
+	neg r4,r4
+LOCAL(pos_result):
+	swap.w r4,r0
+	bra LOCAL(sdiv_check_divisor)
+	sts pr,r1
+LOCAL(pos_divisor):
+	extu.w r5,r0
+	bt/s LOCAL(pos_result)
+	cmp/eq r5,r0
+	neg r4,r4
+LOCAL(neg_result):
+	mova LOCAL(negate_result),r0
+	;
+	mov r0,r1
+	swap.w r4,r0
+	lds r2,macl
+	sts pr,r2
+LOCAL(sdiv_check_divisor):
+	shlr16 r4
+	bf/s LOCAL(sdiv_large_divisor)
+	div0u
+	bra LOCAL(sdiv_small_divisor)
+	shll16 r5
+	.balign 4
+LOCAL(negate_result):
+	neg r0,r0
+	jmp @r2
+	sts macl,r2
+	ENDFUNC(GLOBAL(sdivsi3_i4i))
+#endif /* !__SH_FPU_DOUBLE__ */
+#endif /* L_udivsi3_i4i */
+
+#ifdef L_sdivsi3_i4i
+#if defined (__SH_FPU_DOUBLE__) || defined (__SH4_SINGLE_ONLY__)
+/* 48 bytes, 45 cycles on sh4-200  */
+!! args in r4 and r5, result in r0, clobber r1
+
+	.global GLOBAL(sdivsi3_i4i)
+	FUNC(GLOBAL(sdivsi3_i4i))
+GLOBAL(sdivsi3_i4i):
+	sts.l fpscr,@-r15
+	sts fpul,r1
+	mova L1,r0
+	lds.l @r0+,fpscr
+	lds r4,fpul
+#ifdef FMOVD_WORKS
+	fmov.d dr0,@-r15
+	float fpul,dr0
+	lds r5,fpul
+	fmov.d dr2,@-r15
+#else
+	fmov.s DR01,@-r15
+	fmov.s DR00,@-r15
+	float fpul,dr0
+	lds r5,fpul
+	fmov.s DR21,@-r15
+	fmov.s DR20,@-r15
+#endif
+	float fpul,dr2
+	fdiv dr2,dr0
+#ifdef FMOVD_WORKS
+	fmov.d @r15+,dr2
+#else
+	fmov.s @r15+,DR20
+	fmov.s @r15+,DR21
+#endif
+	ftrc dr0,fpul
+#ifdef FMOVD_WORKS
+	fmov.d @r15+,dr0
+#else
+	fmov.s @r15+,DR00
+	fmov.s @r15+,DR01
+#endif
+	lds.l @r15+,fpscr
+	sts fpul,r0
+	rts
+	lds r1,fpul
+
+	.p2align 2
+L1:
+#ifndef FMOVD_WORKS
+	.long 0x80000
+#else
+	.long 0x180000
+#endif
+
+	ENDFUNC(GLOBAL(sdivsi3_i4i))
+#endif /* __SH_FPU_DOUBLE__ */
+#endif /* L_sdivsi3_i4i */
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/predicates.md gcc-4.1.1/gcc/config/sh/predicates.md
--- gcc-4.1.1.orig/gcc/config/sh/predicates.md	2005-07-21 01:55:20.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/predicates.md	2006-08-10 09:56:05.000000000 +0100
@@ -1,5 +1,6 @@
 ;; Predicate definitions for Renesas / SuperH SH.
 ;; Copyright (C) 2005 Free Software Foundation, Inc.
+;; Copyright (c) 2006  STMicroelectronics.
 ;;
 ;; This file is part of GCC.
 ;;
@@ -243,9 +244,10 @@   switch (GET_CODE (op))
   return 0;
 })
 
-;; TODO: Add a comment here.
+;; Return 1 of OP is an address suitable for a cache manipulation operation.
+;; MODE has the meaning as in address_operand.
 
-(define_predicate "cache_address_operand"
+(define_special_predicate "cache_address_operand"
   (match_code "plus,reg")
 {
   if (GET_CODE (op) == PLUS)
@@ -541,21 +543,7 @@   return true_regnum (op) <= LAST_GENERA
 ;; TODO: Add a comment here.
 
 (define_predicate "less_comparison_operator"
-  (match_code "lt,le,ltu,leu")
-{
-  if (mode != VOIDmode && GET_MODE (op) != mode)
-    return 0;
-  switch (GET_CODE (op))
-    {
-    case LT:
-    case LE:
-    case LTU:
-    case LEU:
-      return 1;
-    default:
-      return 0;
-    }
-})
+  (match_code "lt,le,ltu,leu"))
 
 ;; Returns 1 if OP is a valid source operand for a logical operation.
 
@@ -861,9 +849,9 @@   if (op_mode != SImode && op_mode != DI
   return extend_reg_operand (op, mode);
 })
 
-;; TODO: Add a comment here.
+;; Return 1 of OP is an address suitable for an unaligned access instruction.
 
-(define_predicate "ua_address_operand"
+(define_special_predicate "ua_address_operand"
   (match_code "subreg,reg,plus")
 {
   if (GET_CODE (op) == PLUS
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/sh1.md gcc-4.1.1/gcc/config/sh/sh1.md
--- gcc-4.1.1.orig/gcc/config/sh/sh1.md	2005-06-25 02:22:41.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/sh1.md	2006-08-10 09:56:05.000000000 +0100
@@ -1,5 +1,6 @@
 ;; DFA scheduling description for Renesas / SuperH SH.
 ;; Copyright (C) 2004 Free Software Foundation, Inc.
+;; Copyright (c) 2006  STMicroelectronics.
 
 ;; This file is part of GCC.
 
@@ -45,7 +46,7 @@        (eq_attr "type" "load_si,pcload_s
 
 (define_insn_reservation "sh1_load_store" 2
   (and (eq_attr "pipe_model" "sh1")
-       (eq_attr "type" "load,pcload,pload,store,pstore"))
+       (eq_attr "type" "load,pcload,pload,mem_mac,store,fstore,pstore,mac_mem"))
   "sh1memory*2")
 
 (define_insn_reservation "sh1_arith3" 3
@@ -76,7 +77,7 @@        (eq_attr "type" "dmpy"))
 
 (define_insn_reservation "sh1_fp" 2
   (and (eq_attr "pipe_model" "sh1")
-       (eq_attr "type" "fp,fmove"))
+       (eq_attr "type" "fp,fpscr_toggle,fp_cmp,fmove"))
   "sh1fp")
 
 (define_insn_reservation "sh1_fdiv" 13
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/sh4-300.md gcc-4.1.1/gcc/config/sh/sh4-300.md
--- gcc-4.1.1.orig/gcc/config/sh/sh4-300.md	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/sh4-300.md	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,290 @@
+;; DFA scheduling description for ST40-300.
+;; Copyright (C) 2004 Free Software Foundation, Inc.
+;; Copyright (C) 2006 STMicroelectronics (Will be assigned to FSF when
+;; patch is contributed.)
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;; Load and store instructions save a cycle if they are aligned on a
+;; four byte boundary.  Using a function unit for stores encourages
+;; gcc to separate load and store instructions by one instruction,
+;; which makes it more likely that the linker will be able to word
+;; align them when relaxing.
+
+;; The following description models the ST40-300 pipeline using the DFA based
+;; scheduler.
+
+;; Two automata are defined to reduce number of states
+;; which a single large automaton will have. (Factoring)
+
+(define_automaton "sh4_300_inst_pipeline,sh4_300_fpu_pipe")
+
+;; This unit is basically the decode unit of the processor.
+;; Since SH4 is a dual issue machine,it is as if there are two
+;; units so that any insn can be processed by either one
+;; of the decoding unit.
+
+(define_cpu_unit "sh4_300_pipe_01,sh4_300_pipe_02" "sh4_300_inst_pipeline")
+
+;; The floating point units.
+
+(define_cpu_unit "sh4_300_fpt,sh4_300_fpu,sh4_300_fds" "sh4_300_fpu_pipe")
+
+;; integer multiplier unit
+
+(define_cpu_unit "sh4_300_mul" "sh4_300_inst_pipeline")
+
+;; LS unit
+
+(define_cpu_unit "sh4_300_ls" "sh4_300_inst_pipeline")
+
+;; The address calculator used for branch instructions.
+;; This will be reserved after "issue" of branch instructions
+;; and this is to make sure that no two branch instructions
+;; can be issued in parallel.
+
+(define_cpu_unit "sh4_300_br" "sh4_300_inst_pipeline")
+
+;; ----------------------------------------------------
+;; This reservation is to simplify the dual issue description.
+
+(define_reservation  "sh4_300_issue"  "sh4_300_pipe_01|sh4_300_pipe_02")
+
+(define_reservation "all" "sh4_300_pipe_01+sh4_300_pipe_02")
+
+;;(define_insn_reservation "nil" 0 (eq_attr "type" "nil") "nothing")
+
+;; MOV RM,RN / MOV #imm8,RN / STS PR,RN
+(define_insn_reservation "sh4_300_mov" 0
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "move,movi8,prget"))
+  "sh4_300_issue")
+
+;; Fixed STS from MACL / MACH
+(define_insn_reservation "sh4_300_mac_gp" 0
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "mac_gp"))
+  "sh4_300_issue+sh4_300_mul")
+
+;; Fixed LDS to MACL / MACH
+(define_insn_reservation "sh4_300_gp_mac" 1
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "gp_mac"))
+  "sh4_300_issue+sh4_300_mul")
+
+;; Instructions without specific resource requirements with latency 1.
+
+(define_insn_reservation "sh4_300_simple_arith" 1
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "mt_group,arith,dyn_shift,prset"))
+  "sh4_300_issue")
+
+;; Load and store instructions have no alignment peculiarities for the ST40-300,
+;; but they use the load-store unit, which they share with the fmove type
+;; insns (fldi[01]; fmov frn,frm; flds; fsts; fabs; fneg) .
+;; Loads have a latency of three.
+
+;; Load Store instructions.
+(define_insn_reservation "sh4_300_load" 3
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "load,pcload,load_si,pcload_si,pload"))
+  "sh4_300_issue+sh4_300_ls")
+
+(define_insn_reservation "sh4_300_mac_load" 3
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "mem_mac"))
+  "sh4_300_issue+sh4_300_ls+sh4_300_mul")
+
+(define_insn_reservation "sh4_300_fload" 4
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "fload,pcfload"))
+  "sh4_300_issue+sh4_300_ls+sh4_300_fpt")
+
+;; sh_adjust_cost describes the reduced latency of the feeding insns of a store.
+;; The latency of an auto-increment register is 1; the latency of the memory
+;; output is not actually considered here anyway.
+(define_insn_reservation "sh4_300_store" 1
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "store,pstore"))
+  "sh4_300_issue+sh4_300_ls")
+
+(define_insn_reservation "sh4_300_fstore" 1
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "fstore"))
+  "sh4_300_issue+sh4_300_ls+sh4_300_fpt")
+
+;; Fixed STS.L from MACL / MACH
+(define_insn_reservation "sh4_300_mac_store" 1
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "mac_mem"))
+  "sh4_300_issue+sh4_300_mul+sh4_300_ls")
+
+(define_insn_reservation "sh4_300_gp_fpul" 2
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "gp_fpul"))
+  "sh4_300_issue+sh4_300_fpt")
+
+(define_insn_reservation "sh4_300_fpul_gp" 1
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "fpul_gp"))
+  "sh4_300_issue+sh4_300_fpt")
+
+;; Branch (BF,BF/S,BT,BT/S,BRA)
+;; Branch Far (JMP,RTS,BRAF)
+;; Group:	BR
+;; When displacement is 0 for BF / BT, we have effectively conditional
+;; execution of one instruction, without pipeline disruption.
+;; Otherwise, the latency depends on prediction success.
+;; We can't really do much with the latency, even if we could express it,
+;; but the pairing restrictions are useful to take into account.
+;; ??? If the branch is likely, and not paired with a preceding insn,
+;; or likely and likely not predicted, we might want to fill the delay slot.
+;; However, there appears to be no machinery to make the compiler
+;; recognize these scenarios.
+
+(define_insn_reservation "sh4_300_branch"  1
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "cbranch,jump,return,jump_ind"))
+  "sh4_300_issue+sh4_300_br")
+
+;; RTE
+(define_insn_reservation "sh4_300_return_from_exp" 9
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "rte"))
+  "sh4_300_pipe_01+sh4_300_pipe_02*9")
+
+;; OCBP, OCBWB
+;; Group:	CO
+;; Latency: 	1-5
+;; Issue Rate: 	1
+
+;; cwb is used for the sequence ocbwb @%0; extu.w %0,%2; or %1,%2; mov.l %0,@%2
+;; This description is likely inexact, but this pattern should not actually
+;; appear when compiling for sh4-300; we should use isbi instead.
+;; If a -mtune option is added later, we should use the icache array
+;; dispatch method instead.
+(define_insn_reservation "sh4_300_ocbwb"  3
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "cwb"))
+  "all*3")
+
+;; JSR,BSR,BSRF
+;; Calls have a mandatory delay slot, which we'd like to fill with an insn
+;; that can be paired with the call itself.
+;; Scheduling runs before reorg, so we approximate this by saying that we
+;; want the call to be paired with a preceding insn.
+;; In most cases, the insn that loads the address of the call should have
+;; a non-zero latency (mov rn,rm doesn't make sense since we could use rn
+;; for the address then).  Thus, a preceding insn that can be paired with
+;; a call should be elegible for the delay slot.
+;;
+;; calls introduce a longisch delay that is likely to flush the pipelines
+;; of the caller's instructions.  Ordinary functions tend to end with a
+;; load to restore a register (in the delay slot of rts), while sfuncs
+;; tend to end with an EX or MT insn.  But that is not actually relevant,
+;; since there are no instructions that contend for memory access early.
+;; We could, of course, provide exact scheduling information for specific
+;; sfuncs, if that should prove useful.
+
+(define_insn_reservation "sh4_300_call" 16
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "call,sfunc"))
+  "sh4_300_issue+sh4_300_br,all*15")
+
+;; FMOV.S / FMOV.D
+(define_insn_reservation "sh4_300_fmov" 1
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "fmove"))
+  "sh4_300_issue+sh4_300_fpt")
+
+;; LDS to FPSCR
+(define_insn_reservation "sh4_300_fpscr_load" 8
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "gp_fpscr"))
+  "sh4_300_issue+sh4_300_fpu+sh4_300_fpt")
+
+;; LDS.L to FPSCR
+(define_insn_reservation "sh4_300_fpscr_load_mem" 8
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type"  "mem_fpscr"))
+  "sh4_300_issue+sh4_300_fpu+sh4_300_fpt+sh4_300_ls")
+
+
+;; Fixed point multiplication (DMULS.L DMULU.L MUL.L MULS.W,MULU.W)
+(define_insn_reservation "multi" 2
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "smpy,dmpy"))
+  "sh4_300_issue+sh4_300_mul")
+
+;; FPCHG, FRCHG, FSCHG
+(define_insn_reservation "fpscr_toggle"  1
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "fpscr_toggle"))
+  "sh4_300_issue+sh4_300_fpu+sh4_300_fpt")
+
+;; FCMP/EQ, FCMP/GT
+(define_insn_reservation "fp_cmp"  3
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "fp_cmp,dfp_cmp"))
+  "sh4_300_issue+sh4_300_fpu")
+
+;; Single precision floating point (FADD,FLOAT,FMAC,FMUL,FSUB,FTRC)
+;; Double-precision floating-point (FADD,FCNVDS,FCNVSD,FLOAT,FSUB,FTRC)
+(define_insn_reservation "fp_arith"  6
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "fp,ftrc_s,dfp_arith,dfp_conv"))
+  "sh4_300_issue+sh4_300_fpu")
+
+;; Single Precision FDIV/SQRT
+(define_insn_reservation "fp_div" 19
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "fdiv"))
+  "sh4_300_issue+sh4_300_fpu+sh4_300_fds,sh4_300_fds*15")
+
+;; Double-precision floating-point FMUL
+(define_insn_reservation "dfp_mul" 9
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "dfp_mul"))
+  "sh4_300_issue+sh4_300_fpu,sh4_300_fpu*3")
+
+;; Double precision FDIV/SQRT
+(define_insn_reservation "dp_div" 35
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "dfdiv"))
+  "sh4_300_issue+sh4_300_fpu+sh4_300_fds,sh4_300_fds*31")
+
+
+;; ??? We don't really want these for sh4-300.
+;; this pattern itself is likely to finish in 3 cycles, but also
+;; to disrupt branch prediction for taken branches for the following
+;; condbranch.
+(define_insn_reservation "sh4_300_arith3" 5
+  (and (eq_attr "pipe_model" "sh4_300")
+       (eq_attr "type" "arith3"))
+  "sh4_300_issue,all*4")
+
+;; arith3b insns without brach redirection make use of the 0-offset 0-latency
+;; branch feature, and thus schedule the same no matter if the branch is taken
+;; or not.  If the branch is redirected, the taken branch might take longer,
+;; but then, we don't have to take the next branch.
+;; ??? should we suppress branch redirection for sh4-300 to improve branch
+;; target hit rates?
+(define_insn_reservation "arith3b" 2
+  (and (eq_attr "pipe_model" "sh4")
+       (eq_attr "type" "arith3"))
+  "issue,all")
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/sh4a.md gcc-4.1.1/gcc/config/sh/sh4a.md
--- gcc-4.1.1.orig/gcc/config/sh/sh4a.md	2005-06-25 02:22:41.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/sh4a.md	2006-08-10 09:56:05.000000000 +0100
@@ -1,5 +1,6 @@
 ;; Scheduling description for Renesas SH4a
 ;; Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+;; Copyright (c) 2006  STMicroelectronics.
 ;;
 ;; This file is part of GCC.
 ;;
@@ -98,9 +99,11 @@        (eq_attr "type" "mova"))
 ;; MOV
 ;; Group: MT
 ;; Latency: 0
+;; ??? not sure if movi8 belongs here, but that's where it was
+;; effectively before.
 (define_insn_reservation "sh4a_mov" 0
   (and (eq_attr "cpu" "sh4a")
-       (eq_attr "type" "move"))
+       (eq_attr "type" "move,movi8,gp_mac"))
   "ID_or")
 
 ;; Load
@@ -108,7 +111,7 @@        (eq_attr "type" "move"))
 ;; Latency: 3
 (define_insn_reservation "sh4a_load" 3
   (and (eq_attr "cpu" "sh4a")
-       (eq_attr "type" "load,pcload"))
+       (eq_attr "type" "load,pcload,mem_mac"))
   "sh4a_ls+sh4a_memory")
 
 (define_insn_reservation "sh4a_load_si" 3
@@ -121,7 +124,7 @@        (eq_attr "type" "load_si,pcload_s
 ;; Latency: 0
 (define_insn_reservation "sh4a_store" 0
   (and (eq_attr "cpu" "sh4a")
-       (eq_attr "type" "store"))
+       (eq_attr "type" "store,fstore,mac_mem"))
   "sh4a_ls+sh4a_memory")
 
 ;; CWB TYPE
@@ -177,7 +180,7 @@        (eq_attr "type" "fmove"))
 ;; Latency: 	3
 (define_insn_reservation "sh4a_fp_arith"  3
   (and (eq_attr "cpu" "sh4a")
-       (eq_attr "type" "fp"))
+       (eq_attr "type" "fp,fp_cmp,fpscr_toggle"))
   "ID_or,sh4a_fex")
 
 (define_insn_reservation "sh4a_fp_arith_ftrc"  3
@@ -207,7 +210,7 @@ ;; Double-precision floating-point (FADD
 ;; Latency: 	5
 (define_insn_reservation "sh4a_fp_double_arith" 5
   (and (eq_attr "cpu" "sh4a")
-       (eq_attr "type" "dfp_arith"))
+       (eq_attr "type" "dfp_arith,dfp_mul"))
   "ID_or,sh4a_fex*3")
 
 ;; Double precision FDIV/SQRT
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/sh4.md gcc-4.1.1/gcc/config/sh/sh4.md
--- gcc-4.1.1.orig/gcc/config/sh/sh4.md	2005-06-25 02:22:41.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/sh4.md	2006-08-10 09:56:05.000000000 +0100
@@ -1,5 +1,6 @@
 ;; DFA scheduling description for SH4.
 ;; Copyright (C) 2004 Free Software Foundation, Inc.
+;; Copyright (c) 2006  STMicroelectronics.
 
 ;; This file is part of GCC.
 
@@ -209,9 +210,14 @@ ;; (define_bypass 2 "sh4_fload" "!")
 
 (define_insn_reservation "sh4_store" 1
   (and (eq_attr "pipe_model" "sh4")
-       (eq_attr "type" "store"))
+       (eq_attr "type" "store,fstore"))
   "issue+load_store,nothing,memory")
 
+(define_insn_reservation "mac_mem" 1
+  (and (eq_attr "pipe_model" "sh4")
+       (eq_attr "type" "mac_mem"))
+  "d_lock,nothing,memory")
+
 ;; Load Store instructions.
 ;; Group:	LS
 ;; Latency: 	1
@@ -372,35 +378,42 @@   "d_lock,nothing,(F1+memory),F1*2")
 ;; Fixed point multiplication (DMULS.L DMULU.L MUL.L MULS.W,MULU.W)
 ;; Group:	CO
 ;; Latency: 	4 / 4
-;; Issue Rate: 	1
+;; Issue Rate: 	2
 
 (define_insn_reservation "multi" 4
   (and (eq_attr "pipe_model" "sh4")
        (eq_attr "type" "smpy,dmpy"))
   "d_lock,(d_lock+f1_1),(f1_1|f1_2)*3,F2")
 
-;; Fixed STS from MACL / MACH
+;; Fixed STS from, and LDS to MACL / MACH
 ;; Group:	CO
 ;; Latency: 	3
 ;; Issue Rate: 	1
 
 (define_insn_reservation "sh4_mac_gp" 3
   (and (eq_attr "pipe_model" "sh4")
-       (eq_attr "type" "mac_gp"))
+       (eq_attr "type" "mac_gp,gp_mac,mem_mac"))
   "d_lock")
 
 
 ;; Single precision floating point computation FCMP/EQ,
-;; FCMP/GT, FADD, FLOAT, FMAC, FMUL, FSUB, FTRC, FRVHG, FSCHG
+;; FCMP/GT, FADD, FLOAT, FMAC, FMUL, FSUB, FTRC, FRCHG, FSCHG
 ;; Group:	FE
 ;; Latency: 	3/4
 ;; Issue Rate: 	1
 
 (define_insn_reservation "fp_arith"  3
   (and (eq_attr "pipe_model" "sh4")
-       (eq_attr "type" "fp"))
+       (eq_attr "type" "fp,fp_cmp"))
   "issue,F01,F2")
 
+;; We don't model the resource usage of this exactly because that would
+;; introduce a bogus latency.
+(define_insn_reservation "sh4_fpscr_toggle"  1
+  (and (eq_attr "pipe_model" "sh4")
+       (eq_attr "type" "fpscr_toggle"))
+  "issue")
+
 (define_insn_reservation "fp_arith_ftrc"  3
   (and (eq_attr "pipe_model" "sh4")
        (eq_attr "type" "ftrc_s"))
@@ -437,7 +450,7 @@ ;; Latency: 	(7,8)/9
 
 (define_insn_reservation "fp_double_arith" 8
   (and (eq_attr "pipe_model" "sh4")
-       (eq_attr "type" "dfp_arith"))
+       (eq_attr "type" "dfp_arith,dfp_mul"))
   "issue,F01,F1+F2,fpu*4,F2")
 
 ;; Double-precision FCMP (FCMP/EQ,FCMP/GT)
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/sh.c gcc-4.1.1/gcc/config/sh/sh.c
--- gcc-4.1.1.orig/gcc/config/sh/sh.c	2006-02-14 14:46:33.000000000 +0000
+++ gcc-4.1.1/gcc/config/sh/sh.c	2006-08-10 09:56:05.000000000 +0100
@@ -3,6 +3,7 @@    Copyright (C) 1993, 1994, 1995, 1996,
    2003, 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Steve Chamberlain (sac@cygnus.com).
    Improved by Jim Wilson (wilson@cygnus.com).
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -520,18 +521,33 @@       target_flags = (target_flags & ~MA
       return true;
 
     case OPT_m4:
+    case OPT_m4_100:
+    case OPT_m4_200:
+    case OPT_m4_300:
       target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4;
       return true;
 
     case OPT_m4_nofpu:
+    case OPT_m4_100_nofpu:
+    case OPT_m4_200_nofpu:
+    case OPT_m4_300_nofpu:
+    case OPT_m4_340:
+    case OPT_m4_400:
+    case OPT_m4_500:
       target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4_NOFPU;
       return true;
 
     case OPT_m4_single:
+    case OPT_m4_100_single:
+    case OPT_m4_200_single:
+    case OPT_m4_300_single:
       target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4_SINGLE;
       return true;
 
     case OPT_m4_single_only:
+    case OPT_m4_100_single_only:
+    case OPT_m4_200_single_only:
+    case OPT_m4_300_single_only:
       target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4_SINGLE_ONLY;
       return true;
 
@@ -650,7 +666,8 @@    '''  print likelihood suffix (/u for 
    'R'  print the LSW of a dp value - changes if in little endian
    'S'  print the MSW of a dp value - changes if in little endian
    'T'  print the next word of a dp value - same as 'R' in big endian mode.
-   'M'  print an `x' if `m' will print `base,index'.
+   'M'  SHMEDIA: print an `x' if `m' will print `base,index'.
+        otherwise: print .b / .w / .l / .s / .d suffix if operand is a MEM.
    'N'  print 'r63' if the operand is (const_int 0).
    'd'  print a V2SF reg as dN instead of fpN.
    'm'  print a pair `base,offset' or `base,index', for LD and ST.
@@ -808,11 +825,29 @@ 	case GEU: case LEU: fputs ("geu", strea
 	}
       break;
     case 'M':
-      if (GET_CODE (x) == MEM
-	  && GET_CODE (XEXP (x, 0)) == PLUS
-	  && (GET_CODE (XEXP (XEXP (x, 0), 1)) == REG
-	      || GET_CODE (XEXP (XEXP (x, 0), 1)) == SUBREG))
-	fputc ('x', stream);
+      if (TARGET_SHMEDIA)
+	{
+	  if (GET_CODE (x) == MEM
+	      && GET_CODE (XEXP (x, 0)) == PLUS
+	      && (GET_CODE (XEXP (XEXP (x, 0), 1)) == REG
+		  || GET_CODE (XEXP (XEXP (x, 0), 1)) == SUBREG))
+	    fputc ('x', stream);
+	}
+      else
+	{
+	  if (GET_CODE (x) == MEM)
+	    {
+	      switch (GET_MODE (x))
+		{
+		case QImode: fputs (".b", stream); break;
+		case HImode: fputs (".w", stream); break;
+		case SImode: fputs (".l", stream); break;
+		case SFmode: fputs (".s", stream); break;
+		case DFmode: fputs (".d", stream); break;
+		default: gcc_unreachable ();
+		}
+	    }
+	}
       break;
 
     case 'm':
@@ -1305,6 +1340,216 @@ 	    emit_insn (gen_addsi3 (op1, op1, fo
   return 0;
 }
 
+enum rtx_code
+prepare_cbranch_operands (rtx *operands, enum machine_mode mode,
+			  enum rtx_code comparison)
+{
+  rtx op1;
+  rtx scratch = NULL_RTX;
+
+  if (comparison == CODE_FOR_nothing)
+    comparison = GET_CODE (operands[0]);
+  else
+    scratch = operands[4];
+  if (GET_CODE (operands[1]) == CONST_INT
+      && GET_CODE (operands[2]) != CONST_INT)
+    {
+      rtx tmp = operands[1];
+
+      operands[1] = operands[2];
+      operands[2] = tmp;
+      comparison = swap_condition (comparison);
+    }
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      HOST_WIDE_INT val = INTVAL (operands[2]);
+      if ((val == -1 || val == -0x81)
+	  && (comparison == GT || comparison == LE))
+	{
+	  comparison = (comparison == GT) ? GE : LT;
+	  operands[2] = gen_int_mode (val + 1, mode);
+	}
+      else if ((val == 1 || val == 0x80)
+	       && (comparison == GE || comparison == LT))
+	{
+	  comparison = (comparison == GE) ? GT : LE;
+	  operands[2] = gen_int_mode (val - 1, mode);
+	}
+      else if (val == 1 && (comparison == GEU || comparison == LTU))
+	{
+	  comparison = (comparison == GEU) ? NE : EQ;
+	  operands[2] = CONST0_RTX (mode);
+	}
+      else if (val == 0x80 && (comparison == GEU || comparison == LTU))
+	{
+	  comparison = (comparison == GEU) ? GTU : LEU;
+	  operands[2] = gen_int_mode (val - 1, mode);
+	}
+      else if (val == 0 && (comparison == GTU || comparison == LEU))
+	comparison = (comparison == GTU) ? NE : EQ;
+      else if (mode == SImode
+	       && ((val == 0x7fffffff
+		    && (comparison == GTU || comparison == LEU))
+		   || ((unsigned HOST_WIDE_INT) val
+			== (unsigned HOST_WIDE_INT) 0x7fffffff + 1
+		       && (comparison == GEU || comparison == LTU))))
+	{
+	  comparison = (comparison == GTU || comparison == GEU) ? LT : GE;
+	  operands[2] = CONST0_RTX (mode);
+	}
+    }
+  op1 = operands[1];
+  if (!no_new_pseudos)
+    operands[1] = force_reg (mode, op1);
+  /* When we are handling DImode comparisons, we want to keep constants so
+     that we can optimize the component comparisons; however, memory loads
+     are better issued as a whole so that they can be scheduled well.
+     SImode equality comparisons allow I08 constants, but only when they
+     compare r0.  Hence, if operands[1] has to be loaded from somewhere else
+     into a register, that register might as well be r0, and we allow the
+     constant.  If it is already in a register, this is likely to be
+     allocatated to a different hard register, thus we load the constant into
+     a register unless it is zero.  */
+  if (!REG_P (operands[2])
+      && (GET_CODE (operands[2]) != CONST_INT
+	  || (mode == SImode && operands[2] != CONST0_RTX (SImode)
+	      && ((comparison != EQ && comparison != NE)
+		  || (REG_P (op1) && REGNO (op1) != R0_REG)
+		  || !CONST_OK_FOR_I08 (INTVAL (operands[2]))))))
+    {
+      if (scratch && GET_MODE (scratch) == mode)
+	{
+	  emit_move_insn (scratch, operands[2]);
+	  operands[2] = scratch;
+	}
+      else if (!no_new_pseudos)
+	operands[2] = force_reg (mode, operands[2]);
+    }
+  return comparison;
+}
+
+void
+expand_cbranchsi4 (rtx *operands, enum rtx_code comparison)
+{
+  rtx (*branch_expander) (rtx) = gen_branch_true;
+
+  comparison = prepare_cbranch_operands (operands, SImode, comparison);
+  switch (comparison)
+    {
+    case NE: case LT: case LE: case LTU: case LEU:
+      comparison = reverse_condition (comparison);
+      branch_expander = gen_branch_false;
+    default: ;
+    }
+  emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, T_REG),
+                          gen_rtx_fmt_ee (comparison, SImode,
+                                          operands[1], operands[2])));
+  emit_jump_insn (branch_expander (operands[3]));
+}
+
+bool
+expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
+{
+  enum rtx_code msw_taken, msw_skip, lsw_taken;
+  rtx skip_label;
+  rtx op1h, op1l, op2h, op2l;
+
+  comparison = prepare_cbranch_operands (operands, DImode, comparison);
+  op1h = gen_highpart_mode (SImode, DImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  msw_taken = msw_skip = lsw_taken = CODE_FOR_nothing;
+  switch (comparison)
+    {
+    /* ??? Should we use the cmpeqdi_t pattern for equality comparisons?
+       That costs 1 cycle more when the first branch can be predicted taken,
+       but saves us mispredicts because only one branch needs prediction.
+       It also enables generating the cmpeqdi_t-1 pattern.  */
+    case EQ:
+      if (TARGET_CMPEQDI_T)
+	{
+	  emit_insn (gen_cmpeqdi_t (operands[1], operands[2]));
+	  emit_jump_insn (gen_branch_true (operands[3]));
+	  return true;
+	}
+      msw_skip = NE;
+      lsw_taken = EQ;
+      break;
+    case NE:
+      if (TARGET_CMPEQDI_T)
+	{
+	  emit_insn (gen_cmpeqdi_t (operands[1], operands[2]));
+	  emit_jump_insn (gen_branch_false (operands[3]));
+	  return true;
+	}
+      msw_taken = NE;
+      lsw_taken = NE;
+      break;
+    case GTU: case GT:
+      msw_taken = comparison;
+      if (GET_CODE (op2l) == CONST_INT && INTVAL (op2l) == -1)
+	break;
+      if (comparison != GTU || op2h != CONST0_RTX (SImode))
+	msw_skip = swap_condition (msw_taken);
+      lsw_taken = GTU;
+      break;
+    case GEU: case GE:
+      if (op2l == CONST0_RTX (SImode))
+	msw_taken = comparison;
+      else
+	{
+	  msw_taken = comparison == GE ? GT : GTU;
+	  msw_skip = swap_condition (msw_taken);
+	  lsw_taken = GEU;
+	}
+      break;
+    case LTU: case LT:
+      msw_taken = comparison;
+      if (op2l == CONST0_RTX (SImode))
+	break;
+      msw_skip = swap_condition (msw_taken);
+      lsw_taken = LTU;
+      break;
+    case LEU: case LE:
+      if (GET_CODE (op2l) == CONST_INT && INTVAL (op2l) == -1)
+	msw_taken = comparison;
+      else
+	{
+	  lsw_taken = LEU;
+	  if (comparison == LE)
+	    msw_taken = LT;
+	  else if (op2h != CONST0_RTX (SImode))
+	    msw_taken = LTU;
+	  else
+	    break;
+	  msw_skip = swap_condition (msw_taken);
+	}
+      break;
+    default: return false;
+    }
+  operands[1] = op1h;
+  operands[2] = op2h;
+  operands[4] = NULL_RTX;
+  if (msw_taken != CODE_FOR_nothing)
+    expand_cbranchsi4 (operands, msw_taken);
+  if (msw_skip != CODE_FOR_nothing)
+    {
+      rtx taken_label = operands[3];
+
+      operands[3] = skip_label = gen_label_rtx ();
+      expand_cbranchsi4 (operands, msw_skip);
+      operands[3] = taken_label;
+    }
+  operands[1] = op1l;
+  operands[2] = op2l;
+  if (lsw_taken != CODE_FOR_nothing)
+    expand_cbranchsi4 (operands, lsw_taken);
+  if (msw_skip != CODE_FOR_nothing)
+    emit_label (skip_label);
+  return true;
+}
+
 /* Prepare the operands for an scc instruction; make sure that the
    compare has been done.  */
 rtx
@@ -1687,6 +1932,12 @@       gcc_unreachable ();
     }
 }
 
+/* Output a code sequence for INSN using TEMPLATE with OPERANDS; but before,
+   fill in operands 9 as a label to the successor insn.
+   We try to use jump threading where possible.
+   IF CODE matches the comparison in the IF_THEN_ELSE of a following jump,
+   we assume the jump is taken.  I.e. EQ means follow jmp and bf, NE means
+   follow jmp and bt, if the address is in range.  */
 const char *
 output_branchy_insn (enum rtx_code code, const char *template,
 		     rtx insn, rtx *operands)
@@ -2081,6 +2332,15 @@       if (CONST_OK_FOR_I08 (INTVAL (x)))
       else if ((outer_code == AND || outer_code == IOR || outer_code == XOR)
 	       && CONST_OK_FOR_K08 (INTVAL (x)))
         *total = 1;
+      /* prepare_cmp_insn will force costly constants int registers before
+	 the cbrach[sd]i4 pattterns can see them, so preserve potentially
+	 interesting ones not covered by I08 above.  */
+      else if (outer_code == COMPARE
+	       && ((unsigned HOST_WIDE_INT) INTVAL (x)
+		    == (unsigned HOST_WIDE_INT) 0x7fffffff + 1
+		    || INTVAL (x) == 0x7fffffff
+		   || INTVAL (x) == 0x80 || INTVAL (x) == -0x81))
+        *total = 1;
       else
         *total = 8;
       return true;
@@ -2099,6 +2359,11 @@         *total = COSTS_N_INSNS (2);
     case CONST_DOUBLE:
       if (TARGET_SHMEDIA)
         *total = COSTS_N_INSNS (4);
+      /* prepare_cmp_insn will force costly constants int registers before
+	 the cbrachdi4 patttern can see them, so preserve potentially
+	 interesting ones.  */
+      else if (outer_code == COMPARE && GET_MODE (x) == DImode)
+        *total = 1;
       else
         *total = 10;
       return true;
@@ -3033,6 +3298,8 @@ static int pool_size;
 static rtx pool_window_label;
 static int pool_window_last;
 
+static int max_labelno_before_reorg;
+
 /* ??? If we need a constant in HImode which is the truncated value of a
    constant we need in SImode, we could combine the two entries thus saving
    two bytes.  Is this common enough to be worth the effort of implementing
@@ -3313,6 +3580,8 @@ 	  && INTVAL (src) >= -32768
 	  && INTVAL (src) <= 32767);
 }
 
+#define MOVA_LABELREF(mova) XVECEXP (SET_SRC (PATTERN (mova)), 0, 0)
+
 /* Nonzero if the insn is a move instruction which needs to be fixed.  */
 
 /* ??? For a DImode/DFmode moves, we don't need to fix it if each half of the
@@ -3372,16 +3641,17 @@ 	  && GET_CODE (PATTERN (insn)) == SET
 	  && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC
 	  && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPEC_MOVA
 	  /* Don't match mova_const.  */
-	  && GET_CODE (XVECEXP (SET_SRC (PATTERN (insn)), 0, 0)) == LABEL_REF);
+	  && GET_CODE (MOVA_LABELREF (insn)) == LABEL_REF);
 }
 
 /* Fix up a mova from a switch that went out of range.  */
 static void
 fixup_mova (rtx mova)
 {
+  PUT_MODE (XEXP (MOVA_LABELREF (mova), 0), QImode);
   if (! flag_pic)
     {
-      SET_SRC (PATTERN (mova)) = XVECEXP (SET_SRC (PATTERN (mova)), 0, 0);
+      SET_SRC (PATTERN (mova)) = MOVA_LABELREF (mova);
       INSN_CODE (mova) = -1;
     }
   else
@@ -3415,6 +3685,53 @@       INSN_CODE (mova) = -1;
     }
 }
 
+/* NEW_MOVA is a mova we've just encountered while scanning forward.  Update
+   *num_mova, and check if the new mova is not nested within the first one.
+   return 0 if *first_mova was replaced, 1 if new_mova was replaced,
+   2 if new_mova has been assigned to *first_mova, -1 otherwise..  */
+static int
+untangle_mova (int *num_mova, rtx *first_mova, rtx new_mova)
+{
+  int n_addr;
+  int f_target, n_target;
+
+  if (optimize)
+    {
+      n_addr = INSN_ADDRESSES (INSN_UID (new_mova));
+      n_target = INSN_ADDRESSES (INSN_UID (XEXP (MOVA_LABELREF (new_mova), 0)));
+      if (n_addr > n_target || n_addr + 1022 < n_target)
+	{
+	  /* Change the mova into a load.
+	     broken_move will then return true for it.  */
+	  fixup_mova (new_mova);
+	  return 1;
+	}
+    }
+  if (!(*num_mova)++)
+    {
+      *first_mova = new_mova;
+      return 2;
+    }
+  if (!optimize
+      || ((f_target
+	   = INSN_ADDRESSES (INSN_UID (XEXP (MOVA_LABELREF (*first_mova), 0))))
+	  >= n_target))
+    return -1;
+
+  (*num_mova)--;
+  if (f_target - INSN_ADDRESSES (INSN_UID (*first_mova))
+      > n_target - n_addr)
+    {
+      fixup_mova (*first_mova);
+      return 0;
+    }
+  else
+    {
+      fixup_mova (new_mova);
+      return 1;
+    }
+}
+
 /* Find the last barrier from insn FROM which is close enough to hold the
    constant pool.  If we can't find one, then create one near the end of
    the range.  */
@@ -3458,7 +3775,12 @@   while (from && count_si < si_limit && 
       int inc = get_attr_length (from);
       int new_align = 1;
 
-      if (GET_CODE (from) == CODE_LABEL)
+      /* If this is a label that existed at the time of the compute_alignments
+	 call, determine the alignment.  N.B.  When find_barrier recurses for
+	 an out-of-reach mova, we might see labels at the start of previously
+	 inserted constant tables.  */
+      if (GET_CODE (from) == CODE_LABEL
+	  && CODE_LABEL_NUMBER (from) <= max_labelno_before_reorg)
 	{
 	  if (optimize)
 	    new_align = 1 << label_to_alignment (from);
@@ -3468,6 +3790,22 @@ 	    new_align = 1 << barrier_align (fro
 	    new_align = 1;
 	  inc = 0;
 	}
+      /* In case we are scanning a constant table because of recursion, check
+	 for explicit alignments.  If the table is long, we might be forced
+	 to emit the new table in front of it; the length of the alignment
+	 might be the last straw.  */
+      else if (GET_CODE (from) == INSN
+	       && GET_CODE (PATTERN (from)) == UNSPEC_VOLATILE
+	       && XINT (PATTERN (from), 1) == UNSPECV_ALIGN)
+	new_align = INTVAL (XVECEXP (PATTERN (from), 0, 0));
+      /* When we find the end of a constant table, paste the new constant
+	 at the end.  That is better than putting it in front because
+	 this way, we don't need extra alignment for adding a 4-byte-aligned
+	 mov(a) label to a 2/4 or 8/4 byte aligned table.  */
+      else if (GET_CODE (from) == INSN
+	       && GET_CODE (PATTERN (from)) == UNSPEC_VOLATILE
+	       && XINT (PATTERN (from), 1) == UNSPECV_CONST_END)
+	return from;
 
       if (GET_CODE (from) == BARRIER)
 	{
@@ -3532,11 +3870,16 @@ 		si_limit -= GET_MODE_SIZE (mode);
 
       if (mova_p (from))
 	{
-	  if (! num_mova++)
+	  switch (untangle_mova (&num_mova, &mova, from))
 	    {
-	      leading_mova = 0;
-	      mova = from;
-	      barrier_before_mova = good_barrier ? good_barrier : found_barrier;
+	      case 0:	return find_barrier (0, 0, mova);
+	      case 2:
+		{
+		  leading_mova = 0;
+		  barrier_before_mova
+		    = good_barrier ? good_barrier : found_barrier;
+		}
+	      default:	break;
 	    }
 	  if (found_si > count_si)
 	    count_si = found_si;
@@ -3545,7 +3888,10 @@       else if (GET_CODE (from) == JUMP_I
 	       && (GET_CODE (PATTERN (from)) == ADDR_VEC
 		   || GET_CODE (PATTERN (from)) == ADDR_DIFF_VEC))
 	{
-	  if (num_mova)
+	  if ((num_mova > 1 && GET_MODE (prev_nonnote_insn (from)) == VOIDmode)
+	      || (num_mova
+		  && (prev_nonnote_insn (from)
+		      == XEXP (MOVA_LABELREF (mova), 0))))
 	    num_mova--;
 	  if (barrier_align (next_real_insn (from)) == align_jumps_log)
 	    {
@@ -4265,6 +4611,7 @@   rtx r0_rtx = gen_rtx_REG (Pmode, 0);
   rtx r0_inc_rtx = gen_rtx_POST_INC (Pmode, r0_rtx);
 
   first = get_insns ();
+  max_labelno_before_reorg = max_label_num ();
 
   /* We must split call insns before introducing `mova's.  If we're
      optimizing, they'll have already been split.  Otherwise, make
@@ -4523,21 +4870,23 @@       if (mova_p (insn))
 	     below the switch table.  Check if that has happened.
 	     We only have the addresses available when optimizing; but then,
 	     this check shouldn't be needed when not optimizing.  */
-	  rtx label_ref = XVECEXP (SET_SRC (PATTERN (insn)), 0, 0);
-	  if (optimize
-	      && (INSN_ADDRESSES (INSN_UID (insn))
-		  > INSN_ADDRESSES (INSN_UID (XEXP (label_ref, 0)))))
+	  if (!untangle_mova (&num_mova, &mova, insn))
 	    {
-	      /* Change the mova into a load.
-		 broken_move will then return true for it.  */
-	      fixup_mova (insn);
+	      insn = mova;
+	      num_mova = 0;
 	    }
-	  else if (! num_mova++)
-	    mova = insn;
 	}
       else if (GET_CODE (insn) == JUMP_INSN
 	       && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
-	       && num_mova)
+	       && num_mova
+	       /* ??? loop invariant motion can also move a mova out of a
+		  loop.  Since loop does this code motion anyway, maybe we
+		  should wrap UNSPEC_MOVA into a CONST, so that reload can
+		  move it back.  */
+	       && ((num_mova > 1
+		    && GET_MODE (prev_nonnote_insn (insn)) == VOIDmode)
+		   || (prev_nonnote_insn (insn)
+		       == XEXP (MOVA_LABELREF (mova), 0))))
 	{
 	  rtx scan;
 	  int total;
@@ -4694,6 +5043,8 @@ 	  dump_table (need_aligned_label ? insn
 	  insn = barrier;
 	}
     }
+  for (insn = first; insn; insn = NEXT_INSN (insn))
+    PUT_MODE (insn, VOIDmode);
 
   mdep_reorg_phase = SH_SHORTEN_BRANCHES1;
   INSN_ADDRESSES_FREE ();
@@ -8428,23 +8779,32 @@ 	       && ! flow_dependent_p (insn, dep
     }
   else if (REG_NOTE_KIND (link) == 0)
     {
-      enum attr_type dep_type, type;
+      enum attr_type type;
+      rtx dep_set;
 
       if (recog_memoized (insn) < 0
 	  || recog_memoized (dep_insn) < 0)
 	return cost;
 
-      dep_type = get_attr_type (dep_insn);
-      if (dep_type == TYPE_FLOAD || dep_type == TYPE_PCFLOAD)
-	cost--;
-      if ((dep_type == TYPE_LOAD_SI || dep_type == TYPE_PCLOAD_SI)
-	  && (type = get_attr_type (insn)) != TYPE_CALL
-	  && type != TYPE_SFUNC)
-	cost--;
+      dep_set = single_set (dep_insn);
 
+      /* The latency that we specify in the scheduling description refers
+	 to the actual output, not to an auto-increment register; for that,
+	 the latency is one.  */
+      if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1)
+	{
+	  rtx set = single_set (insn);
+
+	  if (set
+	      && !reg_mentioned_p (SET_DEST (dep_set), SET_SRC (set))
+	      && (!MEM_P (SET_DEST (set))
+		  || !reg_mentioned_p (SET_DEST (dep_set),
+				       XEXP (SET_DEST (set), 0))))
+	    cost = 1;
+	}
       /* The only input for a call that is timing-critical is the
 	 function's address.  */
-      if (GET_CODE(insn) == CALL_INSN)
+      if (GET_CODE (insn) == CALL_INSN)
 	{
 	  rtx call = PATTERN (insn);
 
@@ -8456,12 +8816,16 @@ 	  if (GET_CODE (call) == CALL && GET_CO
 		  /* sibcalli_thunk uses a symbol_ref in an unspec.  */
 	      && (GET_CODE (XEXP (XEXP (call, 0), 0)) == UNSPEC
 		  || ! reg_set_p (XEXP (XEXP (call, 0), 0), dep_insn)))
-	    cost = 0;
+	    cost -= TARGET_SH4_300 ? 3 : 6;
 	}
       /* Likewise, the most timing critical input for an sfuncs call
 	 is the function address.  However, sfuncs typically start
 	 using their arguments pretty quickly.
-	 Assume a four cycle delay before they are needed.  */
+	 Assume a four cycle delay for SH4 before they are needed.
+	 Cached ST40-300 calls are quicker, so assume only a one
+	 cycle delay there.
+	 ??? Maybe we should encode the delays till input registers
+	 are needed by sfuncs into the sfunc call insn.  */
       /* All sfunc calls are parallels with at least four components.
 	 Exploit this to avoid unnecessary calls to sfunc_uses_reg.  */
       else if (GET_CODE (PATTERN (insn)) == PARALLEL
@@ -8469,50 +8833,83 @@ 	       && XVECLEN (PATTERN (insn), 0) >
 	       && (reg = sfunc_uses_reg (insn)))
 	{
 	  if (! reg_set_p (reg, dep_insn))
-	    cost -= 4;
+	    cost -= TARGET_SH4_300 ? 1 : 4;
 	}
-      /* When the preceding instruction loads the shift amount of
-	 the following SHAD/SHLD, the latency of the load is increased
-	 by 1 cycle.  */
-      else if (TARGET_SH4
-	       && get_attr_type (insn) == TYPE_DYN_SHIFT
-	       && get_attr_any_int_load (dep_insn) == ANY_INT_LOAD_YES
-	       && reg_overlap_mentioned_p (SET_DEST (PATTERN (dep_insn)),
-					   XEXP (SET_SRC (single_set (insn)),
-						 1)))
-	cost++;
-      /* When an LS group instruction with a latency of less than
-	 3 cycles is followed by a double-precision floating-point
-	 instruction, FIPR, or FTRV, the latency of the first
-	 instruction is increased to 3 cycles.  */
-      else if (cost < 3
-	       && get_attr_insn_class (dep_insn) == INSN_CLASS_LS_GROUP
-	       && get_attr_dfp_comp (insn) == DFP_COMP_YES)
-	cost = 3;
-      /* The lsw register of a double-precision computation is ready one
-	 cycle earlier.  */
-      else if (reload_completed
-	       && get_attr_dfp_comp (dep_insn) == DFP_COMP_YES
-	       && (use_pat = single_set (insn))
-	       && ! regno_use_in (REGNO (SET_DEST (single_set (dep_insn))),
-				  SET_SRC (use_pat)))
-	cost -= 1;
+      if (TARGET_HARD_SH4 && !TARGET_SH4_300)
+	{
+	  enum attr_type dep_type = get_attr_type (dep_insn);
 
-      if (get_attr_any_fp_comp (dep_insn) == ANY_FP_COMP_YES
-	  && get_attr_late_fp_use (insn) == LATE_FP_USE_YES)
-	cost -= 1;
+	  if (dep_type == TYPE_FLOAD || dep_type == TYPE_PCFLOAD)
+	    cost--;
+	  else if ((dep_type == TYPE_LOAD_SI || dep_type == TYPE_PCLOAD_SI)
+		   && (type = get_attr_type (insn)) != TYPE_CALL
+		   && type != TYPE_SFUNC)
+	    cost--;
+	  /* When the preceding instruction loads the shift amount of
+	     the following SHAD/SHLD, the latency of the load is increased
+	     by 1 cycle.  */
+	  if (get_attr_type (insn) == TYPE_DYN_SHIFT
+	      && get_attr_any_int_load (dep_insn) == ANY_INT_LOAD_YES
+	      && reg_overlap_mentioned_p (SET_DEST (PATTERN (dep_insn)),
+					  XEXP (SET_SRC (single_set (insn)),
+						1)))
+	    cost++;
+	  /* When an LS group instruction with a latency of less than
+	     3 cycles is followed by a double-precision floating-point
+	     instruction, FIPR, or FTRV, the latency of the first
+	     instruction is increased to 3 cycles.  */
+	  else if (cost < 3
+		   && get_attr_insn_class (dep_insn) == INSN_CLASS_LS_GROUP
+		   && get_attr_dfp_comp (insn) == DFP_COMP_YES)
+	    cost = 3;
+	  /* The lsw register of a double-precision computation is ready one
+	     cycle earlier.  */
+	  else if (reload_completed
+		   && get_attr_dfp_comp (dep_insn) == DFP_COMP_YES
+		   && (use_pat = single_set (insn))
+		   && ! regno_use_in (REGNO (SET_DEST (single_set (dep_insn))),
+				      SET_SRC (use_pat)))
+	    cost -= 1;
+
+	  if (get_attr_any_fp_comp (dep_insn) == ANY_FP_COMP_YES
+	      && get_attr_late_fp_use (insn) == LATE_FP_USE_YES)
+	    cost -= 1;
+	}
+      else if (TARGET_SH4_300)
+	{
+	  /* Stores need their input register two cycles later.  */
+	  if (dep_set && cost >= 1
+	      && ((type = get_attr_type (insn)) == TYPE_STORE
+		  || type == TYPE_PSTORE
+		  || type == TYPE_FSTORE || type == TYPE_MAC_MEM))
+	    {
+	      rtx set = single_set (insn);
+
+	      if (!reg_mentioned_p (SET_SRC (set), XEXP (SET_DEST (set), 0))
+		  && rtx_equal_p (SET_SRC (set), SET_DEST (dep_set)))
+		{
+		  cost -= 2;
+		  /* But don't reduce the cost below 1 if the address depends
+		     on a side effect of dep_insn.  */
+		  if (cost < 1
+		      && modified_in_p (XEXP (SET_DEST (set), 0), dep_insn))
+		    cost = 1;
+		}
+	    }
+	}
     }
   /* An anti-dependence penalty of two applies if the first insn is a double
      precision fadd / fsub / fmul.  */
-  else if (REG_NOTE_KIND (link) == REG_DEP_ANTI
+  else if (!TARGET_SH4_300
+	   && REG_NOTE_KIND (link) == REG_DEP_ANTI
 	   && recog_memoized (dep_insn) >= 0
-	   && get_attr_type (dep_insn) == TYPE_DFP_ARITH
+	   && (get_attr_type (dep_insn) == TYPE_DFP_ARITH
+	       || get_attr_type (dep_insn) == TYPE_DFP_MUL)
 	   /* A lot of alleged anti-flow dependences are fake,
 	      so check this one is real.  */
 	   && flow_dependent_p (dep_insn, insn))
     cost = 2;
 
-
   return cost;
 }
 
@@ -10702,11 +11099,4 @@ 			    DECL_ATTRIBUTES (current_function
 
 enum sh_divide_strategy_e sh_div_strategy = SH_DIV_STRATEGY_DEFAULT;
 
-/* This defines the storage for the variable part of a -mboard= option.
-   It is only required when using the sh-superh-elf target */
-#ifdef _SUPERH_H
-const char * boardtype = "7750p2";
-const char * osruntime = "bare";
-#endif
-
 #include "gt-sh.h"
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/sh.h gcc-4.1.1/gcc/config/sh/sh.h
--- gcc-4.1.1.orig/gcc/config/sh/sh.h	2006-01-30 19:02:39.000000000 +0000
+++ gcc-4.1.1/gcc/config/sh/sh.h	2006-08-10 09:56:05.000000000 +0100
@@ -3,6 +3,7 @@    Copyright (C) 1993, 1994, 1995, 1996,
    2003, 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Steve Chamberlain (sac@cygnus.com).
    Improved by Jim Wilson (wilson@cygnus.com).
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -122,6 +123,10 @@   if (TARGET_SHMEDIA)							\
       CLEAR_HARD_REG_SET (reg_class_contents[FP0_REGS]);		\
       regno_reg_class[FIRST_FP_REG] = FP_REGS;				\
     }									\
+  if (TARGET_R0R3_TO_REG_MUL < 2)					\
+    regno_reg_class[R1_REG] = regno_reg_class[R2_REG]			\
+      = regno_reg_class[R3_REG] = GENERAL_REGS;				\
+    /* The peephole2s needs reg_class_contents[R0R3_REGS].  */		\
   if (flag_pic)								\
     {									\
       fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;				\
@@ -239,6 +244,9 @@ #define TARGET_DIVIDE_INV20U (sh_div_str
 #define TARGET_DIVIDE_INV20L (sh_div_strategy == SH_DIV_INV20L)
 #define TARGET_DIVIDE_INV_CALL (sh_div_strategy == SH_DIV_INV_CALL)
 #define TARGET_DIVIDE_INV_CALL2 (sh_div_strategy == SH_DIV_INV_CALL2)
+#define TARGET_DIVIDE_CALL_DIV1 (sh_div_strategy == SH_DIV_CALL_DIV1)
+#define TARGET_DIVIDE_CALL_FP (sh_div_strategy == SH_DIV_CALL_FP)
+#define TARGET_DIVIDE_CALL_TABLE (sh_div_strategy == SH_DIV_CALL_TABLE)
 
 #define SELECT_SH1               (MASK_SH1)
 #define SELECT_SH2               (MASK_SH2 | SELECT_SH1)
@@ -276,6 +284,7 @@ #define SELECT_SH5_COMPACT_NOFPU (MASK_S
 #endif
 #if SUPPORT_SH2
 #define SUPPORT_SH3 1
+#define SUPPORT_SH2A_NOFPU 1
 #endif
 #if SUPPORT_SH3
 #define SUPPORT_SH4_NOFPU 1
@@ -283,16 +292,17 @@ #define SELECT_SH5_COMPACT_NOFPU (MASK_S
 #if SUPPORT_SH4_NOFPU
 #define SUPPORT_SH4A_NOFPU 1
 #define SUPPORT_SH4AL 1
-#define SUPPORT_SH2A_NOFPU 1
 #endif
 
 #if SUPPORT_SH2E
 #define SUPPORT_SH3E 1
+#define SUPPORT_SH2A_SINGLE_ONLY 1
 #endif
 #if SUPPORT_SH3E
 #define SUPPORT_SH4_SINGLE_ONLY 1
+#endif
+#if SUPPORT_SH4_SINGLE_ONLY
 #define SUPPORT_SH4A_SINGLE_ONLY 1
-#define SUPPORT_SH2A_SINGLE_ONLY 1
 #endif
 
 #if SUPPORT_SH4
@@ -471,8 +481,13 @@   if (SIZE)								\
       target_flags |= MASK_SMALLCODE;					\
       sh_div_str = SH_DIV_STR_FOR_SIZE ;				\
     }									\
+  else									\
+    {									\
+      TARGET_CBRANCHDI4 = 1;						\
+      TARGET_EXPAND_CBRANCHDI4 = 1;					\
+    }									\
   /* We can't meaningfully test TARGET_SHMEDIA here, because -m options	\
-     haven't been parsed yet, hence we';d read only the default.	\
+     haven't been parsed yet, hence we'd read only the default.		\
      sh_target_reg_class will return NO_REGS if this is not SHMEDIA, so	\
      it's OK to always set flag_branch_target_load_optimize.  */	\
   if (LEVEL > 1)							\
@@ -497,16 +512,24 @@ } while (0)
 extern int assembler_dialect;
 
 enum sh_divide_strategy_e {
+  /* SH5 strategies.  */
   SH_DIV_CALL,
   SH_DIV_CALL2,
-  SH_DIV_FP,
+  SH_DIV_FP, /* We could do this also for SH4.  */
   SH_DIV_INV,
   SH_DIV_INV_MINLAT,
   SH_DIV_INV20U,
   SH_DIV_INV20L,
   SH_DIV_INV_CALL,
   SH_DIV_INV_CALL2,
-  SH_DIV_INV_FP
+  SH_DIV_INV_FP,
+  /* SH1 .. SH4 strategies.  Because of the small number of registers
+     available, the compiler uses knowledge of the actual et of registers
+     being clobbed by the different functions called.  */
+  SH_DIV_CALL_DIV1, /* No FPU, medium size, highest latency.  */
+  SH_DIV_CALL_FP,     /* FPU needed, small size, high latency.  */
+  SH_DIV_CALL_TABLE,  /* No FPU, large size, medium latency. */
+  SH_DIV_INTRINSIC
 };
 
 extern enum sh_divide_strategy_e sh_div_strategy;
@@ -602,6 +625,7 @@ 	      if (TARGET_FPU_ANY)					\
 	      else							\
 		sh_div_strategy = SH_DIV_INV;				\
 	    }								\
+	  TARGET_CBRANCHDI4 = 0;					\
 	}								\
       /* -fprofile-arcs needs a working libgcov .  In unified tree	\
 	 configurations with newlib, this requires to configure with	\
@@ -616,19 +640,55 @@ 	warning (0, "profiling is still experim
        targetm.asm_out.aligned_op.di = NULL;				\
        targetm.asm_out.unaligned_op.di = NULL;				\
     }									\
+  if (!TARGET_SH1)							\
+    TARGET_PRETEND_CMOVE = 0;						\
+  if (TARGET_SH1)							\
+    {									\
+      if (! strcmp (sh_div_str, "call-div1"))				\
+	sh_div_strategy = SH_DIV_CALL_DIV1;				\
+      else if (! strcmp (sh_div_str, "call-fp")				\
+	       && (TARGET_FPU_DOUBLE					\
+		   || (TARGET_HARD_SH4 && TARGET_SH2E)			\
+		   || (TARGET_SHCOMPACT && TARGET_FPU_ANY)))		\
+	sh_div_strategy = SH_DIV_CALL_FP;				\
+      else if (! strcmp (sh_div_str, "call-table") && TARGET_SH2)	\
+	sh_div_strategy = SH_DIV_CALL_TABLE;				\
+      else								\
+	/* Pick one that makes most sense for the target in general.	\
+	   It is not much good to use different functions depending	\
+	   on -Os, since then we'll end up with two different functions	\
+	   when some of the code is compiled for size, and some for	\
+	   speed.  */							\
+									\
+	/* SH4 tends to emphasize speed.  */				\
+	if (TARGET_HARD_SH4)						\
+	  sh_div_strategy = SH_DIV_CALL_TABLE;				\
+	/* These have their own way of doing things.  */		\
+	else if (TARGET_SH2A)						\
+	  sh_div_strategy = SH_DIV_INTRINSIC;				\
+	/* ??? Should we use the integer SHmedia function instead?  */	\
+	else if (TARGET_SHCOMPACT && TARGET_FPU_ANY)			\
+	  sh_div_strategy = SH_DIV_CALL_FP;				\
+        /* SH1 .. SH3 cores often go into small-footprint systems, so	\
+	   default to the smallest implementation available.  */	\
+	else								\
+	  sh_div_strategy = SH_DIV_CALL_DIV1;				\
+    }									\
   if (sh_divsi3_libfunc[0])						\
     ; /* User supplied - leave it alone.  */				\
-  else if (TARGET_HARD_SH4 && TARGET_SH2E)				\
+  else if (TARGET_DIVIDE_CALL_FP)					\
     sh_divsi3_libfunc = "__sdivsi3_i4";					\
+  else if (TARGET_DIVIDE_CALL_TABLE)					\
+    sh_divsi3_libfunc = "__sdivsi3_i4i";				\
   else if (TARGET_SH5)							\
-    {									\
-      if (TARGET_FPU_ANY && TARGET_SH1)					\
-	sh_divsi3_libfunc = "__sdivsi3_i4";				\
-      else								\
-	sh_divsi3_libfunc = "__sdivsi3_1";				\
-    }									\
+    sh_divsi3_libfunc = "__sdivsi3_1";					\
   else									\
     sh_divsi3_libfunc = "__sdivsi3";					\
+  if (sh_branch_cost == -1)						\
+    sh_branch_cost							\
+      = TARGET_SH5 ? 1 : ! TARGET_SH2 || TARGET_HARD_SH4 ? 2 : 1;	\
+  if (TARGET_R0R3_TO_REG_MUL == -1)					\
+    TARGET_R0R3_TO_REG_MUL = /* TARGET_SH4_300 ? 2 : */ 0;		\
   if (TARGET_FMOVD)							\
     reg_class_from_letter['e' - 'a'] = NO_REGS;				\
 									\
@@ -805,7 +865,7 @@ #define LOCAL_ALIGNMENT(TYPE, ALIGN) \
   ((GET_MODE_CLASS (TYPE_MODE (TYPE)) == MODE_COMPLEX_INT \
     || GET_MODE_CLASS (TYPE_MODE (TYPE)) == MODE_COMPLEX_FLOAT) \
    ? (unsigned) MIN (BIGGEST_ALIGNMENT, GET_MODE_BITSIZE (TYPE_MODE (TYPE))) \
-   : (unsigned) ALIGN)
+   : (unsigned) DATA_ALIGNMENT(TYPE, ALIGN))
 
 /* Make arrays of chars word-aligned for the same reasons.  */
 #define DATA_ALIGNMENT(TYPE, ALIGN)		\
@@ -1344,6 +1404,7 @@ enum reg_class
 {
   NO_REGS,
   R0_REGS,
+  R0R3_REGS,
   PR_REGS,
   T_REGS,
   MAC_REGS,
@@ -1369,6 +1430,7 @@ #define N_REG_CLASSES  (int) LIM_REG_CLA
 {			\
   "NO_REGS",		\
   "R0_REGS",		\
+  "R0R3_REGS",		\
   "PR_REGS",		\
   "T_REGS",		\
   "MAC_REGS",		\
@@ -1396,6 +1458,8 @@ #define N_REG_CLASSES  (int) LIM_REG_CLA
   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	\
 /* R0_REGS:  */								\
   { 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	\
+/* R0R3_REGS:  */							\
+  { 0x0000000f, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	\
 /* PR_REGS:  */								\
   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00040000 },	\
 /* T_REGS:  */								\
@@ -1486,9 +1550,11 @@   (!ALLOW_INDEXED_ADDRESS ? NO_REGS : TA
    description.  */
 extern enum reg_class reg_class_from_letter[];
 
-/* We might use 'Rxx' constraints in the future for exotic reg classes.*/
+/* Use 'Rxx' constraints for exotic reg classes.  */
 #define REG_CLASS_FROM_CONSTRAINT(C, STR) \
-  (ISLOWER (C) ? reg_class_from_letter[(C)-'a'] : NO_REGS )
+  (ISLOWER (C) ? reg_class_from_letter[(C)-'a'] \
+   : (C) == 'R' && (STR)[1] == '0' && (STR)[2] == '3' ? R0R3_REGS \
+   : NO_REGS )
 
 /* Overview of uppercase letter constraints:
    A: Addresses (constraint len == 3)
@@ -2239,6 +2305,7 @@    : (REGNO) == R0_REG || (unsigned) reg
 #define CONSTANT_ADDRESS_P(X)	(GET_CODE (X) == LABEL_REF)
 
 /* Nonzero if the constant value X is a legitimate general operand.  */
+/* can_store_by_pieces constructs VOIDmode CONST_DOUBLEs.  */
 
 #define LEGITIMATE_CONSTANT_P(X) \
   (TARGET_SHMEDIA							\
@@ -2249,7 +2316,7 @@       || (X) == CONST0_RTX (GET_MODE (X)
       || TARGET_SHMEDIA64)						\
    : (GET_CODE (X) != CONST_DOUBLE					\
       || GET_MODE (X) == DFmode || GET_MODE (X) == SFmode		\
-      || (TARGET_SH2E && (fp_zero_operand (X) || fp_one_operand (X)))))
+      || GET_MODE (X) == DImode || GET_MODE (X) == VOIDmode))
 
 /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
    and check its validity for a certain class.
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/sh.md gcc-4.1.1/gcc/config/sh/sh.md
--- gcc-4.1.1.orig/gcc/config/sh/sh.md	2006-04-20 03:03:47.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/sh.md	2006-08-10 09:56:05.000000000 +0100
@@ -3,6 +3,7 @@ ;;  Copyright (C) 1993, 1994, 1995, 1996
 ;;  2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 ;;  Contributed by Steve Chamberlain (sac@cygnus.com).
 ;;  Improved by Jim Wilson (wilson@cygnus.com).
+;;  Copyright (c) 2006  STMicroelectronics.
 
 ;; This file is part of GCC.
 
@@ -47,6 +48,8 @@ ;; the Free Software Foundation; either 
 ;;    l -- pr
 ;;    z -- r0
 ;;
+;;    R03 -- r0, r1, r2 or r3  - experimental constraint for SH4-300
+;;
 ;; Special formats used for outputting SH instructions:
 ;;
 ;;   %.  --  print a .s if insn needs delay slot
@@ -202,7 +205,9 @@          (const_string "sh1"))))
 ;; load_si	Likewise, SImode variant for general register.
 ;; fload	Likewise, but load to fp register.
 ;; store	to memory
+;; fstore	floating point register to memory
 ;; move		general purpose register to register
+;; movi8	8 bit immediate to general purpose register
 ;; mt_group	other sh4 mt instructions
 ;; fmove	register to register, floating point
 ;; smpy		word precision integer multiply
@@ -219,11 +224,15 @@          (const_string "sh1"))))
 ;; sfunc	special function call with known used registers
 ;; call		function call
 ;; fp		floating point
+;; fpscr_toggle	toggle a bit in the fpscr
 ;; fdiv		floating point divide (or square root)
 ;; gp_fpul	move from general purpose register to fpul
 ;; fpul_gp	move from fpul to general purpose register
 ;; mac_gp	move from mac[lh] to general purpose register
-;; dfp_arith, dfp_cmp,dfp_conv
+;; gp_mac	move from general purpose register to mac[lh]
+;; mac_mem	move from mac[lh] to memory
+;; mem_mac	move from memory to mac[lh]
+;; dfp_arith,dfp_mul, fp_cmp,dfp_cmp,dfp_conv
 ;; ftrc_s	fix_truncsfsi2_i4
 ;; dfdiv	double precision floating point divide (or square root)
 ;; cwb		ic_invalidate_line_i
@@ -261,7 +270,7 @@ ;; pt_media	SHmedia pt instruction (expa
 ;; nil		no-op move, will be deleted.
 
 (define_attr "type"
- "mt_group,cbranch,jump,jump_ind,arith,arith3,arith3b,dyn_shift,load,load_si,fload,store,move,fmove,smpy,dmpy,return,pload,prset,pstore,prget,pcload,pcload_si,pcfload,rte,sfunc,call,fp,fdiv,ftrc_s,dfp_arith,dfp_cmp,dfp_conv,dfdiv,gp_fpul,fpul_gp,mac_gp,mem_fpscr,gp_fpscr,cwb,movua,fsrra,fsca,tls_load,arith_media,cbranch_media,cmp_media,dfdiv_media,dfmul_media,dfparith_media,dfpconv_media,dmpy_media,fcmp_media,fdiv_media,fload_media,fmove_media,fparith_media,fpconv_media,fstore_media,gettr_media,invalidate_line_media,jump_media,load_media,pt_media,ptabs_media,store_media,mcmp_media,mac_media,d2mpy_media,atrans_media,ustore_media,nil,other"
+ "mt_group,cbranch,jump,jump_ind,arith,arith3,arith3b,dyn_shift,load,load_si,fload,store,fstore,move,movi8,fmove,smpy,dmpy,return,pload,prset,pstore,prget,pcload,pcload_si,pcfload,rte,sfunc,call,fp,fpscr_toggle,fdiv,ftrc_s,dfp_arith,dfp_mul,fp_cmp,dfp_cmp,dfp_conv,dfdiv,gp_fpul,fpul_gp,mac_gp,gp_mac,mac_mem,mem_mac,mem_fpscr,gp_fpscr,cwb,movua,fsrra,fsca,tls_load,arith_media,cbranch_media,cmp_media,dfdiv_media,dfmul_media,dfparith_media,dfpconv_media,dmpy_media,fcmp_media,fdiv_media,fload_media,fmove_media,fparith_media,fpconv_media,fstore_media,gettr_media,invalidate_line_media,jump_media,load_media,pt_media,ptabs_media,store_media,mcmp_media,mac_media,d2mpy_media,atrans_media,ustore_media,nil,other"
   (const_string "other"))
 
 ;; We define a new attribute namely "insn_class".We use
@@ -277,12 +286,12 @@   (const_string "other"))
 (define_attr "insn_class"
   "mt_group,ex_group,ls_group,br_group,fe_group,co_group,none"
   (cond [(eq_attr "type" "move,mt_group") (const_string "mt_group")
-         (eq_attr "type" "arith,dyn_shift") (const_string "ex_group")
-	 (eq_attr "type" "fmove,load,pcload,load_si,pcload_si,fload,pcfload,store,gp_fpul,fpul_gp") (const_string "ls_group")
+         (eq_attr "type" "movi8,arith,dyn_shift") (const_string "ex_group")
+	 (eq_attr "type" "fmove,load,pcload,load_si,pcload_si,fload,pcfload,store,fstore,gp_fpul,fpul_gp") (const_string "ls_group")
 	 (eq_attr "type" "cbranch,jump") (const_string "br_group")
-	 (eq_attr "type" "fp,fdiv,ftrc_s,dfp_arith,dfp_conv,dfdiv")
+	 (eq_attr "type" "fp,fp_cmp,fdiv,ftrc_s,dfp_arith,dfp_mul,dfp_conv,dfdiv")
 	   (const_string "fe_group")
-	 (eq_attr "type" "jump_ind,smpy,dmpy,mac_gp,return,pload,prset,pstore,prget,rte,sfunc,call,dfp_cmp,mem_fpscr,gp_fpscr,cwb") (const_string "co_group")]
+	 (eq_attr "type" "jump_ind,smpy,dmpy,mac_gp,return,pload,prset,pstore,prget,rte,sfunc,call,dfp_cmp,mem_fpscr,gp_fpscr,cwb,gp_mac,mac_mem,mem_mac") (const_string "co_group")]
 	(const_string "none")))
 ;; nil are zero instructions, and arith3 / arith3b are multiple instructions,
 ;; so these do not belong in an insn group, although they are modeled
@@ -492,14 +501,14 @@ 	(const_string "no")))
 ;; SH4 Double-precision computation with double-precision result -
 ;; the two halves are ready at different times.
 (define_attr "dfp_comp" "yes,no"
-  (cond [(eq_attr "type" "dfp_arith,dfp_conv,dfdiv") (const_string "yes")]
+  (cond [(eq_attr "type" "dfp_arith,dfp_mul,dfp_conv,dfdiv") (const_string "yes")]
 	(const_string "no")))
 
 ;; Insns for which the latency of a preceding fp insn is decreased by one.
 (define_attr "late_fp_use" "yes,no" (const_string "no"))
 ;; And feeding insns for which this relevant.
 (define_attr "any_fp_comp" "yes,no"
-  (cond [(eq_attr "type" "fp,fdiv,ftrc_s,dfp_arith,dfp_conv,dfdiv")
+  (cond [(eq_attr "type" "fp,fdiv,ftrc_s,dfp_arith,dfp_mul,dfp_conv,dfdiv")
 	 (const_string "yes")]
 	(const_string "no")))
 
@@ -607,15 +616,37 @@ 	       (match_operand:SI 1 "arith_reg_o
    [(set_attr "type" "mt_group")])
 
 ;; -------------------------------------------------------------------------
+;; SImode compare and branch
+;; -------------------------------------------------------------------------
+
+(define_expand "cbranchsi4"
+  [(set (pc)
+	(if_then_else (match_operator 0 "comparison_operator"
+			[(match_operand:SI 1 "arith_operand" "")
+			 (match_operand:SI 2 "arith_operand" "")])
+		      (label_ref (match_operand 3 "" ""))
+		      (pc)))
+   (clobber (reg:SI T_REG))]
+  "TARGET_CBRANCHDI4"
+  "expand_cbranchsi4 (operands, CODE_FOR_nothing); DONE;")
+
+;; -------------------------------------------------------------------------
 ;; SImode unsigned integer comparisons
 ;; -------------------------------------------------------------------------
 
-(define_insn "cmpgeusi_t"
+(define_insn_and_split "cmpgeusi_t"
   [(set (reg:SI T_REG)
 	(geu:SI (match_operand:SI 0 "arith_reg_operand" "r")
-		(match_operand:SI 1 "arith_reg_operand" "r")))]
+		(match_operand:SI 1 "arith_reg_or_0_operand" "rN")))]
   "TARGET_SH1"
   "cmp/hs	%1,%0"
+  "&& operands[0] == CONST0_RTX (SImode)"
+  [(pc)]
+  "
+{
+  emit_insn (gen_sett ());
+  DONE;
+}"
    [(set_attr "type" "mt_group")])
 
 (define_insn "cmpgtusi_t"
@@ -645,12 +676,64 @@     operands[0] = copy_to_mode_reg (SImo
 }")
 
 ;; -------------------------------------------------------------------------
-;; DImode signed integer comparisons
+;; DImode compare and branch
 ;; -------------------------------------------------------------------------
 
-;; ??? Could get better scheduling by splitting the initial test from the
-;; rest of the insn after reload.  However, the gain would hardly justify
-;; the sh.md size increase necessary to do that.
+
+;; arith3 patterns don't work well with the sh4-300 branch prediction mechanism.
+;; Therefore, we aim to have a set of three branches that go straight to the
+;; destination, i.e. only one of them is taken at any one time.
+;; This mechanism should also be slightly better for the sh4-200.
+
+(define_expand "cbranchdi4"
+  [(set (pc)
+	(if_then_else (match_operator 0 "comparison_operator"
+			[(match_operand:DI 1 "arith_operand" "")
+			 (match_operand:DI 2 "arith_operand" "")])
+		      (label_ref (match_operand 3 "" ""))
+		      (pc)))
+   (clobber (match_dup 4))
+   (clobber (reg:SI T_REG))]
+  "TARGET_CBRANCHDI4"
+  "
+{
+  enum rtx_code comparison;
+
+  if (TARGET_EXPAND_CBRANCHDI4)
+    {
+      if (expand_cbranchdi4 (operands, CODE_FOR_nothing))
+	DONE;
+    }
+  comparison = prepare_cbranch_operands (operands, DImode, CODE_FOR_nothing);
+  if (comparison != GET_CODE (operands[0]))
+    operands[0]
+      = gen_rtx_fmt_ee (VOIDmode, comparison, operands[1], operands[2]);
+   operands[4] = gen_rtx_SCRATCH (SImode);
+}")
+
+(define_insn_and_split "cbranchdi4_i"
+  [(set (pc)
+	(if_then_else (match_operator 0 "comparison_operator"
+			[(match_operand:DI 1 "arith_operand" "r,r")
+			 (match_operand:DI 2 "arith_operand" "rN,i")])
+		      (label_ref (match_operand 3 "" ""))
+		      (pc)))
+   (clobber (match_scratch:SI 4 "=&X,r"))
+   (clobber (reg:SI T_REG))]
+  "TARGET_CBRANCHDI4"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  if (!expand_cbranchdi4 (operands, GET_CODE (operands[0])))
+    FAIL;
+  DONE;
+}")
+
+;; -------------------------------------------------------------------------
+;; DImode signed integer comparisons
+;; -------------------------------------------------------------------------
 
 (define_insn ""
   [(set (reg:SI T_REG)
@@ -1182,19 +1265,72 @@   emit_insn (gen_movsicc_false (operands
   DONE;
 }")
 
+(define_insn "*movsicc_t_false"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
+	(if_then_else (eq (reg:SI T_REG) (const_int 0))
+		      (match_operand:SI 1 "general_movsrc_operand" "r,I08")
+		      (match_operand:SI 2 "arith_reg_operand" "0,0")))]
+  "TARGET_PRETEND_CMOVE
+   && (arith_reg_operand (operands[1], SImode)
+       || (immediate_operand (operands[1], SImode)
+	   && CONST_OK_FOR_I08 (INTVAL (operands[1]))))"
+  "bt 0f\;mov %1,%0\\n0:"
+  [(set_attr "type" "mt_group,arith") ;; poor approximation
+   (set_attr "length" "4")])
+
+(define_insn "*movsicc_t_true"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
+	(if_then_else (ne (reg:SI T_REG) (const_int 0))
+		      (match_operand:SI 1 "general_movsrc_operand" "r,I08")
+		      (match_operand:SI 2 "arith_reg_operand" "0,0")))]
+  "TARGET_PRETEND_CMOVE
+   && (arith_reg_operand (operands[1], SImode)
+       || (immediate_operand (operands[1], SImode)
+	   && CONST_OK_FOR_I08 (INTVAL (operands[1]))))"
+  "bf 0f\;mov %1,%0\\n0:"
+  [(set_attr "type" "mt_group,arith") ;; poor approximation
+   (set_attr "length" "4")])
+
 (define_expand "movsicc"
-  [(set (match_operand:SI 0 "register_operand" "")
+  [(set (match_operand:SI 0 "arith_reg_dest" "")
 	(if_then_else:SI (match_operand 1 "comparison_operator" "")
-			 (match_operand:SI 2 "register_operand" "")
-			 (match_operand:SI 3 "register_operand" "")))]
-  "TARGET_SHMEDIA"
+			 (match_operand:SI 2 "arith_reg_or_0_operand" "")
+			 (match_operand:SI 3 "arith_reg_operand" "")))]
+  "TARGET_SHMEDIA || TARGET_PRETEND_CMOVE"
   "
 {
   if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE)
       && GET_MODE (sh_compare_op0) == SImode
+      && (TARGET_SHMEDIA
+	  || (REG_P (sh_compare_op0) && REGNO (sh_compare_op0) == T_REG))
       && sh_compare_op1 == const0_rtx)
     operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), VOIDmode,
 				  sh_compare_op0, sh_compare_op1);
+  else if (TARGET_PRETEND_CMOVE)
+    {
+      enum rtx_code code = GET_CODE (operands[1]);
+      enum rtx_code new_code = code;
+      rtx tmp;
+
+      if (! currently_expanding_to_rtl)
+	FAIL;
+      switch (code)
+	{
+	case LT: case LE: case LEU: case LTU:
+	  if (GET_MODE_CLASS (GET_MODE (sh_compare_op0)) != MODE_INT)
+	    break;
+	case NE:
+	  new_code = reverse_condition (code);
+	  break;
+	case EQ: case GT: case GE: case GEU: case GTU:
+	  break;
+	default:
+	  FAIL;
+	}
+      tmp = prepare_scc_operands (new_code);
+      operands[1] = gen_rtx_fmt_ee (new_code == code ? NE : EQ, VOIDmode,
+				    tmp, const0_rtx);
+    }
   else
     {
       rtx tmp;
@@ -1741,6 +1877,21 @@   "(TARGET_HARD_SH4 || TARGET_SHCOMPACT)
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
+(define_insn "udivsi3_i4_int"
+  [(set (match_operand:SI 0 "register_operand" "=z")
+	(udiv:SI (reg:SI R4_REG) (reg:SI R5_REG)))
+   (clobber (reg:SI T_REG))
+   (clobber (reg:SI R1_REG))
+   (clobber (reg:SI PR_REG))
+   (clobber (reg:SI MACH_REG))
+   (clobber (reg:SI MACL_REG))
+   (use (match_operand:SI 1 "arith_reg_operand" "r"))]
+  "TARGET_SH1"
+  "jsr	@%1%#"
+  [(set_attr "type" "sfunc")
+   (set_attr "needs_delay_slot" "yes")])
+
+
 (define_expand "udivsi3"
   [(set (match_dup 3) (symbol_ref:SI "__udivsi3"))
    (set (reg:SI R4_REG) (match_operand:SI 1 "general_operand" ""))
@@ -1759,7 +1910,27 @@ 	      (use (match_dup 3))])]
 
   operands[3] = gen_reg_rtx (Pmode);
   /* Emit the move of the address to a pseudo outside of the libcall.  */
-  if (TARGET_HARD_SH4 && TARGET_SH2E)
+  if (TARGET_DIVIDE_CALL_TABLE)
+    {
+      /* libgcc2:__udivmoddi4 is not supposed to use an actual division, since
+	 that causes problems when the divide code is supposed to come from a
+	 separate library.  Division by zero is undefined, so dividing 1 can be
+	 implemented by comparing with the divisor.  */
+      if (operands[1] == const1_rtx && currently_expanding_to_rtl)
+	{
+	  emit_insn (gen_cmpsi (operands[1], operands[2]));
+	  emit_insn (gen_sgeu (operands[0]));
+	  DONE;
+	}
+      else if (operands[2] == const0_rtx)
+	{
+	  emit_move_insn (operands[0], operands[2]);
+	  DONE;
+	}
+      function_symbol (operands[3], \"__udivsi3_i4i\", SFUNC_GOT);
+      last = gen_udivsi3_i4_int (operands[0], operands[3]);
+    }
+  else if (TARGET_DIVIDE_CALL_FP)
     {
       function_symbol (operands[3], \"__udivsi3_i4\", SFUNC_STATIC);
       if (TARGET_FPU_SINGLE)
@@ -1977,6 +2148,20 @@   "(TARGET_HARD_SH4 || TARGET_SHCOMPACT)
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
+(define_insn "divsi3_i4_int"
+  [(set (match_operand:SI 0 "register_operand" "=z")
+	(div:SI (reg:SI R4_REG) (reg:SI R5_REG)))
+   (clobber (reg:SI T_REG))
+   (clobber (reg:SI PR_REG))
+   (clobber (reg:SI R1_REG))
+   (clobber (reg:SI MACH_REG))
+   (clobber (reg:SI MACL_REG))
+   (use (match_operand:SI 1 "arith_reg_operand" "r"))]
+  "TARGET_SH1"
+  "jsr	@%1%#"
+  [(set_attr "type" "sfunc")
+   (set_attr "needs_delay_slot" "yes")])
+
 (define_expand "divsi3"
   [(set (match_dup 3) (symbol_ref:SI "__sdivsi3"))
    (set (reg:SI R4_REG) (match_operand:SI 1 "general_operand" ""))
@@ -1997,7 +2182,12 @@ 	      (use (match_dup 3))])]
 
   operands[3] = gen_reg_rtx (Pmode);
   /* Emit the move of the address to a pseudo outside of the libcall.  */
-  if (TARGET_HARD_SH4 && TARGET_SH2E)
+  if (TARGET_DIVIDE_CALL_TABLE)
+    {
+      function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT);
+      last = gen_divsi3_i4_int (operands[0], operands[3]);
+    }
+  else if (TARGET_DIVIDE_CALL_FP)
     {
       function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_STATIC);
       if (TARGET_FPU_SINGLE)
@@ -2676,6 +2866,64 @@ 		 (match_operand:SI 1 "arith_reg_operan
   "mul.l	%1,%0"
   [(set_attr "type" "dmpy")])
 
+(define_insn "mulr03"
+  [(set (match_operand:SI 0 "arith_reg_operand" "=r")
+	(mult:SI (match_operand:SI 1 "arith_reg_operand" "%0")
+		 (match_operand:SI 2 "arith_reg_operand" "R03")))]
+  "TARGET_R0R3_TO_REG_MUL - !reload_completed >= 1"
+  "mulr	%2,%0"
+  [(set_attr "type" "dmpy")])
+
+(define_peephole2
+  [(set (reg:SI MACL_REG)
+	(mult:SI (match_operand:SI 1 "arith_reg_operand" "r,R03")
+		 (match_operand:SI 2 "arith_reg_operand" "R03,r")))
+   (set (match_operand:SI 0 "arith_reg_dest" "=r,r") (reg:SI MACL_REG))]
+  "TARGET_R0R3_TO_REG_MUL
+   && peep2_regno_dead_p (2, MACL_REG)
+   && ((!reg_overlap_mentioned_p (operands[0], operands[1])
+	&& true_regnum (operands[1]) <= R3_REG)
+       || (!reg_overlap_mentioned_p (operands[0], operands[2])
+	   && true_regnum (operands[2]) <= R3_REG))"
+  [(set (match_dup 0) (match_dup 3))
+   (set (match_dup 0) (mult:SI (match_dup 0) (match_dup 4)))]
+  "
+{
+  if (reg_overlap_mentioned_p (operands[0], operands[1])
+      || true_regnum (operands[1]) > R3_REG)
+    {
+      operands[4] = operands[2];
+      operands[3] = operands[1];
+    }
+  else
+    {
+      operands[4] = operands[1];
+      operands[3] = operands[2];
+    }
+}")
+
+(define_peephole2
+  [(match_scratch:SI 3 "R03")
+   (set (reg:SI MACL_REG)
+	(mult:SI (match_operand:SI 1 "arith_reg_operand" "r,0")
+		 (match_operand:SI 2 "arith_reg_operand" "0,r")))
+   (set (match_operand:SI 0 "arith_reg_dest" "=r,r") (reg:SI MACL_REG))]
+  "TARGET_R0R3_TO_REG_MUL
+   && peep2_regno_dead_p (3, MACL_REG)
+   && (true_regnum (operands[1]) == true_regnum (operands[0])
+       || true_regnum (operands[2]) == true_regnum (operands[0]))"
+  [(set (match_dup 3) (match_dup 4))
+   (set (match_dup 0) (mult:SI (match_dup 0) (match_dup 3)))]
+  "
+{
+  if (true_regnum (operands[1]) == true_regnum (operands[0]))
+    operands[4] = operands[2];
+  else
+    operands[4] = operands[1];
+}")
+
+;; ??? should we also use mulr if we'd need two reg-reg copies?
+
 (define_expand "mulsi3"
   [(set (reg:SI MACL_REG)
 	(mult:SI  (match_operand:SI 1 "arith_reg_operand" "")
@@ -2687,7 +2935,12 @@ 	(reg:SI MACL_REG))]
 {
   rtx first, last;
 
-  if (!TARGET_SH2)
+  if (TARGET_R0R3_TO_REG_MUL == 2)
+    {
+      emit_insn (gen_mulr03 (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+  else if (!TARGET_SH2)
     {
       /* The address must be set outside the libcall,
 	 since it goes into a pseudo.  */
@@ -4657,7 +4910,7 @@ (define_insn "push_fpul"
   [(set (mem:SF (pre_dec:SI (reg:SI SP_REG))) (reg:SF FPUL_REG))]
   "TARGET_SH2E && ! TARGET_SH5"
   "sts.l	fpul,@-r15"
-  [(set_attr "type" "store")
+  [(set_attr "type" "fstore")
    (set_attr "late_fp_use" "yes")
    (set_attr "hit_stack" "yes")])
 
@@ -4739,9 +4992,9 @@ ;; (set (subreg:SI (mem:QI (plus:SI (reg
 ;; (made from (set (subreg:SI (reg:QI ###) 0) ) into T.
 (define_insn "movsi_i"
   [(set (match_operand:SI 0 "general_movdst_operand"
-	    "=r,r,t,r,r,r,r,m,<,<,x,l,x,l,r")
+	    "=r,r,r,t,r,r,r,r,m,<,<,x,l,x,l,r")
 	(match_operand:SI 1 "general_movsrc_operand"
-	 "Q,rI08,r,mr,x,l,t,r,x,l,r,r,>,>,i"))]
+	 "Q,r,I08,r,mr,x,l,t,r,x,l,r,r,>,>,i"))]
   "TARGET_SH1
    && ! TARGET_SH2E
    && ! TARGET_SH2A
@@ -4750,6 +5003,7 @@        || register_operand (operands[1],
   "@
 	mov.l	%1,%0
 	mov	%1,%0
+	mov	%1,%0
 	cmp/pl	%1
 	mov.l	%1,%0
 	sts	%1,%0
@@ -4763,8 +5017,8 @@        || register_operand (operands[1],
 	lds.l	%1,%0
 	lds.l	%1,%0
 	fake	%1,%0"
-  [(set_attr "type" "pcload_si,move,mt_group,load_si,mac_gp,prget,move,store,store,pstore,move,prset,load,pload,pcload_si")
-   (set_attr "length" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*")])
+  [(set_attr "type" "pcload_si,move,movi8,mt_group,load_si,mac_gp,prget,arith,mac_mem,store,pstore,gp_mac,prset,mem_mac,pload,pcload_si")
+   (set_attr "length" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*")])
 
 ;; t/r must come after r/r, lest reload will try to reload stuff like
 ;; (subreg:SI (reg:SF FR14_REG) 0) into T (compiling stdlib/strtod.c -m3e -O2)
@@ -4774,15 +5028,16 @@ ;; (subreg:SI (reg:SF FR14_REG) 0) into 
 ;; TARGET_FMOVD is in effect, and mode switching is done before reload.
 (define_insn "movsi_ie"
   [(set (match_operand:SI 0 "general_movdst_operand"
-	    "=r,r,r,t,r,r,r,r,m,<,<,x,l,x,l,y,<,r,y,r,*f,y,*f,y")
+	    "=r,r,r,r,t,r,r,r,r,m,<,<,x,l,x,l,y,<,r,y,r,*f,y,*f,y")
 	(match_operand:SI 1 "general_movsrc_operand"
-	 "Q,rI08,I20,r,mr,x,l,t,r,x,l,r,r,>,>,>,y,i,r,y,y,*f,*f,y"))]
+	 "Q,r,I08,I20,r,mr,x,l,t,r,x,l,r,r,>,>,>,y,i,r,y,y,*f,*f,y"))]
   "(TARGET_SH2E || TARGET_SH2A)
    && (register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode))"
   "@
 	mov.l	%1,%0
 	mov	%1,%0
+	mov	%1,%0
 	movi20	%1,%0
 	cmp/pl	%1
 	mov.l	%1,%0
@@ -4805,26 +5060,27 @@        || register_operand (operands[1],
 	flds	%1,fpul
 	fmov	%1,%0
 	! move optimized away"
-  [(set_attr "type" "pcload_si,move,move,*,load_si,mac_gp,prget,move,store,store,pstore,move,prset,load,pload,load,store,pcload_si,gp_fpul,fpul_gp,fmove,fmove,fmove,nil")
-   (set_attr "late_fp_use" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,yes,*,*,yes,*,*,*,*")
-   (set_attr "length" "*,*,4,*,4,*,*,*,4,*,*,*,*,*,*,*,*,*,*,*,*,*,*,0")])
+  [(set_attr "type" "pcload_si,move,movi8,move,*,load_si,mac_gp,prget,arith,store,mac_mem,pstore,gp_mac,prset,mem_mac,pload,load,fstore,pcload_si,gp_fpul,fpul_gp,fmove,fmove,fmove,nil")
+   (set_attr "late_fp_use" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,yes,*,*,yes,*,*,*,*")
+   (set_attr "length" "*,*,*,4,*,4,*,*,*,4,*,*,*,*,*,*,*,*,*,*,*,*,*,*,0")])
 
 (define_insn "movsi_i_lowpart"
-  [(set (strict_low_part (match_operand:SI 0 "general_movdst_operand" "+r,r,r,r,r,r,m,r"))
-	(match_operand:SI 1 "general_movsrc_operand" "Q,rI08,mr,x,l,t,r,i"))]
+  [(set (strict_low_part (match_operand:SI 0 "general_movdst_operand" "+r,r,r,r,r,r,r,m,r"))
+	(match_operand:SI 1 "general_movsrc_operand" "Q,r,I08,mr,x,l,t,r,i"))]
    "TARGET_SH1
     && (register_operand (operands[0], SImode)
         || register_operand (operands[1], SImode))"
   "@
 	mov.l	%1,%0
 	mov	%1,%0
+	mov	%1,%0
 	mov.l	%1,%0
 	sts	%1,%0
 	sts	%1,%0
 	movt	%0
 	mov.l	%1,%0
 	fake	%1,%0"
-  [(set_attr "type" "pcload,move,load,move,prget,move,store,pcload")])
+  [(set_attr "type" "pcload,move,arith,load,mac_gp,prget,arith,store,pcload")])
 
 (define_insn_and_split "load_ra"
   [(set (match_operand:SI 0 "general_movdst_operand" "")
@@ -5078,19 +5334,20 @@   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
 (define_insn "movqi_i"
-  [(set (match_operand:QI 0 "general_movdst_operand" "=r,r,m,r,r,l")
-	(match_operand:QI 1 "general_movsrc_operand"  "ri,m,r,t,l,r"))]
+  [(set (match_operand:QI 0 "general_movdst_operand" "=r,r,r,m,r,r,l")
+	(match_operand:QI 1 "general_movsrc_operand"  "r,i,m,r,t,l,r"))]
   "TARGET_SH1
    && (arith_reg_operand (operands[0], QImode)
        || arith_reg_operand (operands[1], QImode))"
   "@
 	mov	%1,%0
+	mov	%1,%0
 	mov.b	%1,%0
 	mov.b	%1,%0
 	movt	%0
 	sts	%1,%0
 	lds	%1,%0"
- [(set_attr "type" "move,load,store,move,move,move")])
+ [(set_attr "type" "move,movi8,load,store,arith,prget,prset")])
 
 (define_insn "*movqi_media"
   [(set (match_operand:QI 0 "general_movdst_operand" "=r,r,r,m")
@@ -5709,7 +5966,7 @@        (const_int 10) (const_int 8))
       (if_then_else
        (ne (symbol_ref "TARGET_SHCOMPACT") (const_int 0))
        (const_int 10) (const_int 8))])
-   (set_attr "type" "fmove,move,pcfload,fload,store,pcload,load,store,load,fload")
+   (set_attr "type" "fmove,move,pcfload,fload,fstore,pcload,load,store,load,fload")
    (set_attr "late_fp_use" "*,*,*,*,yes,*,*,*,*,*")
    (set (attr "fp_mode") (if_then_else (eq_attr "fmovd" "yes")
 					   (const_string "double")
@@ -6426,7 +6683,7 @@ 	   && GET_CODE (XEXP (operands[0], 0)) 
 	sts.l	%1,%0
 	lds.l	%1,%0
 	! move optimized away"
-  [(set_attr "type" "fmove,move,fmove,fmove,pcfload,fload,store,pcload,load,store,fmove,fmove,load,*,fpul_gp,gp_fpul,store,load,nil")
+  [(set_attr "type" "fmove,move,fmove,fmove,pcfload,fload,fstore,pcload,load,store,fmove,fmove,load,*,fpul_gp,gp_fpul,fstore,load,nil")
    (set_attr "late_fp_use" "*,*,*,*,*,*,yes,*,*,*,*,*,*,*,yes,*,yes,*,*")
    (set_attr "length" "*,*,*,*,4,4,4,*,*,*,2,2,2,4,2,2,2,2,0")
    (set (attr "fp_mode") (if_then_else (eq_attr "fmovd" "yes")
@@ -9803,7 +10060,7 @@        || GET_CODE (XEXP (operands[1], 0
 	sts	fpscr,%0
 	sts.l	fpscr,%0"
   [(set_attr "length" "0,2,2,4,2,2,2,2,2")
-   (set_attr "type" "nil,mem_fpscr,load,mem_fpscr,gp_fpscr,move,store,mac_gp,store")])
+   (set_attr "type" "nil,mem_fpscr,load,mem_fpscr,gp_fpscr,move,store,mac_gp,fstore")])
 
 (define_peephole2
   [(set (reg:PSI FPSCR_REG)
@@ -9854,7 +10111,7 @@   [(set (reg:PSI FPSCR_REG)
 	(xor:PSI (reg:PSI FPSCR_REG) (const_int 1048576)))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fschg"
-  [(set_attr "type" "fp") (set_attr "fp_set" "unknown")])
+  [(set_attr "type" "fpscr_toggle") (set_attr "fp_set" "unknown")])
 
 ;; There's no way we can use it today, since optimize mode switching
 ;; doesn't enable us to know from which mode we're switching to the
@@ -9866,7 +10123,7 @@   [(set (reg:PSI FPSCR_REG)
 	(xor:PSI (reg:PSI FPSCR_REG) (const_int 524288)))]
   "TARGET_SH4A_FP && ! TARGET_FPU_SINGLE"
   "fpchg"
-  [(set_attr "type" "fp")])
+  [(set_attr "type" "fpscr_toggle")])
 
 (define_expand "addsf3"
   [(set (match_operand:SF 0 "arith_reg_operand" "")
@@ -9998,25 +10255,12 @@    (use (match_operand:PSI 3 "fpscr_oper
   [(set_attr "type" "fp")
    (set_attr "fp_mode" "single")])
 
-;; Unfortunately, the combiner is unable to cope with the USE of the FPSCR
-;; register in feeding fp instructions.  Thus, we cannot generate fmac for
-;; mixed-precision SH4 targets.  To allow it to be still generated for the
-;; SH3E, we use a separate insn for SH3E mulsf3.
-
 (define_expand "mulsf3"
   [(set (match_operand:SF 0 "fp_arith_reg_operand" "")
 	(mult:SF (match_operand:SF 1 "fp_arith_reg_operand" "")
 		 (match_operand:SF 2 "fp_arith_reg_operand" "")))]
   "TARGET_SH2E || TARGET_SHMEDIA_FPU"
-  "
-{
-  if (TARGET_SH4 || TARGET_SH2A_SINGLE)
-    expand_sf_binop (&gen_mulsf3_i4, operands);
-  else if (TARGET_SH2E)
-    emit_insn (gen_mulsf3_ie (operands[0], operands[1], operands[2]));
-  if (! TARGET_SHMEDIA)
-    DONE;
-}")
+  "")
 
 (define_insn "*mulsf3_media"
   [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
@@ -10026,6 +10270,27 @@ 		 (match_operand:SF 2 "fp_arith_reg_ope
   "fmul.s	%1, %2, %0"
   [(set_attr "type" "fparith_media")])
 
+;; Unfortunately, the combiner is unable to cope with the USE of the FPSCR
+;; register in feeding fp instructions.  Thus, in order to generate fmac,
+;; we start out with a mulsf pattern that does not depend on fpscr.
+;; This is split after combine to introduce the dependency, in order to
+;; get mode switching and scheduling right.
+(define_insn_and_split "mulsf3_ie"
+  [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
+	(mult:SF (match_operand:SF 1 "fp_arith_reg_operand" "%0")
+		 (match_operand:SF 2 "fp_arith_reg_operand" "f")))]
+  "TARGET_SH2E"
+  "fmul	%2,%0"
+  "TARGET_SH4 || TARGET_SH2A_SINGLE"
+  [(const_int 0)]
+  "
+{
+  emit_insn (gen_mulsf3_i4 (operands[0], operands[1], operands[2],
+	     get_fpscr_rtx ()));
+  DONE;
+}"
+  [(set_attr "type" "fp")])
+
 (define_insn "mulsf3_i4"
   [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
 	(mult:SF (match_operand:SF 1 "fp_arith_reg_operand" "%0")
@@ -10036,14 +10301,6 @@    (use (match_operand:PSI 3 "fpscr_oper
   [(set_attr "type" "fp")
    (set_attr "fp_mode" "single")])
 
-(define_insn "mulsf3_ie"
-  [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
-	(mult:SF (match_operand:SF 1 "fp_arith_reg_operand" "%0")
-		 (match_operand:SF 2 "fp_arith_reg_operand" "f")))]
-  "TARGET_SH2E && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)"
-  "fmul	%2,%0"
-  [(set_attr "type" "fp")])
-
 (define_insn "mac_media"
   [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f")
 	(plus:SF (mult:SF (match_operand:SF 1 "fp_arith_reg_operand" "%f")
@@ -10059,7 +10316,7 @@ 	(plus:SF (mult:SF (match_operand:SF 1 "
 			  (match_operand:SF 2 "fp_arith_reg_operand" "f"))
 		 (match_operand:SF 3 "arith_reg_operand" "0")))
    (use (match_operand:PSI 4 "fpscr_operand" "c"))]
-  "TARGET_SH2E && ! TARGET_SH4"
+  "TARGET_SH2E"
   "fmac	fr0,%2,%0"
   [(set_attr "type" "fp")
    (set_attr "fp_mode" "single")])
@@ -10210,7 +10467,7 @@ 	(gt:SI (match_operand:SF 0 "fp_arith_re
 	       (match_operand:SF 1 "fp_arith_reg_operand" "f")))]
   "TARGET_SH2E && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)"
   "fcmp/gt	%1,%0"
-  [(set_attr "type" "fp")
+  [(set_attr "type" "fp_cmp")
    (set_attr "fp_mode" "single")])
 
 (define_insn "cmpeqsf_t"
@@ -10219,7 +10476,7 @@ 	(eq:SI (match_operand:SF 0 "fp_arith_re
 	       (match_operand:SF 1 "fp_arith_reg_operand" "f")))]
   "TARGET_SH2E && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)"
   "fcmp/eq	%1,%0"
-  [(set_attr "type" "fp")
+  [(set_attr "type" "fp_cmp")
    (set_attr "fp_mode" "single")])
 
 (define_insn "ieee_ccmpeqsf_t"
@@ -10239,7 +10496,7 @@ 	       (match_operand:SF 1 "fp_arith_re
    (use (match_operand:PSI 2 "fpscr_operand" "c"))]
   "(TARGET_SH4 || TARGET_SH2A_SINGLE)"
   "fcmp/gt	%1,%0"
-  [(set_attr "type" "fp")
+  [(set_attr "type" "fp_cmp")
    (set_attr "fp_mode" "single")])
 
 (define_insn "cmpeqsf_t_i4"
@@ -10249,7 +10506,7 @@ 	       (match_operand:SF 1 "fp_arith_re
    (use (match_operand:PSI 2 "fpscr_operand" "c"))]
   "(TARGET_SH4 || TARGET_SH2A_SINGLE)"
   "fcmp/eq	%1,%0"
-  [(set_attr "type" "fp")
+  [(set_attr "type" "fp_cmp")
    (set_attr "fp_mode" "single")])
 
 (define_insn "*ieee_ccmpeqsf_t_4"
@@ -10606,7 +10863,7 @@ 		 (match_operand:DF 2 "fp_arith_reg_ope
    (use (match_operand:PSI 3 "fpscr_operand" "c"))]
   "(TARGET_SH4 || TARGET_SH2A_DOUBLE)"
   "fmul	%2,%0"
-  [(set_attr "type" "dfp_arith")
+  [(set_attr "type" "dfp_mul")
    (set_attr "fp_mode" "double")])
 
 (define_expand "divdf3"
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/sh.opt gcc-4.1.1/gcc/config/sh/sh.opt
--- gcc-4.1.1.orig/gcc/config/sh/sh.opt	2005-06-25 02:22:41.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/sh.opt	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 ; Options for the SH port of the compiler.
 
-; Copyright (C) 2005 Free Software Foundation, Inc.
+; Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+; Copyright (c) 2006  STMicroelectronics.
 ;
 ; This file is part of GCC.
 ;
@@ -57,11 +58,11 @@ Target RejectNegative Condition(SUPPORT_
 Generate SH2a FPU-less code
 
 m2a-single
-Target RejectNegative Condition (SUPPORT_SH2A_SINGLE)
+Target RejectNegative Condition(SUPPORT_SH2A_SINGLE)
 Generate default single-precision SH2a code
 
 m2a-single-only
-Target RejectNegative Condition (SUPPORT_SH2A_SINGLE_ONLY)
+Target RejectNegative Condition(SUPPORT_SH2A_SINGLE_ONLY)
 Generate only single-precision SH2a code
 
 m2e
@@ -80,18 +81,83 @@ m4
 Target RejectNegative Mask(SH4) Condition(SUPPORT_SH4)
 Generate SH4 code
 
+m4-100
+Target RejectNegative Condition(SUPPORT_SH4)
+Generate SH4-100 code
+
+m4-200
+Target RejectNegative Condition(SUPPORT_SH4)
+Generate SH4-200 code
+
+;; TARGET_SH4_300 indicates if we have the ST40-300 instruction set and
+;; pipeline - irrespective of ABI.
+m4-300
+Target RejectNegative Condition(SUPPORT_SH4) Var(TARGET_SH4_300)
+Generate SH4-300 code
+
 m4-nofpu
 Target RejectNegative Condition(SUPPORT_SH4_NOFPU)
 Generate SH4 FPU-less code
 
+m4-100-nofpu
+Target RejectNegative Condition(SUPPORT_SH4_NOFPU)
+Generate SH4-100 FPU-less code
+
+m4-200-nofpu
+Target RejectNegative Condition(SUPPORT_SH4_NOFPU)
+Generate SH4-200 FPU-less code
+
+m4-300-nofpu
+Target RejectNegative Condition(SUPPORT_SH4_NOFPU) Var(TARGET_SH4_300) VarExists
+Generate SH4-300 FPU-less code
+
+m4-340
+Target RejectNegative Condition(SUPPORT_SH4_NOFPU) Var(TARGET_SH4_300) VarExists
+Generate code for SH4 340 series (MMU/FPU-less)
+;; passes -isa=sh4-nommu-nofpu to the assembler.
+
+m4-400
+Target RejectNegative Condition(SUPPORT_SH4_NOFPU)
+Generate code for SH4 400 series (MMU/FPU-less)
+;; passes -isa=sh4-nommu-nofpu to the assembler.
+
+m4-500
+Target RejectNegative Condition(SUPPORT_SH4_NOFPU)
+Generate code for SH4 500 series (FPU-less).
+;; passes -isa=sh4-nofpu to the assembler.
+
 m4-single
 Target RejectNegative Condition(SUPPORT_SH4_SINGLE)
 Generate default single-precision SH4 code
 
+m4-100-single
+Target RejectNegative Condition(SUPPORT_SH4_SINGLE)
+Generate default single-precision SH4-100 code
+
+m4-200-single
+Target RejectNegative Condition(SUPPORT_SH4_SINGLE)
+Generate default single-precision SH4-200 code
+
+m4-300-single
+Target RejectNegative Condition(SUPPORT_SH4_SINGLE) Var(TARGET_SH4_300) VarExists
+Generate default single-precision SH4-300 code
+
 m4-single-only
 Target RejectNegative Condition(SUPPORT_SH4_SINGLE_ONLY)
 Generate only single-precision SH4 code
 
+m4-100-single-only
+Target RejectNegative Condition(SUPPORT_SH4_SINGLE_ONLY)
+Generate only single-precision SH4-100 code
+
+m4-200-single-only
+Target RejectNegative Condition(SUPPORT_SH4_SINGLE_ONLY)
+Generate only single-precision SH4-200 code
+
+m4-300-single-only
+Target RejectNegative Condition(SUPPORT_SH4_SINGLE_ONLY) Var(TARGET_SH4_300) VarExists
+Generate only single-precision SH4-300 code
+
 m4a
 Target RejectNegative Mask(SH4A) Condition(SUPPORT_SH4A)
 Generate SH4a code
@@ -148,6 +214,22 @@ mbigtable
 Target Report RejectNegative Mask(BIGTABLE)
 Generate 32-bit offsets in switch tables
 
+mbranch-cost=
+Target RejectNegative Joined UInteger Var(sh_branch_cost) Init(-1)
+Cost to assume for a branch insn
+
+mcbranchdi
+Target Var(TARGET_CBRANCHDI4)
+Enable cbranchdi4 pattern
+
+mexpand-cbranchdi
+Target Var(TARGET_EXPAND_CBRANCHDI4)
+Expand cbranchdi4 pattern early into separate comparisons and branches.
+
+mcmpeqdi
+Target Var(TARGET_CMPEQDI_T)
+Emit cmpeqdi_t pattern even when -mcbranchdi and -mexpand-cbranchdi are in effect.
+
 mcut2-workaround
 Target RejectNegative Var(TARGET_SH5_CUT2_WORKAROUND)
 Enable SH5 cut2 workaround
@@ -158,7 +240,7 @@ Align doubles at 64-bit boundaries
 
 mdiv=
 Target RejectNegative Joined Var(sh_div_str) Init("")
-Division strategy, one of: call, call2, fp, inv, inv:minlat, inv20u, inv20l, inv:call, inv:call2, inv:fp
+Division strategy, one of: call, call2, fp, inv, inv:minlat, inv20u, inv20l, inv:call, inv:call2, inv:fp, call-div1, call-fp, call-table
 
 mdivsi3_libfunc=
 Target RejectNegative Joined Var(sh_divsi3_libfunc) Init("")
@@ -195,6 +277,10 @@ ml
 Target Report RejectNegative Mask(LITTLE_ENDIAN)
 Generate code in little endian mode
 
+mlate-r0r3-to-reg-mul
+Target RejectNegative Var(TARGET_R0R3_TO_REG_MUL, 1) VarExists
+Assume availability of integer multiply instruction (src only opd in r0-r3), but only try to use this instruction after register allocation.
+
 mnomacsave
 Target Report RejectNegative Mask(NOMACSAVE)
 Mark MAC register as call-clobbered
@@ -213,6 +299,10 @@ mpt-fixed
 Target Report Mask(PT_FIXED) Condition(SUPPORT_ANY_SH5)
 Assume pt* instructions won't trap
 
+mr0r3-to-reg-mul
+Target Var(TARGET_R0R3_TO_REG_MUL, 2) Init(-1)
+Assume availability of integer multiply instruction (src only opd in r0-r3)
+
 mrelax
 Target Report RejectNegative Mask(RELAX)
 Shorten address references during linking
@@ -232,3 +322,9 @@ Cost to assume for a multiply insn
 musermode
 Target Report RejectNegative Mask(USERMODE)
 Generate library function call to invalidate instruction cache entries after fixing trampoline
+
+;; We might want to enable this by default for TARGET_HARD_SH4, because
+;; zero-offset branches have zero latency.  Needs some benchmarking.
+mpretend-cmove
+Target Var(TARGET_PRETEND_CMOVE)
+Pretend a branch-around-a-move is a conditional move.
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/sh-protos.h gcc-4.1.1/gcc/config/sh/sh-protos.h
--- gcc-4.1.1.orig/gcc/config/sh/sh-protos.h	2006-01-30 19:02:39.000000000 +0000
+++ gcc-4.1.1/gcc/config/sh/sh-protos.h	2006-08-10 09:56:05.000000000 +0100
@@ -4,6 +4,7 @@    Copyright (C) 1993, 1994, 1995, 1996,
    Free Software Foundation, Inc.
    Contributed by Steve Chamberlain (sac@cygnus.com).
    Improved by Jim Wilson (wilson@cygnus.com).
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -69,6 +70,10 @@ extern void print_operand (FILE *, rtx, 
 extern void output_pic_addr_const (FILE *, rtx);
 extern int expand_block_move (rtx *);
 extern int prepare_move_operands (rtx[], enum machine_mode mode);
+extern enum rtx_code prepare_cbranch_operands (rtx *, enum machine_mode mode,
+					       enum rtx_code comparison);
+extern void expand_cbranchsi4 (rtx *operands, enum rtx_code comparison);
+extern bool expand_cbranchdi4 (rtx *operands, enum rtx_code comparison);
 extern void from_compare (rtx *, int);
 extern int shift_insns_rtx (rtx);
 extern void gen_ashift (int, int, rtx);
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/superh.h gcc-4.1.1/gcc/config/sh/superh.h
--- gcc-4.1.1.orig/gcc/config/sh/superh.h	2005-06-25 02:22:41.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/superh.h	2006-08-10 09:56:05.000000000 +0100
@@ -1,5 +1,6 @@
 /* Definitions of target machine for gcc for Super-H using sh-superh-elf.
-   Copyright (C) 2001 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2006 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GNU CC.
 
@@ -20,9 +21,9 @@ Boston, MA 02110-1301, USA.  */
 
 
 /* This header file is used when the vendor name is set to 'superh'.
-   It configures the compiler for SH4 only and switches the default
-   endianess to little (although big endian is still available).
-   It also configures the spec file to the default board configuration
+   config.gcc already configured the compiler for SH4 only and switched
+   the default endianess to little (although big endian is still available).
+   This file configures the spec file to the default board configuration
    but in such a way that it can be overridden by a boardspecs file
    (using the -specs= option). This file is expected to disable the
    defaults and provide options --defsym _start and --defsym _stack
@@ -39,57 +40,6 @@    (using the -specs= option). This file
 #undef TARGET_VERSION
 #define TARGET_VERSION fprintf (stderr, " (SuperH SH special %s)", __DATE__);
 
-
-/* We override TARGET_PROCESSOR_SWITCHES in order to remove all the unrequired cpu options
-   and add options for all the SuperH CPU variants:
-   -m4-100  is an alias for -m4.
-   -m4-200  is an alias for -m4.
-   -m4-400  is an alias for -m4-nofpu and passes -isa=sh4-nommu-nofpu to the assembler.
-   -m4-500  is an alias for -m4-nofpu and passes -isa=sh4-nofpu to the assembler.  */
-#undef TARGET_PROCESSOR_SWITCHES
-#define TARGET_PROCESSOR_SWITCHES \
-  {"4-500",	TARGET_NONE, "SH4 500 series (FPU-less)" }, \
-  {"4-500",	SELECT_SH4_NOFPU, "" }, \
-  {"4-400",	TARGET_NONE, "SH4 400 series (MMU/FPU-less)" },	\
-  {"4-400",	SELECT_SH4_NOFPU, "" }, \
-  {"4-200-single-only",	TARGET_NONE, "SH4 200 series with double = float (SH3e ABI)" },	\
-  {"4-200-single-only",	SELECT_SH4_SINGLE_ONLY, "" }, \
-  {"4-200-single",	TARGET_NONE, "SH4 200 series with single precision pervading" }, \
-  {"4-200-single",	SELECT_SH4_SINGLE, "" }, \
-  {"4-200-nofpu",	TARGET_NONE, "SH4 200 series using soft floating point" }, \
-  {"4-200-nofpu",	SELECT_SH4_NOFPU, "" }, \
-  {"4-200",	TARGET_NONE, "SH4 200 series" }, \
-  {"4-200",	SELECT_SH4_NOFPU, "" }, \
-  {"4-100-single-only",	TARGET_NONE, "SH4 100 series with double = float (SH3e ABI)" },	\
-  {"4-100-single-only",	SELECT_SH4_SINGLE_ONLY, "" }, \
-  {"4-100-single",	TARGET_NONE, "SH4 100 series with single precision pervading" }, \
-  {"4-100-single",	SELECT_SH4_SINGLE, "" }, \
-  {"4-100-nofpu",	TARGET_NONE, "SH4 100 series using soft floating point" }, \
-  {"4-100-nofpu",	SELECT_SH4_NOFPU, "" }, \
-  {"4-100",	TARGET_NONE, "SH4 100 series" }, \
-  {"4-100",	SELECT_SH4_NOFPU, "" }, \
-  {"4-single-only",	TARGET_NONE, "Generic SH4 with double = float (SH3e ABI)" }, \
-  {"4-single-only",	SELECT_SH4_SINGLE_ONLY, "" }, \
-  {"4-single",	TARGET_NONE, "Generic SH4 with single precision pervading" }, \
-  {"4-single",	SELECT_SH4_SINGLE, "" }, \
-  {"4-nofpu",	TARGET_NONE, "Generic SH4 using soft floating point" },	\
-  {"4-nofpu",	SELECT_SH4_NOFPU, "" }, \
-  {"4",	        TARGET_NONE, "Generic SH4 (default)" },	\
-  {"4",	        SELECT_SH4, "" }
-
-
-/* Provide the -mboard= option used by the boardspecs file */
-#undef SUBTARGET_OPTIONS
-#define SUBTARGET_OPTIONS \
-  { "board=",   &boardtype, "Board name [and momory region].", 0 }, \
-  { "runtime=", &osruntime, "Runtime name.", 0 }, \
-
-/* These are required by the mboard= option and runtime= option
-   and are defined in sh.c but are not used anywhere */
-extern const char * boardtype;
-extern const char * osruntime;
-
-
 /* Override the linker spec strings to use the new emulation
    The specstrings are concatenated as follows
    LINK_EMUL_PREFIX.(''|'32'|'64'|LINK_DEFAULT_CPU_EMUL).SUBTARGET_LINK_EMUL_SUFFIX
@@ -103,7 +53,7 @@    LINK_EMUL_PREFIX.(''|'32'|'64'|LINK_D
 /* Add the SUBTARGET_LINK_SPEC to add the board and runtime support and
    change the endianness */
 #undef SUBTARGET_LINK_SPEC
-#if  TARGET_ENDIAN_DEFAULT == LITTLE_ENDIAN_BIT
+#if  TARGET_ENDIAN_DEFAULT == MASK_LITTLE_ENDIAN
 #define SUBTARGET_LINK_SPEC "%(board_link) %(ldruntime) %{ml|!mb:-EL}%{mb:-EB}"
 #else
 #define SUBTARGET_LINK_SPEC "%(board_link) %(ldruntime) %{ml:-EL}%{mb|!ml:-EB}"
@@ -126,17 +76,17 @@ /* This is used by the link spec if the 
    on newlib and provide the runtime support */
 #undef SUBTARGET_CPP_SPEC
 #define SUBTARGET_CPP_SPEC \
-"-D__EMBEDDED_CROSS__ %{m4-100*:-D__SH4_100__} %{m4-200*:-D__SH4_200__} %{m4-400:-D__SH4_400__} %{m4-500:-D__SH4_500__} \
+"-D__EMBEDDED_CROSS__ %{m4-100*:-D__SH4_100__} %{m4-200*:-D__SH4_200__} %{m4-300*:-D__SH4_300__} %{m4-340:-D__SH4_340__} %{m4-400:-D__SH4_400__} %{m4-500:-D__SH4_500__} \
 %(cppruntime)"
 
 /* Override the SUBTARGET_ASM_SPEC to add the runtime support */
 #undef SUBTARGET_ASM_SPEC
-#define SUBTARGET_ASM_SPEC "%{m4-100*|m4-200*:-isa=sh4} %{m4-400:-isa=sh4-nommu-nofpu} %{m4-500:-isa=sh4-nofpu} %(asruntime)"
+#define SUBTARGET_ASM_SPEC "%{m4-100*|m4-200*:-isa=sh4} %{m4-400|m4-340:-isa=sh4-nommu-nofpu} %{m4-500:-isa=sh4-nofpu} %(asruntime)"
 
 /* Override the SUBTARGET_ASM_RELAX_SPEC so it doesn't interfere with the
    runtime support by adding -isa=sh4 in the wrong place.  */
 #undef SUBTARGET_ASM_RELAX_SPEC
-#define SUBTARGET_ASM_RELAX_SPEC "%{!m4-100*:%{!m4-200*:%{!m4-400:%{!m4-500:-isa=sh4}}}}"
+#define SUBTARGET_ASM_RELAX_SPEC "%{!m4-100*:%{!m4-200*:%{!m4-300*:%{!m4-340:%{!m4-400:%{!m4-500:-isa=sh4}}}}}}"
 
 /* Create the CC1_SPEC to add the runtime support */
 #undef CC1_SPEC
@@ -149,3 +99,11 @@ #define CC1PLUS_SPEC "%(cc1runtime)"
 /* Override the LIB_SPEC to add the runtime support */
 #undef LIB_SPEC
 #define LIB_SPEC "%{!shared:%{!symbolic:%(libruntime) -lc}} %{pg:-lprofile -lc}"
+
+/* Override STARTFILE_SPEC to add profiling and MMU support.  */
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+  "%{!shared: %{!m4-400*:%{!m4-340*: %{pg:gcrt1-mmu.o%s}%{!pg:crt1-mmu.o%s}}}} \
+   %{!shared: %{m4-340*|m4-400*: %{pg:gcrt1.o%s}%{!pg:crt1.o%s}}} \
+   crti.o%s \
+   %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}"
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/superh.opt gcc-4.1.1/gcc/config/sh/superh.opt
--- gcc-4.1.1.orig/gcc/config/sh/superh.opt	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/superh.opt	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,10 @@
+;; The -mboard and -mruntime options need only be accepted here, they are
+;; actually processed by supplementary specs files.
+
+mboard=
+Target RejectNegative Joined
+Board name [and memory region].
+
+mruntime=
+Target RejectNegative Joined
+Runtime name.
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/t-elf gcc-4.1.1/gcc/config/sh/t-elf
--- gcc-4.1.1.orig/gcc/config/sh/t-elf	2004-06-21 19:18:40.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/t-elf	2006-08-10 09:56:05.000000000 +0100
@@ -1,5 +1,6 @@
 EXTRA_MULTILIB_PARTS= crt1.o crti.o crtn.o \
-	crtbegin.o crtend.o crtbeginS.o crtendS.o
+	crtbegin.o crtend.o crtbeginS.o crtendS.o $(IC_EXTRA_PARTS) \
+	$(OPT_EXTRA_PARTS)
 
 # Compile crtbeginS.o and crtendS.o with pic.
 CRTSTUFF_T_CFLAGS_S = -fPIC
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/t-sh gcc-4.1.1/gcc/config/sh/t-sh
--- gcc-4.1.1.orig/gcc/config/sh/t-sh	2006-01-30 16:19:11.000000000 +0000
+++ gcc-4.1.1/gcc/config/sh/t-sh	2006-08-10 09:56:05.000000000 +0100
@@ -5,6 +5,7 @@ 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) 
 LIB1ASMSRC = sh/lib1funcs.asm
 LIB1ASMFUNCS = _ashiftrt _ashiftrt_n _ashiftlt _lshiftrt _movmem \
   _movmem_i4 _mulsi3 _sdivsi3 _sdivsi3_i4 _udivsi3 _udivsi3_i4 _set_fpscr \
+  _div_table _udiv_qrnnd_16 \
   $(LIB1ASMFUNCS_CACHE)
 
 # We want fine grained libraries, so use the new code to build the
@@ -37,9 +38,12 @@ MULTILIB_DIRNAMES= 
 # is why sh2a and sh2a-single need their own multilibs.
 MULTILIB_MATCHES = $(shell \
   multilibs="$(MULTILIB_OPTIONS)" ; \
-  for abi in m1,m2,m3,m4-nofpu,m4al,m4a-nofpu m1,m2,m2a-nofpu \
-             m2e,m3e,m4-single-only,m4a-single-only m2e,m2a-single-only \
-             m4-single,m4a-single m4,m4a \
+  for abi in m1,m2,m3,m4-nofpu,m4-100-nofpu,m4-200-nofpu,m4-400,m4-500,m4-340,m4-300-nofpu,m4al,m4a-nofpu \
+             m1,m2,m2a-nofpu \
+             m2e,m3e,m4-single-only,m4-100-single-only,m4-200-single-only,m4-300-single-only,m4a-single-only \
+             m2e,m2a-single-only \
+             m4-single,m4-100-single,m4-200-single,m4-300-single,m4a-single \
+             m4,m4-100,m4-200,m4-300,m4a \
              m5-32media,m5-compact,m5-32media \
              m5-32media-nofpu,m5-compact-nofpu,m5-32media-nofpu; do \
     subst= ; \
@@ -71,6 +75,42 @@ gt-sh.h : s-gtype ; @true
 # These are not suitable for COFF.
 # EXTRA_MULTILIB_PARTS= crt1.o crti.o crtn.o crtbegin.o crtend.o
 
+IC_EXTRA_PARTS= libic_invalidate_array_4-100.a libic_invalidate_array_4-200.a \
+libic_invalidate_array_4a.a
+OPT_EXTRA_PARTS= libgcc-Os-4-200.a libgcc-4-300.a
+EXTRA_MULTILIB_PARTS= $(IC_EXTRA_PARTS) $(OPT_EXTRA_PARTS)
+
+$(T)ic_invalidate_array_4-100.o: $(srcdir)/config/sh/lib1funcs.asm $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)ic_invalidate_array_4-100.o -DL_ic_invalidate_array -DWAYS=1 -DWAY_SIZE=0x2000 -x assembler-with-cpp $(srcdir)/config/sh/lib1funcs.asm
+$(T)libic_invalidate_array_4-100.a: $(T)ic_invalidate_array_4-100.o $(GCC_PASSES)
+	$(AR_CREATE_FOR_TARGET) $(T)libic_invalidate_array_4-100.a $(T)ic_invalidate_array_4-100.o
+
+$(T)ic_invalidate_array_4-200.o: $(srcdir)/config/sh/lib1funcs.asm $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)ic_invalidate_array_4-200.o -DL_ic_invalidate_array -DWAYS=2 -DWAY_SIZE=0x2000 -x assembler-with-cpp $(srcdir)/config/sh/lib1funcs.asm
+$(T)libic_invalidate_array_4-200.a: $(T)ic_invalidate_array_4-200.o $(GCC_PASSES)
+	$(AR_CREATE_FOR_TARGET) $(T)libic_invalidate_array_4-200.a $(T)ic_invalidate_array_4-200.o
+
+$(T)ic_invalidate_array_4a.o: $(srcdir)/config/sh/lib1funcs.asm $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)ic_invalidate_array_4a.o -DL_ic_invalidate_array -D__FORCE_SH4A__ -x assembler-with-cpp $(srcdir)/config/sh/lib1funcs.asm
+$(T)libic_invalidate_array_4a.a: $(T)ic_invalidate_array_4a.o $(GCC_PASSES)
+	$(AR_CREATE_FOR_TARGET) $(T)libic_invalidate_array_4a.a $(T)ic_invalidate_array_4a.o
+
+$(T)sdivsi3_i4i-Os-4-200.o: $(srcdir)/config/sh/lib1funcs-Os-4-200.asm $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $@ -DL_sdivsi3_i4i -x assembler-with-cpp $<
+$(T)udivsi3_i4i-Os-4-200.o: $(srcdir)/config/sh/lib1funcs-Os-4-200.asm $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $@ -DL_udivsi3_i4i -x assembler-with-cpp $<
+$(T)unwind-dw2-Os-4-200.o: $(srcdir)/unwind-dw2.c $(srcdir)/unwind-generic.h unwind-pe.h unwind.inc unwind-dw2-fde.h unwind-dw2.h $(CONFIG_H) coretypes.h $(TM_H) $(MACHMODE_H) longlong.h config.status stmp-int-hdrs tsystem.h $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) $(vis_hide) -fexceptions -Os -c -o $@ $<
+OBJS_Os_4_200=$(T)sdivsi3_i4i-Os-4-200.o $(T)udivsi3_i4i-Os-4-200.o $(T)unwind-dw2-Os-4-200.o
+$(T)libgcc-Os-4-200.a: $(OBJS_Os_4_200) $(GCC_PASSES)
+	$(AR_CREATE_FOR_TARGET) $@ $(OBJS_Os_4_200)
+
+$(T)div_table-4-300.o: $(srcdir)/config/sh/lib1funcs-4-300.asm $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $@ -DL_div_table -x assembler-with-cpp $<
+
+$(T)libgcc-4-300.a: $(T)div_table-4-300.o $(GCC_PASSES)
+	$(AR_CREATE_FOR_TARGET) $@ $(T)div_table-4-300.o
+
 # Local Variables:
 # mode: Makefile
 # End:
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config/sh/t-superh gcc-4.1.1/gcc/config/sh/t-superh
--- gcc-4.1.1.orig/gcc/config/sh/t-superh	2005-05-09 18:42:55.000000000 +0100
+++ gcc-4.1.1/gcc/config/sh/t-superh	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,15 @@
-MULTILIB_OPTIONS= mb m4-nofpu/m4-single/m4-single-only
-MULTILIB_DIRNAMES= 
-MULTILIB_MATCHES = m4=m4-100 m4-nofpu=m4-100-nofpu m4-single=m4-100-single m4-single-only=m4-100-single-only \
-		   m4=m4-200 m4-nofpu=m4-200-nofpu m4-single=m4-200-single m4-single-only=m4-200-single-only \
-		   m4-nofpu=m4-400 \
-		   m4-nofpu=m4-500
+EXTRA_MULTILIB_PARTS= crt1.o crti.o crtn.o \
+	crtbegin.o crtend.o crtbeginS.o crtendS.o \
+	crt1-mmu.o gcrt1-mmu.o gcrt1.o $(IC_EXTRA_PARTS) $(OPT_EXTRA_PARTS)
+
+# Compile crt1-mmu.o as crt1.o with -DMMU_SUPPORT
+$(T)crt1-mmu.o: $(srcdir)/config/sh/crt1.asm $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crt1-mmu.o -DMMU_SUPPORT -x assembler-with-cpp $(srcdir)/config/sh/crt1.asm
+
+# Compile gcrt1-mmu.o as crt1-mmu.o with -DPROFILE
+$(T)gcrt1-mmu.o: $(srcdir)/config/sh/crt1.asm $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)gcrt1-mmu.o -DPROFILE -DMMU_SUPPORT -x assembler-with-cpp $(srcdir)/config/sh/crt1.asm
+
+# For sh4-400: Compile gcrt1.o as crt1.o with -DPROFILE
+$(T)gcrt1.o: $(srcdir)/config/sh/crt1.asm $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)gcrt1.o -DPROFILE -x assembler-with-cpp $(srcdir)/config/sh/crt1.asm
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/config.gcc gcc-4.1.1/gcc/config.gcc
--- gcc-4.1.1.orig/gcc/config.gcc	2006-05-09 21:02:29.000000000 +0100
+++ gcc-4.1.1/gcc/config.gcc	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 # GCC target-specific configuration file.
 # Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
 # Free Software Foundation, Inc.
+# Copyright (c) 2006  STMicroelectronics.
 
 #This file is part of GCC.
 
@@ -1919,7 +1920,18 @@ sh-*-symbianelf* | sh[12346l]*-*-symbian
 	sh*-*-kaos*)	tm_file="${tm_file} sh/embed-elf.h kaos.h sh/kaos-sh.h"
 			;;
 	sh*-*-netbsd*)	tm_file="${tm_file} netbsd.h netbsd-elf.h sh/netbsd-elf.h" ;;
-	*)		tm_file="${tm_file} sh/embed-elf.h" ;;
+	sh*-superh-elf)	if test x$with_libgloss != xno; then
+				with_libgloss=yes
+				tm_file="${tm_file} sh/newlib.h"
+			fi
+			tm_file="${tm_file} sh/embed-elf.h sh/superh.h"
+			tmake_file="${tmake_file} sh/t-superh"
+			extra_options="${extra_options} sh/superh.opt" ;;
+	*)		if test x$with_newlib = xyes \
+			   && test x$with_libgloss = xyes; then
+				tm_file="${tm_file} sh/newlib.h"
+			fi
+			tm_file="${tm_file} sh/embed-elf.h" ;;
 	esac
 	case ${target} in
 	sh5*-*-netbsd*)
@@ -1973,7 +1985,21 @@ sh-*-symbianelf* | sh[12346l]*-*-symbian
 	sh2*)			sh_cpu_target=sh2 ;;
 	*)			sh_cpu_target=sh1 ;;
 	esac
-	sh_cpu_default="`echo $with_cpu|sed s/^m/sh/|tr A-Z_ a-z-`"
+	# did the user say --without-fp ?
+	if test x$with_fp = xno; then
+		case ${sh_cpu_target} in
+		sh5-*media)	sh_cpu_target=${sh_cpu_target}-nofpu ;;
+		sh4al | sh1)	;;
+		sh4a* )		sh_cpu_target=sh4a-nofpu ;;
+		sh4*)		sh_cpu_target=sh4-nofpu ;;
+		sh3*)		sh_cpu_target=sh3 ;;
+		sh2a*)		sh_cpu_target=sh2a-nofpu ;;
+		sh2*)		sh_cpu_target=sh2 ;;
+		*)	echo --without-fp not available for $target: ignored
+		esac
+		tm_defines="$tm_defines STRICT_NOFPU=1"
+	fi
+	sh_cpu_default="`echo $with_cpu|sed 's/^m/sh/'|tr ABCDEFGHIJKLMNOPQRSTUVWXYZ_ abcdefghijklmnopqrstuvwxyz-`"
 	case $sh_cpu_default in
 	sh5-64media-nofpu | sh5-64media | \
 	  sh5-32media-nofpu | sh5-32media | sh5-compact-nofpu | sh5-compact | \
@@ -1987,6 +2013,7 @@ sh-*-symbianelf* | sh[12346l]*-*-symbian
 	sh_multilibs=${with_multilib_list}
 	if test x${sh_multilibs} = x ; then
 		case ${target} in
+		sh64-superh-linux* | \
 		sh[1234]*)	sh_multilibs=${sh_cpu_target} ;;
 		sh64* | sh5*)	sh_multilibs=m5-32media,m5-32media-nofpu,m5-compact,m5-compact-nofpu,m5-64media,m5-64media-nofpu ;;
 		sh-superh-*)	sh_multilibs=m4,m4-single,m4-single-only,m4-nofpu ;;
@@ -1994,10 +2021,13 @@ sh-*-symbianelf* | sh[12346l]*-*-symbian
 		sh*-*-netbsd*)	sh_multilibs=m3,m3e,m4 ;;
 		*) sh_multilibs=m1,m2,m2e,m4,m4-single,m4-single-only,m2a,m2a-single ;;
 		esac
+		if test x$with_fp = xno; then
+			sh_multilibs="`echo $sh_multilibs|sed -e s/m4/sh4-nofpu/ -e 's/,m4-[^,]*//g' -e 's/,m[23]e//' -e s/m2a,m2a-single/m2a-nofpu/ -e s/m5-..m....,//g`"
+		fi
 	fi
-	target_cpu_default=SELECT_`echo ${sh_cpu_default}|tr a-z- A-Z_`
+	target_cpu_default=SELECT_`echo ${sh_cpu_default}|tr abcdefghijklmnopqrstuvwxyz- ABCDEFGHIJKLMNOPQRSTUVWXYZ_`
 	tm_defines=${tm_defines}' SH_MULTILIB_CPU_DEFAULT=\"'`echo $sh_cpu_default|sed s/sh/m/`'\"'
-	sh_multilibs=`echo $sh_multilibs,$sh_cpu_default | sed -e 's/[ 	,/][ 	,]*/ /g' -e 's/ $//' -e s/^m/sh/ -e 's/ m/ sh/g' | tr A-Z_ a-z-`
+	sh_multilibs=`echo $sh_multilibs,$sh_cpu_default | sed -e 's/[ 	,/][ 	,]*/ /g' -e 's/ $//' -e 's/^m/sh/' -e 's/ m/ sh/g' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ_ abcdefghijklmnopqrstuvwxyz-`
 	for sh_multilib in ${sh_multilibs}; do
 		case ${sh_multilib} in
 		sh1 | sh2 | sh2e | sh3 | sh3e | \
@@ -2008,7 +2038,7 @@ sh-*-symbianelf* | sh[12346l]*-*-symbian
 		sh5-32media | sh5-32media-nofpu | \
 		sh5-compact | sh5-compact-nofpu)
 			tmake_file="${tmake_file} sh/t-mlib-${sh_multilib}"
-			tm_defines="$tm_defines SUPPORT_`echo $sh_multilib|tr a-z- A-Z_`=1"
+			tm_defines="$tm_defines SUPPORT_`echo $sh_multilib|tr abcdefghijklmnopqrstuvwxyz- ABCDEFGHIJKLMNOPQRSTUVWXYZ_`=1"
 			;;
 		*)
 			echo "with_multilib_list=${sh_multilib} not supported."
@@ -2016,7 +2046,7 @@ sh-*-symbianelf* | sh[12346l]*-*-symbian
 			;;
 		esac
 	done
-	if test x${enable_incomplete_targets} == xyes ; then
+	if test x${enable_incomplete_targets} = xyes ; then
 		tm_defines="$tm_defines SUPPORT_SH1=1 SUPPORT_SH2E=1 SUPPORT_SH4=1 SUPPORT_SH4_SINGLE=1 SUPPORT_SH2A=1 SUPPORT_SH2A_SINGLE=1 SUPPORT_SH5_32MEDIA=1 SUPPORT_SH5_32MEDIA_NOFPU=1 SUPPORT_SH5_64MEDIA=1 SUPPORT_SH5_64MEDIA_NOFPU=1"
 	fi
 	use_fixproto=yes
@@ -2740,7 +2770,7 @@ 			  new_val=`grep "^ARM_CORE(\"$val\","
 
 	sh[123456ble]-*-* | sh-*-*)
 		supported_defaults="cpu"
-		case "`echo $with_cpu | tr A-Z_ a-z- | sed s/sh/m/`" in
+		case "`echo $with_cpu | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ_ abcdefghijklmnopqrstuvwxyz- | sed s/sh/m/`" in
 		"" | m1 | m2 | m2e | m3 | m3e | m4 | m4-single | m4-single-only | m4-nofpu )
 			# OK
 			;;
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/configure gcc-4.1.1/gcc/configure
--- gcc-4.1.1.orig/gcc/configure	2006-02-14 16:50:45.000000000 +0000
+++ gcc-4.1.1/gcc/configure	2006-08-10 09:56:18.000000000 +0100
@@ -309,7 +309,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os target_noncanonical build_subdir host_subdir target_subdir GENINSRC CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT NO_MINUS_C_MINUS_O OUTPUT_OPTION CPP EGREP strict1_warn warn_cflags WERROR nocommon_flag TREEBROWSER valgrind_path valgrind_path_defines valgrind_command coverage_flags enable_multilib enable_shared TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE CROSS_SYSTEM_HEADER_DIR onestep SET_MAKE AWK LN_S LN RANLIB ac_ct_RANLIB ranlib_flags INSTALL INSTALL_PROGRAM INSTALL_DATA make_compare_target have_mktemp_command MAKEINFO BUILD_INFO GENERATED_MANPAGES FLEX BISON NM AR stage1_cflags COLLECT2_LIBS GNAT_LIBEXC LDEXP_LIB TARGET_GETGROUPS_T LIBICONV LTLIBICONV LIBICONV_DEP manext objext gthread_flags extra_modes_file extra_opt_files USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS host_cc_for_libada CROSS ALL SYSTEM_HEADER_DIR inhibit_libc CC_FOR_BUILD BUILD_CFLAGS STMP_FIXINC STMP_FIXPROTO collect2 gcc_cv_as ORIGINAL_AS_FOR_TARGET gcc_cv_ld ORIGINAL_LD_FOR_TARGET gcc_cv_nm ORIGINAL_NM_FOR_TARGET gcc_cv_objdump ORIGINAL_OBJDUMP_FOR_TARGET libgcc_visibility GGC zlibdir zlibinc MAINT gcc_tooldir dollar slibdir objdir subdirs srcdir all_boot_languages all_compilers all_gtfiles all_gtfiles_files_langs all_gtfiles_files_files all_lang_makefrags all_lang_makefiles all_languages all_stagestuff build_exeext build_install_headers_dir build_xm_file_list build_xm_include_list build_xm_defines check_languages cc_set_by_configure quoted_cc_set_by_configure cpp_install_dir xmake_file tmake_file extra_gcc_objs extra_headers_list extra_objs extra_parts extra_passes extra_programs float_h_file gcc_config_arguments gcc_gxx_include_dir libstdcxx_incdir host_exeext host_xm_file_list host_xm_include_list host_xm_defines out_host_hook_obj install lang_opt_files lang_specs_files lang_tree_files local_prefix md_file objc_boehm_gc out_file out_object_file stage_prefix_set_by_configure quoted_stage_prefix_set_by_configure thread_file tm_file_list tm_include_list tm_defines tm_p_file_list tm_p_include_list xm_file_list xm_include_list xm_defines c_target_objs cxx_target_objs target_cpu_default GMPLIBS GMPINC LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os target_noncanonical build_subdir host_subdir target_subdir GENINSRC CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT NO_MINUS_C_MINUS_O OUTPUT_OPTION CPP EGREP strict1_warn warn_cflags WERROR nocommon_flag TREEBROWSER valgrind_path valgrind_path_defines valgrind_command coverage_flags enable_multilib enable_shared TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE CROSS_SYSTEM_HEADER_DIR onestep SET_MAKE AWK LN_S LN RANLIB ac_ct_RANLIB ranlib_flags INSTALL INSTALL_PROGRAM INSTALL_DATA make_compare_target have_mktemp_command MAKEINFO BUILD_INFO GENERATED_MANPAGES FLEX BISON NM AR stage1_cflags COLLECT2_LIBS GNAT_LIBEXC LDEXP_LIB TARGET_GETGROUPS_T LIBICONV LTLIBICONV LIBICONV_DEP manext objext gthread_flags extra_modes_file extra_opt_files USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS host_cc_for_libada CROSS ALL SYSTEM_HEADER_DIR inhibit_libc CC_FOR_BUILD BUILD_CFLAGS STMP_FIXINC STMP_FIXPROTO collect2 gcc_cv_as ORIGINAL_AS_FOR_TARGET gcc_cv_ld ORIGINAL_LD_FOR_TARGET gcc_cv_nm ORIGINAL_NM_FOR_TARGET gcc_cv_objdump ORIGINAL_OBJDUMP_FOR_TARGET libgcc_visibility GGC zlibdir zlibinc MAINT gcc_tooldir dollar slibdir objdir subdirs srcdir all_boot_languages all_compilers all_gtfiles all_gtfiles_files_langs all_gtfiles_files_files all_lang_makefrags all_lang_makefiles all_languages all_stagestuff build_exeext build_install_headers_dir build_xm_file_list build_xm_include_list build_xm_defines check_languages cc_set_by_configure quoted_cc_set_by_configure cpp_install_dir xmake_file tmake_file extra_gcc_objs extra_headers_list extra_libgcc_srcs extra_objs extra_parts extra_passes extra_programs float_h_file gcc_config_arguments gcc_gxx_include_dir libstdcxx_incdir host_exeext host_xm_file_list host_xm_include_list host_xm_defines out_host_hook_obj install lang_opt_files lang_specs_files lang_tree_files local_prefix md_file objc_boehm_gc out_file out_object_file stage_prefix_set_by_configure quoted_stage_prefix_set_by_configure thread_file tm_file_list tm_include_list tm_defines tm_p_file_list tm_p_include_list xm_file_list xm_include_list xm_defines c_target_objs cxx_target_objs target_cpu_default GMPLIBS GMPINC LIBOBJS LTLIBOBJS'
 ac_subst_files='language_hooks'
 
 # Initialize some variables set by options.
@@ -6307,6 +6307,9 @@ is_release=
 if test x"`cat $srcdir/DEV-PHASE`" != xexperimental; then
   is_release=yes
 fi
+# This compiler has been modified from the official FSF release, and
+# we want to enable sanity checks.
+is_release=
 # Check whether --enable-werror or --disable-werror was given.
 if test "${enable_werror+set}" = set; then
   enableval="$enable_werror"
@@ -7492,7 +7495,7 @@   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
     ac_prog_version=`$MAKEINFO --version 2>&1 |
                    sed -n 's/^.*GNU texinfo.* \([0-9][0-9.]*\).*$/\1/p'`
-  echo "configure:7495: version of makeinfo is $ac_prog_version" >&5
+  echo "configure:7498: version of makeinfo is $ac_prog_version" >&5
   case $ac_prog_version in
     '')     gcc_cv_prog_makeinfo_modern=no;;
     4.[2-9]*)
@@ -12089,7 +12092,7 @@ case ${enable_threads} in
     target_thread_file='single'
     ;;
   aix | dce | gnat | irix | posix | posix95 | rtems | \
-  single | solaris | vxworks | win32 )
+  single | solaris | vxworks | win32 | generic)
     target_thread_file=${enable_threads}
     ;;
   *)
@@ -12110,6 +12113,14 @@ if test $thread_file != single; then
   rm -f gthr-default.h
   echo "#include \"gthr-${thread_file}.h\"" > gthr-default.h
   gthread_flags=-DHAVE_GTHR_DEFAULT
+  if test $thread_file != posix; then
+    if test -f $srcdir/gthr-${thread_file}.c; then
+      extra_libgcc_srcs=$srcdir/gthr-${thread_file}.c
+    fi
+    if test -f $srcdir/gthr-objc-${thread_file}.c; then
+      extra_libgcc_srcs="${extra_libgcc_srcs} $srcdir/gthr-objc-${thread_file}.c"
+    fi
+  fi
 fi
 
 
@@ -14316,11 +14327,14 @@ cat > conftest.big <<EOF
 EOF
   # If the assembler didn't choke, and we can objdump,
   # and we got the correct data, then succeed.
+  # The text in the here-document typically retains its unix-style line
+  # endings, while the output of objdump will use host line endings.
+  # Therefore, use diff -b for the comparisons.
   if test x$gcc_cv_objdump != x \
   && $gcc_cv_objdump -s -j .eh_frame conftest.o 2>/dev/null \
      | tail -3 > conftest.got \
-  && { cmp conftest.lit conftest.got > /dev/null 2>&1 \
-    || cmp conftest.big conftest.got > /dev/null 2>&1; }
+  && { diff -b conftest.lit conftest.got > /dev/null 2>&1 \
+    || diff -b conftest.big conftest.got > /dev/null 2>&1; }
   then
     gcc_cv_as_eh_frame=yes
   elif { ac_try='$gcc_cv_as -o conftest.o --traditional-format /dev/null'
@@ -16544,6 +16558,7 @@ objdir=`${PWDCMD-pwd}`
 
 
 
+
 # Echo link setup.
 if test x${build} = x${host} ; then
   if test x${host} = x${target} ; then
@@ -17331,6 +17346,7 @@ s,@xmake_file@,$xmake_file,;t t
 s,@tmake_file@,$tmake_file,;t t
 s,@extra_gcc_objs@,$extra_gcc_objs,;t t
 s,@extra_headers_list@,$extra_headers_list,;t t
+s,@extra_libgcc_srcs@,$extra_libgcc_srcs,;t t
 s,@extra_objs@,$extra_objs,;t t
 s,@extra_parts@,$extra_parts,;t t
 s,@extra_passes@,$extra_passes,;t t
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/configure.ac gcc-4.1.1/gcc/configure.ac
--- gcc-4.1.1.orig/gcc/configure.ac	2006-02-14 16:50:45.000000000 +0000
+++ gcc-4.1.1/gcc/configure.ac	2006-08-10 09:56:05.000000000 +0100
@@ -3,6 +3,7 @@
 
 # Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
 # Free Software Foundation, Inc.
+# Copyright (c) 2006  STMicroelectronics.
 
 #This file is part of GCC.
 
@@ -386,6 +387,9 @@ is_release=
 if test x"`cat $srcdir/DEV-PHASE`" != xexperimental; then
   is_release=yes
 fi
+# This compiler has been modified from the official FSF release, and
+# we want to enable sanity checks.
+is_release=
 AC_ARG_ENABLE(werror, 
 [  --enable-werror         enable -Werror in bootstrap stage2 and later], [],
 [if test x$is_release = x ; then
@@ -1323,7 +1327,7 @@ case ${enable_threads} in
     target_thread_file='single'
     ;;
   aix | dce | gnat | irix | posix | posix95 | rtems | \
-  single | solaris | vxworks | win32 )
+  single | solaris | vxworks | win32 | generic)
     target_thread_file=${enable_threads}
     ;;
   *)
@@ -1344,6 +1348,14 @@ if test $thread_file != single; then
   rm -f gthr-default.h
   echo "#include \"gthr-${thread_file}.h\"" > gthr-default.h
   gthread_flags=-DHAVE_GTHR_DEFAULT
+  if test $thread_file != posix; then
+    if test -f $srcdir/gthr-${thread_file}.c; then
+      extra_libgcc_srcs=$srcdir/gthr-${thread_file}.c
+    fi
+    if test -f $srcdir/gthr-objc-${thread_file}.c; then
+      extra_libgcc_srcs="${extra_libgcc_srcs} $srcdir/gthr-objc-${thread_file}.c"
+    fi
+  fi
 fi
 AC_SUBST(gthread_flags)
 
@@ -2122,11 +2134,14 @@ cat > conftest.big <<EOF
 EOF
   # If the assembler didn't choke, and we can objdump,
   # and we got the correct data, then succeed.
+  # The text in the here-document typically retains its unix-style line
+  # endings, while the output of objdump will use host line endings.
+  # Therefore, use diff -b for the comparisons.
   if test x$gcc_cv_objdump != x \
   && $gcc_cv_objdump -s -j .eh_frame conftest.o 2>/dev/null \
      | tail -3 > conftest.got \
-  && { cmp conftest.lit conftest.got > /dev/null 2>&1 \
-    || cmp conftest.big conftest.got > /dev/null 2>&1; }
+  && { diff -b conftest.lit conftest.got > /dev/null 2>&1 \
+    || diff -b conftest.big conftest.got > /dev/null 2>&1; }
   then
     gcc_cv_as_eh_frame=yes
   elif AC_TRY_COMMAND($gcc_cv_as -o conftest.o --traditional-format /dev/null); then
@@ -3407,6 +3422,7 @@ AC_SUBST(xmake_file)
 AC_SUBST(tmake_file)
 AC_SUBST(extra_gcc_objs)
 AC_SUBST(extra_headers_list)
+AC_SUBST(extra_libgcc_srcs)
 AC_SUBST(extra_objs)
 AC_SUBST(extra_parts)
 AC_SUBST(extra_passes)
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/c-opts.c gcc-4.1.1/gcc/c-opts.c
--- gcc-4.1.1.orig/gcc/c-opts.c	2006-01-26 19:06:06.000000000 +0000
+++ gcc-4.1.1/gcc/c-opts.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* C/ObjC/C++ command line option handling.
    Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Neil Booth.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -278,6 +279,7 @@       if (lang_fortran && (cl_options[co
       break;
 
     case OPT__output_pch_:
+      CYGPATH (arg);
       pch_file = arg;
       break;
 
@@ -337,11 +339,13 @@       cpp_opts->deps.style = (code == OP
     case OPT_MD:
     case OPT_MMD:
       cpp_opts->deps.style = (code == OPT_MD ? DEPS_SYSTEM: DEPS_USER);
+      CYGPATH (arg);
       deps_file = arg;
       break;
 
     case OPT_MF:
       deps_seen = true;
+      CYGPATH (arg);
       deps_file = arg;
       break;
 
@@ -813,10 +817,12 @@       add_path (xstrdup (arg), AFTER, 0,
 
     case OPT_imacros:
     case OPT_include:
+      CYGPATH (arg);
       defer_opt (code, arg);
       break;
 
     case OPT_iprefix:
+      CYGPATH (arg);
       iprefix = arg;
       break;
 
@@ -825,6 +831,7 @@       add_path (xstrdup (arg), QUOTE, 0,
       break;
 
     case OPT_isysroot:
+      CYGPATH (arg);
       sysroot = arg;
       break;
 
@@ -863,7 +870,10 @@       cpp_set_lang (parse_in, CLK_ASM);
 
     case OPT_o:
       if (!out_fname)
-	out_fname = arg;
+	{
+	  CYGPATH (arg);
+	  out_fname = arg;
+	}
       else
 	error ("output filename specified twice");
       break;
@@ -1228,7 +1238,10 @@ 	  defer_opt (OPT_MT, s + 1);
 
       /* Command line -MF overrides environment variables and default.  */
       if (!deps_file)
-	deps_file = spec;
+	{
+	  CYGPATH (spec);
+	  deps_file = spec;
+	}
 
       deps_append = 1;
       deps_seen = true;
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/cp/ChangeLog.STM gcc-4.1.1/gcc/cp/ChangeLog.STM
--- gcc-4.1.1.orig/gcc/cp/ChangeLog.STM	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/cp/ChangeLog.STM	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,5 @@
+2006-06-23  J"orn Rennecke <joern.rennecke@st.com>
+
+	* except.c (expand_start_catch_block): Use correct types for bitwise
+	copy.
+
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/cp/except.c gcc-4.1.1/gcc/cp/except.c
--- gcc-4.1.1.orig/gcc/cp/except.c	2006-02-18 08:37:34.000000000 +0000
+++ gcc-4.1.1/gcc/cp/except.c	2006-08-10 09:56:05.000000000 +0100
@@ -4,6 +4,7 @@    Copyright (C) 1989, 1992, 1993, 1994,
    Contributed by Michael Tiemann <tiemann@cygnus.com>
    Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
    initial re-implementation courtesy Tad Hunt.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -459,7 +460,14 @@       finish_expr_stmt (do_begin_catch (
   else
     {
       tree init = do_begin_catch ();
-      exp = create_temporary_var (ptr_type_node);
+      tree init_type = type;
+
+      /* Pointers are passed by values, everything else by reference.  */
+      if (!TYPE_PTR_P (type))
+	init_type = build_pointer_type (type);
+      if (init_type != TREE_TYPE (init))
+	init = build1 (NOP_EXPR, init_type, init);
+      exp = create_temporary_var (init_type);
       DECL_REGISTER (exp) = 1;
       cp_finish_decl (exp, init, /*init_const_expr=*/false, 
 		      NULL_TREE, LOOKUP_ONLYCONVERTING);
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/doc/invoke.texi gcc-4.1.1/gcc/doc/invoke.texi
--- gcc-4.1.1.orig/gcc/doc/invoke.texi	2006-02-14 15:08:01.000000000 +0000
+++ gcc-4.1.1/gcc/doc/invoke.texi	2006-08-10 09:56:05.000000000 +0100
@@ -315,7 +315,7 @@ Objective-C and Objective-C++ Dialects}.
 -fno-inline  -fno-math-errno  -fno-peephole  -fno-peephole2 @gol
 -funsafe-math-optimizations  -funsafe-loop-optimizations  -ffinite-math-only @gol
 -fno-trapping-math  -fno-zero-initialized-in-bss @gol
--fomit-frame-pointer  -foptimize-register-move @gol
+-fomit-frame-pointer  -foptimize-register-move -foptimize-related-values @gol
 -foptimize-sibling-calls  -fprefetch-loop-arrays @gol
 -fprofile-generate -fprofile-use @gol
 -fregmove  -frename-registers @gol
@@ -4391,7 +4391,7 @@ also turns on the following optimization
 -fpeephole2 @gol
 -fschedule-insns  -fschedule-insns2 @gol
 -fsched-interblock  -fsched-spec @gol
--fregmove @gol
+-fregmove -foptimize-related-values @gol
 -fstrict-aliasing @gol
 -fdelete-null-pointer-checks @gol
 -freorder-blocks  -freorder-functions @gol
@@ -4855,6 +4855,15 @@ optimization.
 
 Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
 
+@item -foptimize-related-values
+@opindex foptimize-related-values
+For targets with auto-increment addressing modes, attempt to re-arrange
+register + offset calculations and memory acesses in order to reduce
+the overall instruction count and register pressure.
+
+Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}, unless
+-foptimize-register-move is disabled.
+
 @item -fdelayed-branch
 @opindex fdelayed-branch
 If supported for the target machine, attempt to reorder instructions
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/flow.c gcc-4.1.1/gcc/flow.c
--- gcc-4.1.1.orig/gcc/flow.c	2005-12-16 09:02:49.000000000 +0000
+++ gcc-4.1.1/gcc/flow.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Data flow analysis for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -643,7 +644,8 @@ 	      CLEAR_REG_SET (bb->il.rtl->global
 
       /* If asked, remove notes from the blocks we'll update.  */
       if (extent == UPDATE_LIFE_GLOBAL_RM_NOTES)
-	count_or_remove_death_notes (blocks, 1);
+	count_or_remove_death_notes (blocks,
+				     prop_flags & PROP_POST_REGSTACK ? -1 : 1);
     }
 
   /* Clear log links in case we are asked to (re)compute them.  */
@@ -2926,7 +2928,13 @@ 	  else if (! some_was_live)
 	      if (flags & PROP_REG_INFO)
 		REG_N_DEATHS (regno_first) += 1;
 
-	      if (flags & PROP_DEATH_NOTES)
+	      if (flags & PROP_DEATH_NOTES
+#ifdef STACK_REGS
+		  && (!(flags & PROP_POST_REGSTACK)
+		      || !IN_RANGE (REGNO (reg), FIRST_STACK_REG,
+				    LAST_STACK_REG))
+#endif
+		  )
 		{
 		  /* Note that dead stores have already been deleted
 		     when possible.  If we get here, we have found a
@@ -2939,7 +2947,13 @@ 		    = alloc_EXPR_LIST (REG_UNUSED, reg
 	    }
 	  else
 	    {
-	      if (flags & PROP_DEATH_NOTES)
+	      if (flags & PROP_DEATH_NOTES
+#ifdef STACK_REGS
+		  && (!(flags & PROP_POST_REGSTACK)
+		      || !IN_RANGE (REGNO (reg), FIRST_STACK_REG,
+				    LAST_STACK_REG))
+#endif
+		  )
 		{
 		  /* This is a case where we have a multi-word hard register
 		     and some, but not all, of the words of the register are
@@ -2998,7 +3012,12 @@ 	  for (i = regno_first; i <= regno_last
      here and count it.  */
   else if (GET_CODE (reg) == SCRATCH)
     {
-      if (flags & PROP_DEATH_NOTES)
+      if (flags & PROP_DEATH_NOTES
+#ifdef STACK_REGS
+	  && (!(flags & PROP_POST_REGSTACK)
+	      || !IN_RANGE (REGNO (reg), FIRST_STACK_REG, LAST_STACK_REG))
+#endif
+	  )
 	REG_NOTES (insn)
 	  = alloc_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
     }
@@ -3764,6 +3783,10 @@ 	  some_was_live |= REGNO_REG_SET_P (pbi
       if (! some_was_live)
 	{
 	  if ((pbi->flags & PROP_DEATH_NOTES)
+#ifdef STACK_REGS
+	      && (!(pbi->flags & PROP_POST_REGSTACK)
+		  || !IN_RANGE (REGNO (reg), FIRST_STACK_REG, LAST_STACK_REG))
+#endif
 	      && ! find_regno_note (insn, REG_DEAD, regno_first))
 	    REG_NOTES (insn)
 	      = alloc_EXPR_LIST (REG_DEAD, reg, REG_NOTES (insn));
@@ -4415,7 +4438,9 @@ struct tree_opt_pass pass_recompute_reg_
 
 /* Optionally removes all the REG_DEAD and REG_UNUSED notes from a set of
    blocks.  If BLOCKS is NULL, assume the universal set.  Returns a count
-   of the number of registers that died.  */
+   of the number of registers that died.
+   If KILL is 1, remove old REG_DEAD / REG_UNUSED notes.  If it is 0, don't.
+   if it is -1, remove them unless they pertain to a stack reg.  */
 
 int
 count_or_remove_death_notes (sbitmap blocks, int kill)
@@ -4487,7 +4512,14 @@ 		        n = hard_regno_nregs[REGNO (re
 		  /* Fall through.  */
 
 		case REG_UNUSED:
-		  if (kill)
+		  if (kill > 0
+		      || (kill
+#ifdef STACK_REGS
+			  && (!REG_P (XEXP (link, 0))
+			      || !IN_RANGE (REGNO (XEXP (link, 0)),
+					    FIRST_STACK_REG, LAST_STACK_REG))
+#endif
+			  ))
 		    {
 		      rtx next = XEXP (link, 1);
 		      free_EXPR_LIST_node (link);
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/fold-const.c gcc-4.1.1/gcc/fold-const.c
--- gcc-4.1.1.orig/gcc/fold-const.c	2006-05-14 05:19:32.000000000 +0100
+++ gcc-4.1.1/gcc/fold-const.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Fold a constant sub-tree into a single node for C-compiler
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
    2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -1817,7 +1818,13 @@   if (REAL_VALUE_ISNAN (r))
   if (! overflow)
     {
       tree lt = TYPE_MIN_VALUE (type);
-      REAL_VALUE_TYPE l = real_value_from_int_cst (NULL_TREE, lt);
+      REAL_VALUE_TYPE l;
+
+      if (TYPE_PRECISION (type) >= 32)
+	l = real_value_from_int_cst (NULL_TREE, lt);
+      else
+	real_from_integer (&l, VOIDmode, (HOST_WIDE_INT) -1 << 31,
+			   (HOST_WIDE_INT) -1, 0);
       if (REAL_VALUES_LESS (r, l))
 	{
 	  overflow = 1;
@@ -1831,7 +1838,14 @@   if (! overflow)
       tree ut = TYPE_MAX_VALUE (type);
       if (ut)
 	{
-	  REAL_VALUE_TYPE u = real_value_from_int_cst (NULL_TREE, ut);
+	  REAL_VALUE_TYPE u;
+
+	  if (TYPE_PRECISION (type) >= 32)
+	    u = real_value_from_int_cst (NULL_TREE, ut);
+	  else
+	    real_from_integer (&u, VOIDmode,
+			       (HOST_WIDE_INT) 32767 << 16 | 65535L,
+			       (HOST_WIDE_INT) 0, 0);
 	  if (REAL_VALUES_LESS (u, r))
 	    {
 	      overflow = 1;
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/gcc.c gcc-4.1.1/gcc/gcc.c
--- gcc-4.1.1.orig/gcc/gcc.c	2006-05-17 19:38:58.000000000 +0100
+++ gcc-4.1.1/gcc/gcc.c	2006-08-10 09:56:05.000000000 +0100
@@ -2,6 +2,7 @@
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
    Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -1994,6 +1995,7 @@ read_specs (const char *filename, int ma
   char *buffer;
   char *p;
 
+  CYGPATH (filename);
   buffer = load_specs (filename);
 
   /* Scan BUFFER for specs, putting them in the vector.  */
@@ -2216,6 +2218,8 @@       if (*suffix == 0)
 
   if (link_command_spec == 0)
     fatal ("spec file has no spec for linking");
+
+  CYGPATH_FREE (filename);
 }
 
 /* Record the names of temporary files we tell compilers to write,
@@ -2454,9 +2458,12 @@ find_a_file (struct path_prefix *pprefix
   const char *const file_suffix =
     ((mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "");
   struct prefix_list *pl;
-  int len = pprefix->max_len + strlen (name) + strlen (file_suffix) + 1;
+  int len;
   const char *multilib_name, *multilib_os_name;
 
+  CYGPATH (name);
+  len = pprefix->max_len + strlen (name) + strlen (file_suffix) + 1;
+  
 #ifdef DEFAULT_ASSEMBLER
   if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0)
     return xstrdup (DEFAULT_ASSEMBLER);
@@ -2495,6 +2502,7 @@   if (IS_ABSOLUTE_PATH (name))
       if (access (name, mode) == 0)
 	{
 	  strcpy (temp, name);
+	  CYGPATH_FREE (name);
 	  return temp;
 	}
     }
@@ -2515,7 +2523,10 @@ 		strcat (temp, machine_suffix);
 		strcat (temp, multilib_name);
 		strcat (temp, file_suffix);
 		if (access_check (temp, mode) == 0)
-		  return temp;
+		  {
+		    CYGPATH_FREE (name);
+		    return temp;
+		  }
 	      }
 
 	    /* Now try just the multilib_name.  */
@@ -2523,7 +2534,10 @@ 	    strcpy (temp, pl->prefix);
 	    strcat (temp, machine_suffix);
 	    strcat (temp, multilib_name);
 	    if (access_check (temp, mode) == 0)
-	      return temp;
+	      {
+		CYGPATH_FREE (name);
+	        return temp;
+	      }
 	  }
 
 	/* Certain prefixes are tried with just the machine type,
@@ -2539,14 +2553,20 @@ 		strcat (temp, just_machine_suffix);
 		strcat (temp, multilib_name);
 		strcat (temp, file_suffix);
 		if (access_check (temp, mode) == 0)
-		  return temp;
+		  {
+		    CYGPATH_FREE (name);
+		    return temp;
+		  }
 	      }
 
 	    strcpy (temp, pl->prefix);
 	    strcat (temp, just_machine_suffix);
 	    strcat (temp, multilib_name);
 	    if (access_check (temp, mode) == 0)
-	      return temp;
+	      {
+		CYGPATH_FREE (name);
+	        return temp;
+	      }
 	  }
 
 	/* Certain prefixes can't be used without the machine suffix
@@ -2561,17 +2581,24 @@ 		strcpy (temp, pl->prefix);
 		strcat (temp, this_name);
 		strcat (temp, file_suffix);
 		if (access_check (temp, mode) == 0)
-		  return temp;
+		  {
+		    CYGPATH_FREE (name);
+		    return temp;
+		  }
 	      }
 
 	    strcpy (temp, pl->prefix);
 	    strcat (temp, this_name);
 	    if (access_check (temp, mode) == 0)
-	      return temp;
+	      {
+		CYGPATH_FREE (name);
+	        return temp;
+	      }
 	  }
       }
 
   free (temp);
+  CYGPATH_FREE (name);
   return 0;
 }
 
@@ -3245,18 +3272,48 @@       fatal ("couldn't run '%s': %s", ne
   /* FIXME: make_relative_prefix doesn't yet work for VMS.  */
   if (!gcc_exec_prefix)
     {
-      gcc_exec_prefix = make_relative_prefix (argv[0], standard_bindir_prefix,
-					      standard_exec_prefix);
-      gcc_libexec_prefix = make_relative_prefix (argv[0],
-						 standard_bindir_prefix,
-						 standard_libexec_prefix);
+      /* argv[0] may be a soft link. In this case it may be correct to ignore it and treat it
+	 as the real thing, or we may have to follow the link and find the real installation.
+	 We decide which to do based on whether we can find the target directory (its name
+	 is in spec_machine) without following the links.
+	 If so then assume ALL the files have been linked. In this case it would be the wrong
+	 thing to try and be clever, because the user may be pasting the installation
+	 together with links. Some simple package managers do do this.  */
+      char *temp;
+      gcc_libexec_prefix = make_relative_prefix_ignore_links (argv[0],
+							      standard_bindir_prefix,
+							      standard_libexec_prefix);
+      if (gcc_libexec_prefix)
+	add_prefix (&exec_prefixes, gcc_libexec_prefix, "GCC",
+		    PREFIX_PRIORITY_LAST, 0, 0);
+      if ((temp = find_a_file (&exec_prefixes, spec_machine, R_OK, 0)) == NULL)
+	{
+	  /* the directory was not found so follow the links and hope that solves the problem. */
+	  gcc_exec_prefix = make_relative_prefix (argv[0], standard_bindir_prefix,
+						  standard_exec_prefix);
+	  gcc_libexec_prefix = make_relative_prefix (argv[0],
+						     standard_bindir_prefix,
+						     standard_libexec_prefix);
+	}
+      else
+	{
+	  /* the directory was found so ignore the links and assume the headers/libraries/programs
+	     are all linked from the same place as required.  */
+	  free(temp);
+	  gcc_exec_prefix = make_relative_prefix_ignore_links (argv[0], standard_bindir_prefix,
+							       standard_exec_prefix);
+	}
+
       if (gcc_exec_prefix)
 	putenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL));
     }
   else
-    gcc_libexec_prefix = make_relative_prefix (gcc_exec_prefix,
-					       standard_exec_prefix,
-					       standard_libexec_prefix);
+    /* Assume the user knew what they were doing when they set GCC_EXEC_PREFIX
+       so ignore any soft links. */
+    gcc_libexec_prefix = make_relative_prefix_ignore_links (gcc_exec_prefix,
+							    standard_exec_prefix,
+							    standard_libexec_prefix);
+
 #else
 #endif
 
@@ -4087,6 +4144,7 @@ 	      if (ch == 'B')
 #ifdef HAVE_TARGET_OBJECT_SUFFIX
 	  argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
 #endif
+	  CYGPATH (argv[i]);
 
 	  if (strcmp (argv[i], "-") != 0 && access (argv[i], F_OK) < 0)
 	    {
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/gthr-generic.c gcc-4.1.1/gcc/gthr-generic.c
--- gcc-4.1.1.orig/gcc/gthr-generic.c	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/gthr-generic.c	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,170 @@
+/* Generic threads supplementary implementation. */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1997, 1999, 2000, 2002, 2006 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+#define __GTHR_WEAK __attribute__ ((weak))
+
+#include "tconfig.h"
+#include "gthr.h"
+
+#ifndef __gthr_generic_h
+#error "Generic thread support package not supported"
+#endif
+
+/* These are stub functions.  When threading is available, a suitable set of definitions should be linked in.  */
+
+/* Return 1 if thread system is active, 0 if not.  */
+int
+__generic_gxx_active_p (void)
+{
+  return 0;
+}
+
+/* The following functions should return zero on success or the error
+   number.  If the operation is not supported, -1 is returned.
+
+   __generic_gxx_once
+   __generic_gxx_key_create
+   __generic_gxx_key_delete
+   __generic_gxx_setspecific
+   __generic_gxx_mutex_lock
+   __generic_gxx_mutex_trylock
+   __generic_gxx_mutex_unlock
+   __generic_gxx_recursive_mutex_lock
+   __generic_gxx_recursive_mutex_trylock
+   __generic_gxx_recursive_mutex_unlock  */
+
+/* FUNC is a function that should be called without parameters.
+   *ONCE has been initialized to __GTHREAD_ONCE_INIT and is otherwise only
+   used in calls to __generic_gxx_once with FUNC as the second parameter.
+   If __generic_gxx_once succeeds, FUNC will have been called exactly once
+   since the initialization of ONCE through any number of calls of
+   __generic_gxx_once with this pair of ONCE and FUNC values.  */
+int
+__generic_gxx_once (__gthread_once_t *once ATTRIBUTE_UNUSED,
+		    void (*func)(void) ATTRIBUTE_UNUSED)
+{
+  return -1;
+}
+
+/* Assign a key to *KEY that can be used in calls to
+   __generic_gxx_setspecific / __generic_gxx_getspecific.
+   If DTOR is nonzero, and at thread exit the value associated with the key
+   is nonzero, DTOR will be called at thread exit with the value associated
+   with the key as its only argument.  */
+int
+__generic_gxx_key_create (__gthread_key_t *key ATTRIBUTE_UNUSED,
+			  void (*dtor)(void *) ATTRIBUTE_UNUSED)
+{
+  return -1;
+}
+
+/* KEY is a key previously allocated by __generic_gxx_key_create.
+   Remove it from the set of keys known for this thread.  */
+int
+__generic_gxx_key_delete (__gthread_key_t key ATTRIBUTE_UNUSED)
+{
+  return -1;
+}
+
+/* Return thread-specific data associated with KEY.  */
+void *
+__generic_gxx_getspecific (__gthread_key_t key ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+/* Set thread-specific data associated with KEY to PTR.  */
+int
+__generic_gxx_setspecific (__gthread_key_t key ATTRIBUTE_UNUSED,
+		      const void *ptr ATTRIBUTE_UNUSED)
+{
+  return -1;
+}
+
+/* Initialize *MUTEX.  */
+void
+__generic_gxx_mutex_init_function (__gthread_mutex_t *mutex ATTRIBUTE_UNUSED)
+{
+}
+
+/* Acquire a lock on *MUTEX.  The behaviour is undefined if a lock on *MUTEX
+   has already been acquired by the same thread.  */
+int
+__generic_gxx_mutex_lock (__gthread_mutex_t *mutex ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+/* Try to acquire a lock on *MUTEX.  If a lock on *MUTEX already exists,
+   return an error code.  */
+int
+__generic_gxx_mutex_trylock (__gthread_mutex_t *mutex ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+/* A lock on *MUTEX has previously been acquired with __generic_gxx_mutex_lock
+   or __generic_gxx_mutex_trylock.  Release the lock.  */
+int
+__generic_gxx_mutex_unlock (__gthread_mutex_t *mutex ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+/* Initialize *MUTEX.  */
+void
+__generic_gxx_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex ATTRIBUTE_UNUSED)
+{
+}
+
+/* Acquire a lock on *MUTEX.  If a lock on *MUTEX has already been acquired by
+   the same thread, succeed.  */
+int
+__generic_gxx_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+/* Try to acquire a lock on *MUTEX.  If a lock on *MUTEX has already been
+   acquired by the same thread, succeed.  If any other lock on *MUTEX
+   already exists, return an error code.  */
+int
+__generic_gxx_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+/* A lock on *MUTEX has previously been acquired with
+   __generic_gxx_recursive_mutex_lock or
+   __generic_gxx_recursive_mutex_trylock.  Release the lock.  */
+int
+__generic_gxx_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/gthr-generic.h gcc-4.1.1/gcc/gthr-generic.h
--- gcc-4.1.1.orig/gcc/gthr-generic.h	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/gthr-generic.h	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,372 @@
+/* Generic threads compatibility routines for libgcc2 and libobjc. */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1997, 1999, 2000, 2002, 2006 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+#ifndef __gthr_generic_h
+#define __gthr_generic_h
+
+#define __GTHREADS 1
+
+#define __GTHREAD_ONCE_INIT 0
+#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
+#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Avoid depedency on specific headers.
+   The general idea is that you dynamically allocate the required data
+   structures, and a void * is used to point to this dynamically allocated
+   data.  If your implementation can put all the required information in
+   the void * itself, that's fine, too, of course.
+   libstdc++ inherits from the mutex types, whcih is why they need to be
+   wrapped up as structs.  */
+typedef void *__gthread_key_t;
+typedef void *__gthread_once_t;
+typedef struct __gthread_mutex_s { void *p; } __gthread_mutex_t;
+typedef struct __gthread_recursive_mutex_s { void *p; } __gthread_recursive_mutex_t;
+
+/* We should always link with at least one definition, so we want strong
+   references.  The stub definitions are weak so that they can be overriden.  */
+#ifndef __GTHR_WEAK
+#define __GTHR_WEAK
+#endif
+
+extern int __generic_gxx_active_p (void) __GTHR_WEAK;
+
+extern int __generic_gxx_once (__gthread_once_t *, void (*)(void)) __GTHR_WEAK;
+
+extern int __generic_gxx_key_create (__gthread_key_t *,
+				     void (*)(void *)) __GTHR_WEAK;
+
+extern int __generic_gxx_key_delete (__gthread_key_t key) __GTHR_WEAK;
+
+extern void *__generic_gxx_getspecific (__gthread_key_t key) __GTHR_WEAK;
+
+extern int __generic_gxx_setspecific (__gthread_key_t, const void *) __GTHR_WEAK;
+
+extern void __generic_gxx_mutex_init_function (__gthread_mutex_t *) __GTHR_WEAK;
+
+extern int __generic_gxx_mutex_lock (__gthread_mutex_t *) __GTHR_WEAK;
+
+extern int __generic_gxx_mutex_trylock (__gthread_mutex_t *) __GTHR_WEAK;
+
+extern int __generic_gxx_mutex_unlock (__gthread_mutex_t *) __GTHR_WEAK;
+
+extern void __generic_gxx_recursive_mutex_init_function (__gthread_recursive_mutex_t *) __GTHR_WEAK;
+
+extern int __generic_gxx_recursive_mutex_lock (__gthread_recursive_mutex_t *) __GTHR_WEAK;
+
+extern int __generic_gxx_recursive_mutex_trylock (__gthread_recursive_mutex_t *) __GTHR_WEAK;
+
+extern int __generic_gxx_recursive_mutex_unlock (__gthread_recursive_mutex_t *) __GTHR_WEAK;
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef _LIBOBJC
+
+extern int __generic_gxx_objc_init_thread_system (void) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_close_thread_system (void) __GTHR_WEAK;
+
+extern objc_thread_t __generic_gxx_objc_thread_detach (void (*)(void *), void *) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_thread_set_priority (int priority) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_thread_get_priority (void) __GTHR_WEAK;
+
+extern void __generic_gxx_objc_thread_yield (void) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_thread_exit (void) __GTHR_WEAK;
+
+extern objc_thread_t __generic_gxx_objc_thread_id (void) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_thread_set_data (void *value) __GTHR_WEAK;
+
+extern void *__generic_gxx_objc_thread_get_data (void) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_mutex_allocate (objc_mutex_t) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_mutex_deallocate (objc_mutex_t) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_mutex_lock (objc_mutex_t) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_mutex_trylock (objc_mutex_t) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_mutex_unlock (objc_mutex_t) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_condition_allocate (objc_condition_t) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_condition_deallocate (objc_condition_t) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_condition_wait (objc_condition_t, objc_mutex_t) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_condition_broadcast (objc_condition_t) __GTHR_WEAK;
+
+extern int __generic_gxx_objc_condition_signal (objc_condition_t) __GTHR_WEAK;
+
+/* Backend initialization functions */
+
+/* Initialize the threads subsystem.  */
+static inline int
+__gthread_objc_init_thread_system (void)
+{
+  return __generic_gxx_objc_init_thread_system ();
+}
+
+/* Close the threads subsystem.  */
+static inline int
+__gthread_objc_close_thread_system (void)
+{
+  return __generic_gxx_objc_close_thread_system ();
+}
+
+/* Backend thread functions */
+
+/* Create a new thread of execution.  */
+static inline objc_thread_t
+__gthread_objc_thread_detach (void (* func)(void *), void * arg)
+{
+  return __generic_gxx_objc_thread_detach (func, arg);
+}
+
+/* Set the current thread's priority.  */
+static inline int
+__gthread_objc_thread_set_priority (int priority)
+{
+  return __generic_gxx_objc_thread_set_priority (priority);
+}
+
+/* Return the current thread's priority.  */
+static inline int
+__gthread_objc_thread_get_priority (void)
+{
+  return __generic_gxx_objc_thread_get_priority ();
+}
+
+/* Yield our process time to another thread.  */
+static inline void
+__gthread_objc_thread_yield (void)
+{
+  __generic_gxx_objc_thread_yield ();
+}
+
+/* Terminate the current thread.  */
+static inline int
+__gthread_objc_thread_exit (void)
+{
+  return __generic_gxx_objc_thread_exit ();
+}
+
+/* Returns an integer value which uniquely describes a thread.  */
+static inline objc_thread_t
+__gthread_objc_thread_id (void)
+{
+  return __generic_gxx_objc_thread_id ();
+}
+
+/* Sets the thread's local storage pointer.  */
+static inline int
+__gthread_objc_thread_set_data (void *value)
+{
+  return __generic_gxx_objc_thread_set_data (value);
+}
+
+/* Returns the thread's local storage pointer.  */
+static inline void *
+__gthread_objc_thread_get_data (void)
+{
+  return __generic_gxx_objc_thread_get_data ();
+}
+
+/* Backend mutex functions */
+
+/* Allocate a mutex.  */
+static inline int
+__gthread_objc_mutex_allocate (objc_mutex_t mutex)
+{
+  return __generic_gxx_objc_mutex_allocate (mutex);
+}
+
+/* Deallocate a mutex.  */
+static inline int
+__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
+{
+  return __generic_gxx_objc_mutex_deallocate (mutex);
+}
+
+/* Grab a lock on a mutex.  */
+static inline int
+__gthread_objc_mutex_lock (objc_mutex_t mutex)
+{
+  return __generic_gxx_objc_mutex_lock (mutex);
+}
+
+/* Try to grab a lock on a mutex.  */
+static inline int
+__gthread_objc_mutex_trylock (objc_mutex_t mutex)
+{
+  return __generic_gxx_objc_mutex_trylock (mutex);
+}
+
+/* Unlock the mutex */
+static inline int
+__gthread_objc_mutex_unlock (objc_mutex_t mutex)
+{
+  return __generic_gxx_objc_mutex_unlock (mutex);
+}
+
+/* Backend condition mutex functions */
+
+/* Allocate a condition.  */
+static inline int
+__gthread_objc_condition_allocate (objc_condition_t condition)
+{
+  return __generic_gxx_objc_condition_allocate (condition);
+}
+
+/* Deallocate a condition.  */
+static inline int
+__gthread_objc_condition_deallocate (objc_condition_t condition)
+{
+  return __generic_gxx_objc_condition_deallocate (condition);
+}
+
+/* Wait on the condition */
+static inline int
+__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
+{
+  return __generic_gxx_objc_condition_wait (condition, mutex);
+}
+
+/* Wake up all threads waiting on this condition.  */
+static inline int
+__gthread_objc_condition_broadcast (objc_condition_t condition)
+{
+  return __generic_gxx_objc_condition_broadcast ( condition);
+}
+
+/* Wake up one thread waiting on this condition.  */
+static inline int
+__gthread_objc_condition_signal (objc_condition_t condition)
+{
+  return __generic_gxx_objc_condition_signal (condition);
+}
+
+#else /* !_LIBOBJC */
+
+static inline int
+__gthread_active_p (void)
+{
+  return __generic_gxx_active_p ();
+}
+
+static inline int
+__gthread_once (__gthread_once_t *once, void (*func)(void))
+{
+  return __generic_gxx_once (once, func);
+}
+
+static inline int
+__gthread_key_create (__gthread_key_t *key, void (*dtor)(void *))
+{
+  return __generic_gxx_key_create (key, dtor);
+}
+
+static inline int
+__gthread_key_delete (__gthread_key_t key)
+{
+  return __generic_gxx_key_delete (key);
+}
+
+static inline void *
+__gthread_getspecific (__gthread_key_t key)
+{
+  return __generic_gxx_getspecific (key);
+}
+
+static inline int
+__gthread_setspecific (__gthread_key_t key, const void *ptr)
+{
+  return __generic_gxx_setspecific (key, ptr);
+}
+
+static inline void
+__gthread_mutex_init_function (__gthread_mutex_t *mutex)
+{
+  __generic_gxx_mutex_init_function (mutex);
+}
+
+static inline int
+__gthread_mutex_lock (__gthread_mutex_t * mutex)
+{
+  return __generic_gxx_mutex_lock (mutex);
+}
+
+static inline int
+__gthread_mutex_trylock (__gthread_mutex_t * mutex)
+{
+  return __generic_gxx_mutex_trylock (mutex);
+}
+
+static inline int
+__gthread_mutex_unlock (__gthread_mutex_t * mutex)
+{
+  return __generic_gxx_mutex_unlock (mutex);
+}
+
+static inline void
+__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
+{
+  __generic_gxx_recursive_mutex_init_function (mutex);
+}
+
+static inline int
+__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t * mutex)
+{
+  return __generic_gxx_recursive_mutex_lock (mutex);
+}
+
+static inline int
+__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t * mutex)
+{
+  return __generic_gxx_recursive_mutex_trylock (mutex);
+}
+
+static inline int
+__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t * mutex)
+{
+  return __generic_gxx_recursive_mutex_unlock (mutex);
+}
+
+#endif /* _LIBOBJC */
+
+#endif /* __gthr_generic_h */
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/gthr-objc-generic.c gcc-4.1.1/gcc/gthr-objc-generic.c
--- gcc-4.1.1.orig/gcc/gthr-objc-generic.c	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/gthr-objc-generic.c	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,221 @@
+/* Threads compatibility routines for libobjc.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1997, 1999, 2000, 2006 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+#include "tconfig.h"
+
+#define __GTHR_WEAK __attribute__ ((weak))
+#define _LIBOBJC
+
+/* ??? The objc thread types are defined in ../libobjc/objc/thr.h,
+   but we don't want the gcc core to depend on libobjc.  */
+typedef void * objc_thread_t;
+typedef struct objc_mutex *objc_mutex_t;
+typedef struct objc_condition *objc_condition_t;
+#define OBJC_THREAD_INTERACTIVE_PRIORITY        2
+
+#include "gthr.h"
+
+#define UNUSED(x) x ATTRIBUTE_UNUSED
+
+/* Just provide compatibility for mutex handling.  */
+
+/* Thread local storage for a single thread */
+static void *thread_local_storage = 0;
+
+/* Backend initialization functions */
+
+/* Initialize the threads subsystem.  */
+int
+__generic_gxx_objc_init_thread_system (void)
+{
+  /* No thread support available */
+  return -1;
+}
+
+/* Close the threads subsystem.  */
+int
+__generic_gxx_objc_close_thread_system (void)
+{
+  /* No thread support available */
+  return -1;
+}
+
+/* Backend thread functions */
+
+/* Create a new thread of execution.  The thread starts executing by calling
+   FUNC with ARG as its only argument.
+   On success, a handle for the new thread is returned.
+   On failure, zero is returned.  */
+objc_thread_t
+__generic_gxx_objc_thread_detach (void UNUSED ((* func)(void *)),
+				  void * UNUSED(arg))
+{
+  /* No thread support available */
+  return 0;
+}
+
+/* Set the current thread's priority.  */
+int
+__generic_gxx_objc_thread_set_priority (int UNUSED(priority))
+{
+  /* No thread support available */
+  return -1;
+}
+
+/* Return the current thread's priority.  */
+int
+__generic_gxx_objc_thread_get_priority (void)
+{
+  return OBJC_THREAD_INTERACTIVE_PRIORITY;
+}
+
+/* Yield our process time to another thread.  */
+void
+__generic_gxx_objc_thread_yield (void)
+{
+  return;
+}
+
+/* Terminate the current thread.  */
+int
+__generic_gxx_objc_thread_exit (void)
+{
+  /* No thread support available */
+  /* Should we really exit the program */
+  /* exit (&__objc_thread_exit_status); */
+  return -1;
+}
+
+/* Returns an integer value which uniquely describes a thread.  */
+objc_thread_t
+__generic_gxx_objc_thread_id (void)
+{
+  /* No thread support, use 1.  */
+  return (objc_thread_t) 1;
+}
+
+/* Sets the thread's objc local storage pointer.  */
+int
+__generic_gxx_objc_thread_set_data (void *value)
+{
+  thread_local_storage = value;
+  return 0;
+}
+
+/* Returns the thread's objc local storage pointer.  */
+void *
+__generic_gxx_objc_thread_get_data (void)
+{
+  return thread_local_storage;
+}
+
+/* Backend mutex functions */
+
+/* Allocate a backend-specific mutex data in MUTEX->backend.  
+   Return 0 on success, -1 for failure.  */
+int
+__generic_gxx_objc_mutex_allocate (objc_mutex_t UNUSED(mutex))
+{
+  return 0;
+}
+
+/* Deallocate backend-specific mutex data in MUTEX->backend.
+   Return 0 on success, -1 for failure.  */
+int
+__generic_gxx_objc_mutex_deallocate (objc_mutex_t UNUSED(mutex))
+{
+  return 0;
+}
+
+/* Grab a lock on MUTEX.  Return 0 on success.  */
+int
+__generic_gxx_objc_mutex_lock (objc_mutex_t UNUSED(mutex))
+{
+  /* There can only be one thread, so we always get the lock */
+  return 0;
+}
+
+/* Try to grab a lock on MUTEX.  Return 0 on success.  */
+int
+__generic_gxx_objc_mutex_trylock (objc_mutex_t UNUSED(mutex))
+{
+  /* There can only be one thread, so we always get the lock */
+  return 0;
+}
+
+/* Unlock MUTEX.  Return 0 on success.  */
+int
+__generic_gxx_objc_mutex_unlock (objc_mutex_t UNUSED(mutex))
+{
+  return 0;
+}
+
+/* Backend condition mutex functions */
+
+/* Allocate backend-specific condition data in CONDITION->backend.
+   Return 0 on success, -1 for failure.  */
+int
+__generic_gxx_objc_condition_allocate (objc_condition_t UNUSED(condition))
+{
+  return 0;
+}
+
+/* Deallocate backend-specific condition data in CONDITION->backend.
+   Return 0 for success.  */
+int
+__generic_gxx_objc_condition_deallocate (objc_condition_t UNUSED(condition))
+{
+  return 0;
+}
+
+/* MUTEX is a locked mutex.  Atomically release MUTEX and wait on
+   CONDITION, i.e. so that no other thread can observe a state after
+   the release of MUTEX but before this thread has blocked.
+   Then re-acquire a lock on MUTEX.
+   Return 0 on success.  */
+int
+__generic_gxx_objc_condition_wait (objc_condition_t UNUSED(condition),
+				   objc_mutex_t UNUSED(mutex))
+{
+  return 0;
+}
+
+/* Wake up all threads waiting on CONDITION.  Return 0 on success.  */
+int
+__generic_gxx_objc_condition_broadcast (objc_condition_t UNUSED(condition))
+{
+  return 0;
+}
+
+/* Wake up one thread waiting on CONDITION.  Return 0 on success.  */
+int
+__generic_gxx_objc_condition_signal (objc_condition_t UNUSED(condition))
+{
+  return 0;
+}
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/longlong.h gcc-4.1.1/gcc/longlong.h
--- gcc-4.1.1.orig/gcc/longlong.h	2005-12-06 10:02:57.000000000 +0000
+++ gcc-4.1.1/gcc/longlong.h	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
    Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2004,
    2005  Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
    This definition file is free software; you can redistribute it
    and/or modify it under the terms of the GNU General Public
@@ -831,18 +832,51 @@ 	(count) += 16;							\
   } while (0)
 #endif
 
-#if defined (__sh2__) && W_TYPE_SIZE == 32
+#if defined(__sh__) && !__SHMEDIA__ && W_TYPE_SIZE == 32
+#ifndef __sh1__
 #define umul_ppmm(w1, w0, u, v) \
   __asm__ (								\
-       "dmulu.l	%2,%3\n\tsts	macl,%1\n\tsts	mach,%0"		\
-	   : "=r" ((USItype)(w1)),					\
-	     "=r" ((USItype)(w0))					\
+       "dmulu.l	%2,%3\n\tsts%M1	macl,%1\n\tsts%M0	mach,%0"	\
+	   : "=r<" ((USItype)(w1)),					\
+	     "=r<" ((USItype)(w0))					\
 	   : "r" ((USItype)(u)),					\
 	     "r" ((USItype)(v))						\
 	   : "macl", "mach")
 #define UMUL_TIME 5
 #endif
 
+/* This is the same algorithm as __udiv_qrnnd_c.  */
+#define UDIV_NEEDS_NORMALIZATION 1
+
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do {									\
+    extern UWtype __udiv_qrnnd_16 (UWtype, UWtype)			\
+                        __attribute__ ((visibility ("hidden")));	\
+    /* r0: rn r1: qn */ /* r0: n1 r4: n0 r5: d r6: d1 */ /* r2: __m */	\
+    __asm__ (								\
+	"mov%M4 %4,r5\n"						\
+"	swap.w %3,r4\n"							\
+"	swap.w r5,r6\n"							\
+"	jsr @%5\n"							\
+"	shll16 r6\n"							\
+"	swap.w r4,r4\n"							\
+"	jsr @%5\n"							\
+"	swap.w r1,%0\n"							\
+"	or r1,%0"							\
+	: "=r" (q), "=&z" (r)						\
+	: "1" (n1), "r" (n0), "rm" (d), "r" (&__udiv_qrnnd_16)		\
+	: "r1", "r2", "r4", "r5", "r6", "pr");				\
+  } while (0)
+
+#define UDIV_TIME 80
+
+#define sub_ddmmss(sh, sl, ah, al, bh, bl)				\
+  __asm__ ("clrt;subc %5,%1; subc %4,%0"				\
+	   : "=r" (sh), "=r" (sl)					\
+	   : "0" (ah), "1" (al), "r" (bh), "r" (bl))
+
+#endif /* __sh__ */
+
 #if defined (__SH5__) && __SHMEDIA__ && W_TYPE_SIZE == 32
 #define __umulsidi3(u,v) ((UDItype)(USItype)u*(USItype)v)
 #define count_leading_zeros(count, x) \
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/Makefile.in gcc-4.1.1/gcc/Makefile.in
--- gcc-4.1.1.orig/gcc/Makefile.in	2006-05-17 19:38:58.000000000 +0100
+++ gcc-4.1.1/gcc/Makefile.in	2006-08-10 09:56:05.000000000 +0100
@@ -3,6 +3,7 @@
 
 # Copyright (C) 1987, 1988, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
 # 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+# Copyright (c) 2006  STMicroelectronics.
 
 #This file is part of GCC.
 
@@ -606,7 +607,7 @@ LIB2FUNCS_STATIC_EXTRA =
 LIBCONVERT =
 
 # Control whether header files are installed.
-INSTALL_HEADERS=install-headers install-mkheaders
+INSTALL_HEADERS=install-headers #broken: install-mkheaders
 
 # Control whether Info documentation is built and installed.
 BUILD_INFO = @BUILD_INFO@
@@ -978,7 +979,7 @@ OBJS-common = \
  reload.o reload1.o reorg.o resource.o rtl.o rtlanal.o rtl-error.o	   \
  sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.o	   \
  simplify-rtx.o sreal.o stmt.o stor-layout.o stringpool.o		   \
- targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o		   \
+ struct-equiv.o targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o \
  varasm.o varray.o vec.o version.o vmsdbgout.o xcoffout.o alloc-pool.o	   \
  et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o	   \
  tree-profile.o rtlhooks.o cfgexpand.o lambda-mat.o    			   \
@@ -1317,7 +1318,7 @@ 	  cat $(srcdir)/glimits.h > tmp-xlimits
 #
 # Build libgcc.a.
 
-LIB2ADD = $(LIB2FUNCS_EXTRA)
+LIB2ADD = $(LIB2FUNCS_EXTRA) @extra_libgcc_srcs@
 LIB2ADD_ST = $(LIB2FUNCS_STATIC_EXTRA)
 
 libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) $(LIB2ADD_ST) specs \
@@ -1681,6 +1682,8 @@ options.o: options.c $(CONFIG_H) $(SYSTE
 
 dumpvers: dumpvers.c
 
+version.o: $(OBJS:version.o=)
+
 version.o: version.c version.h $(DATESTAMP) $(BASEVER) $(DEVPHASE)
 	$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \
 	-DBASEVER=$(BASEVER_s) -DDATESTAMP=$(DATESTAMP_s) \
@@ -2317,6 +2320,10 @@    $(OBSTACK_H) toplev.h $(TREE_FLOW_H) 
 cfgloopanal.o : cfgloopanal.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
    $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) \
    $(OBSTACK_H) output.h
+struct-equiv.o : struct-equiv.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(RTL_H) hard-reg-set.h output.h $(FLAGS_H) $(RECOG_H) \
+   insn-config.h $(TARGET_H) $(TM_P_H) $(PARAMS_H) \
+   $(REGS_H) $(EMIT_RTL_H)
 loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \
    hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) \
    output.h intl.h
@@ -2402,7 +2409,8 @@    $(SPLAY_TREE_H) $(VARRAY_H) $(IPA_TYP
 regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    insn-config.h timevar.h tree-pass.h \
    $(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) function.h \
-   $(EXPR_H) $(BASIC_BLOCK_H) toplev.h $(TM_P_H) except.h reload.h
+   $(EXPR_H) $(BASIC_BLOCK_H) toplev.h $(TM_P_H) except.h reload.h \
+   $(OPTABS_H) gt-regmove.h
 ddg.o : ddg.c $(DDG_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) \
    toplev.h $(RTL_H) $(TM_P_H) $(REGS_H) function.h \
    $(FLAGS_H) insn-config.h $(INSN_ATTR_H) except.h $(RECOG_H) \
@@ -2757,7 +2765,7 @@   $(srcdir)/tree-dfa.c $(srcdir)/tree-ss
   $(srcdir)/tree-iterator.c $(srcdir)/gimplify.c \
   $(srcdir)/tree-chrec.h $(srcdir)/tree-vect-generic.c \
   $(srcdir)/tree-ssa-operands.h $(srcdir)/tree-ssa-operands.c \
-  $(srcdir)/tree-profile.c $(srcdir)/tree-nested.c \
+  $(srcdir)/tree-profile.c $(srcdir)/tree-nested.c $(srcdir)/regmove.c \
   $(srcdir)/ipa-reference.c $(srcdir)/tree-ssa-structalias.h \
   $(srcdir)/tree-ssa-structalias.c \
   $(srcdir)/targhooks.c $(out_file) \
@@ -2775,7 +2783,7 @@ gt-lists.h gt-alias.h gt-cselib.h gt-gcs
 gt-expr.h gt-sdbout.h gt-optabs.h gt-bitmap.h gt-dojump.h \
 gt-dwarf2out.h gt-reg-stack.h gt-dwarf2asm.h \
 gt-dbxout.h gt-c-common.h gt-c-decl.h gt-c-parser.h \
-gt-c-pragma.h gtype-c.h gt-cfglayout.h \
+gt-c-pragma.h gtype-c.h gt-cfglayout.h gt-regmove.h \
 gt-tree-mudflap.h gt-tree-vect-generic.h \
 gt-tree-profile.h gt-tree-ssa-address.h \
 gt-tree-ssanames.h gt-tree-iterator.h gt-gimplify.h \
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/optabs.c gcc-4.1.1/gcc/optabs.c
--- gcc-4.1.1.orig/gcc/optabs.c	2006-01-31 21:59:53.000000000 +0000
+++ gcc-4.1.1/gcc/optabs.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Expand the basic unary and binary arithmetic operations, for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -4107,19 +4108,41 @@ rtx
 gen_add3_insn (rtx r0, rtx r1, rtx c)
 {
   int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code;
+  int mcode;
+  rtx s;
 
   if (icode == CODE_FOR_nothing
       || !(insn_data[icode].operand[0].predicate
-	   (r0, insn_data[icode].operand[0].mode))
-      || !(insn_data[icode].operand[1].predicate
+	   (r0, insn_data[icode].operand[0].mode)))
+    return NULL_RTX;
+
+  if ((insn_data[icode].operand[1].predicate
 	   (r1, insn_data[icode].operand[1].mode))
-      || !(insn_data[icode].operand[2].predicate
+      && (insn_data[icode].operand[2].predicate
 	   (c, insn_data[icode].operand[2].mode)))
+    return GEN_FCN (icode) (r0, r1, c);
+  
+  mcode = (int) mov_optab->handlers[(int) GET_MODE (r0)].insn_code;
+  if (REGNO (r0) == REGNO (r1)
+      || !(insn_data[icode].operand[1].predicate
+	   (r0, insn_data[icode].operand[1].mode))
+      || !(insn_data[icode].operand[2].predicate
+	   (r1, insn_data[icode].operand[2].mode))
+      || !(insn_data[mcode].operand[0].predicate
+	   (r0, insn_data[mcode].operand[0].mode))
+      || !(insn_data[mcode].operand[1].predicate
+	   (c, insn_data[mcode].operand[1].mode)))
     return NULL_RTX;
 
-  return GEN_FCN (icode) (r0, r1, c);
+  start_sequence ();
+  emit_insn (GEN_FCN (mcode) (r0, c));
+  emit_insn (GEN_FCN (icode) (r0, r0, r1));
+  s = get_insns ();
+  end_sequence ();
+  return s;
 }
 
+
 int
 have_add2_insn (rtx x, rtx y)
 {
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/opts.c gcc-4.1.1/gcc/opts.c
--- gcc-4.1.1.orig/gcc/opts.c	2006-05-17 19:38:58.000000000 +0100
+++ gcc-4.1.1/gcc/opts.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Command line option handling.
    Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Neil Booth.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -569,6 +570,7 @@   if (optimize >= 2)
       flag_schedule_insns_after_reload = 1;
 #endif
       flag_regmove = 1;
+      flag_optimize_related_values = 1;
       flag_strict_aliasing = 1;
       flag_delete_null_pointer_checks = 1;
       flag_reorder_blocks = 1;
@@ -779,6 +781,7 @@       set_Wunused (value);
 
     case OPT_aux_info:
     case OPT_aux_info_:
+      CYGPATH (arg);
       aux_info_file_name = arg;
       flag_gen_aux_info = 1;
       break;
@@ -801,6 +804,7 @@       decode_d_option (arg);
       break;
 
     case OPT_dumpbase:
+      CYGPATH (arg);
       dump_base_name = arg;
       break;
 
@@ -1047,6 +1051,7 @@       set_debug_level (XCOFF_DEBUG, code
       break;
 
     case OPT_o:
+      CYGPATH (arg);
       asm_file_name = arg;
       break;
 
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/postreload.c gcc-4.1.1/gcc/postreload.c
--- gcc-4.1.1.orig/gcc/postreload.c	2005-11-18 13:14:39.000000000 +0000
+++ gcc-4.1.1/gcc/postreload.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Perform simple optimizations to clean up the result of reload.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -889,6 +890,23 @@ 	      if (apply_change_group ())
 		{
 		  rtx *np;
 
+		  /* For every new use of REG_SUM, we have to record the use
+		     of BASE therein.  */
+		  for (i = reg_state[regno].use_index;
+		       i < RELOAD_COMBINE_MAX_USES; i++)
+		    {
+		      rtx *basep = &XEXP (*reg_state[regno].reg_use[i].usep, 1);
+		      rtx use_insn = reg_state[regno].reg_use[i].insn;
+
+		      if (*basep != base)
+			abort ();
+		      reload_combine_note_use (basep, use_insn);
+		    }
+		  if (reg_state[REGNO (base)].use_ruid
+		      > reg_state[regno].use_ruid)
+		    reg_state[REGNO (base)].use_ruid
+		      = reg_state[regno].use_ruid;
+
 		  /* Delete the reg-reg addition.  */
 		  delete_insn (insn);
 
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/prefix.c gcc-4.1.1/gcc/prefix.c
--- gcc-4.1.1.orig/gcc/prefix.c	2005-06-25 03:02:01.000000000 +0100
+++ gcc-4.1.1/gcc/prefix.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Utility to update paths from internal to external forms.
    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -252,6 +253,8 @@ update_path (const char *path, const cha
   char *result, *p;
   const int len = strlen (std_prefix);
 
+  CYGPATH (path);
+  
   if (! strncmp (path, std_prefix, len)
       && (IS_DIR_SEPARATOR(path[len])
           || path[len] == '\0')
@@ -346,6 +349,8 @@   if (DIR_SEPARATOR != '/')
     tr (result, '/', DIR_SEPARATOR);
 #endif
 
+  CYGPATH_FREE (path);
+  
   return result;
 }
 
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/recog.c gcc-4.1.1/gcc/recog.c
--- gcc-4.1.1.orig/gcc/recog.c	2005-12-21 14:56:00.000000000 +0000
+++ gcc-4.1.1/gcc/recog.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Subroutines used by or related to instruction recognition.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
    1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -339,7 +340,7 @@ num_changes_pending (void)
 /* Tentatively apply the changes numbered NUM and up.
    Return 1 if all changes are valid, zero otherwise.  */
 
-static int
+int
 verify_changes (int num)
 {
   int i;
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/recog.h gcc-4.1.1/gcc/recog.h
--- gcc-4.1.1.orig/gcc/recog.h	2005-08-27 03:08:29.000000000 +0100
+++ gcc-4.1.1/gcc/recog.h	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Declarations for interface to insn recognizer and insn-output.c.
    Copyright (C) 1987, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
    Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -76,6 +77,7 @@ extern int asm_operand_ok (rtx, const ch
 extern int validate_change (rtx, rtx *, rtx, int);
 extern int validate_change_maybe_volatile (rtx, rtx *, rtx);
 extern int insn_invalid_p (rtx);
+extern int verify_changes (int);
 extern void confirm_change_group (void);
 extern int apply_change_group (void);
 extern int num_validated_changes (void);
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/regmove.c gcc-4.1.1/gcc/regmove.c
--- gcc-4.1.1.orig/gcc/regmove.c	2005-08-25 07:44:09.000000000 +0100
+++ gcc-4.1.1/gcc/regmove.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Move registers around to reduce number of move instructions needed.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -43,6 +44,9 @@ Software Foundation, 51 Franklin Street,
 #include "except.h"
 #include "toplev.h"
 #include "reload.h"
+#include "obstack.h"
+#include "ggc.h"
+#include "optabs.h"
 #include "timevar.h"
 #include "tree-pass.h"
 
@@ -54,6 +58,13 @@ Software Foundation, 51 Franklin Street,
 #else
 #define STACK_GROWS_DOWNWARD 0
 #endif
+/* Likewise for AUTO_INC_DEC.  */
+#ifdef AUTO_INC_DEC
+#undef AUTO_INC_DEC
+#define AUTO_INC_DEC 1
+#else
+#define AUTO_INC_DEC 0
+#endif
 
 static int perhaps_ends_bb_p (rtx);
 static int optimize_reg_copy_1 (rtx, rtx, rtx);
@@ -83,6 +94,37 @@ static int regclass_compatible_p (int, i
 static int replacement_quality (rtx);
 static int fixup_match_2 (rtx, rtx, rtx, rtx, FILE *);
 
+struct related;
+struct rel_use_chain;
+struct rel_mod;
+struct rel_use;
+
+static struct rel_use *lookup_related (int, enum reg_class, HOST_WIDE_INT, int);
+static void rel_build_chain (struct rel_use *, struct rel_use *,
+			     struct related *);
+static int recognize_related_for_insn (rtx, int, int);
+static void record_reg_use (rtx *, rtx, int, int);
+static struct rel_use *create_rel_use (rtx, rtx *, int, int, int);
+static void new_reg_use (rtx, rtx *, int, int, int, int);
+static void rel_record_mem (rtx *, rtx, int, int, int, rtx, int, int);
+static void new_base (rtx, rtx, int, int);
+static void invalidate_related (rtx, rtx, int, int);
+static void find_related (rtx *, rtx, int, int);
+static void find_related_toplev (rtx, int, int);
+static int chain_starts_earlier (const void *, const void *);
+static int chain_ends_later (const void *, const void *);
+static int mod_before (const void *, const void *);
+static void remove_setting_insns (struct related *, rtx);
+static rtx perform_addition (struct rel_mod *, struct rel_use *, rtx,
+			     struct rel_use_chain *);
+static void modify_address (struct rel_mod *, struct rel_use *, HOST_WIDE_INT);
+static void optimize_related_values_1 (struct related *, int, int, rtx, FILE *);
+static void optimize_related_values_0 (struct related *, int, int, rtx, FILE *);
+static void optimize_related_values (int, FILE *);
+static void count_sets (rtx, rtx, void *);
+static int link_chains (struct rel_use_chain *, struct rel_use_chain *,
+			enum machine_mode);
+
 /* Return nonzero if registers with CLASS1 and CLASS2 can be merged without
    causing too much register allocation problems.  */
 static int
@@ -173,6 +215,8 @@   tmp = gen_add3_insn (tmp, tmp, const2_
 
   /* If we get something that isn't a simple set, or a
      [(set ..) (clobber ..)], this whole function will go wrong.  */
+  if (GET_CODE (tmp) == INSN)
+    tmp = PATTERN (tmp);
   if (GET_CODE (tmp) == SET)
     return NULL_RTX;
   else if (GET_CODE (tmp) == PARALLEL)
@@ -323,6 +367,1877 @@       && reg_overlap_mentioned_p (x, fla
     flags_set_1_set = 1;
 }
 
+static GTY (()) rtx test_addr;
+
+/* Some machines have two-address-adds and instructions that can
+   use only register-indirect addressing and auto_increment, but no
+   offsets.  If multiple fields of a struct are accessed more than
+   once, cse will load each of the member addresses in separate registers.
+   This not only costs a lot of registers, but also of instructions,
+   since each add to initialize an address register must be really expanded
+   into a register-register move followed by an add.
+   regmove_optimize uses some heuristics to detect this case; if these
+   indicate that this is likely, optimize_related_values is run once for
+   the entire function.
+
+   We build chains of uses of related values that can be satisfied with the
+   same base register by taking advantage of auto-increment address modes
+   instead of explicit add instructions.
+
+   We try to link chains with disjoint lifetimes together to reduce the
+   number of temporary registers and register-register copies.
+
+   This optimization pass operates on basic blocks one at a time; it could be
+   extended to work on extended basic blocks or entire functions.  */
+
+/* For each set of values related to a common base register, we use a
+   hash table which maps constant offsets to instructions.
+
+   The instructions mapped to are those that use a register which may,
+   (possibly with a change in addressing mode) differ from the initial
+   value of the base register by exactly that offset after the
+   execution of the instruction.
+   Here we define the size of the hash table, and the hash function to use.  */
+#define REL_USE_HASH_SIZE 43
+#define REL_USE_HASH(I) ((I) % (unsigned HOST_WIDE_INT) REL_USE_HASH_SIZE)
+
+/* For each register in a set of registers that are related, we keep a
+   struct related.
+
+   BASE points to the struct related of the base register (i.e. the one
+   that was the source of the first three-address add for this set of
+   related values).
+
+   INSN is the instruction that initialized the register, or, for the
+   base, the instruction that initialized the first non-base register.
+
+   BASE is the register number of the base register.
+
+   For the base register only, the member BASEINFO points to some extra data.
+
+   'luid' here means linear uid.  We count them starting at the function
+   start; they are used to avoid overlapping lifetimes.
+
+   UPDATES is a list of instructions that set the register to a new
+   value that is still related to the same base.
+
+   When a register in a set of related values is set to something that
+   is not related to the base, INVALIDATE_LUID is set to the luid of
+   the instruction that does this set.  This is used to avoid re-using
+   this register in an overlapping liftime for a related value.
+
+   DEATH is first used to store the insn (if any) where the register dies.
+   When the optimization is actually performed, the REG_DEAD note from
+   the insn denoted by DEATH is removed.
+   Thereafter, the removed death note is stored in DEATH, marking not
+   only that the register dies, but also making the note available for reuse.
+
+   We also use a struct related to keep track of registers that have been
+   used for anything that we don't recognize as related values.
+   The only really interesting datum for these is u.last_luid, which is
+   the luid of the last reference we have seen.  These struct relateds
+   are marked by a zero INSN field; most other members are not used and
+   remain uninitialized.  */
+
+struct related
+{
+  rtx insn;
+  rtx reg;
+  struct related *base;
+  HOST_WIDE_INT offset;
+  struct related *prev;
+  struct update *updates;
+  struct related_baseinfo *baseinfo;
+  int invalidate_luid;
+  rtx death;
+  int reg_orig_calls_crossed;
+  int reg_set_call_tally;
+};
+
+/* HASHTAB maps offsets to register uses with a matching MATCH_OFFSET.
+   PREV_BASE points to the struct related for the previous base register
+   that we currently keep track of.
+   INSN_LUID is the luid of the instruction that started this set of
+   related values.  */
+struct related_baseinfo
+{
+  struct rel_use *hashtab[REL_USE_HASH_SIZE];
+  struct rel_use_chain *chains;
+  struct related *prev_base;
+  int insn_luid;
+};
+
+/* INSN is an instruction that sets a register that previously contained
+   a related value to a new value that is related to the same base register.
+   When the optimization is performed, we have to delete INSN.
+   DEATH_INSN points to the insn (if any) where the register died that we
+   set in INSN.  When we perform the optimization, the REG_DEAD note has
+   to be removed from DEATH_INSN.
+   PREV points to the struct update that pertains to the previous
+   instruction pertaining to the same register that set it from one
+   related value to another one.  */
+struct update
+{
+  rtx insn;
+  rtx death_insn;
+  struct update *prev;
+};
+
+struct rel_use_chain
+{
+  /* Points to first use in this chain.  */
+  struct rel_use *uses;
+  struct rel_use_chain *prev;
+  struct rel_use_chain *linked;
+  /* The following fields are only set after the chain has been completed:  */
+  /* Last use in this chain.  */
+  struct rel_use *end;
+  int start_luid;
+  int end_luid;
+  int calls_crossed;
+  /* The register allocated for this chain.  */
+  rtx reg;
+  /* The death note for this register.  */
+  rtx death_note;
+  /* Offset after execution of last insn.  */
+  HOST_WIDE_INT match_offset;
+};
+
+/* ADDRP points to the place where the actual use of the related value is.
+   This is commonly a memory address, and has to be set to a register
+   or some auto_inc addressing of this register.
+   But ADDRP is also used for all other uses of related values to
+   the place where the register is inserted; we can tell that an
+   unardorned register is to be inserted because no offset adjustment
+   is required, hence this is handled by the same logic as register-indirect
+   addressing.  The only exception to this is when SET_IN_PARALLEL is set,
+   see below.
+
+   OFFSET is the offset that is actually used in this instance, i.e.
+   the value of the base register when the set of related values was
+   created plus OFFSET yields the value that is used.
+   This might be different from the value of the used register before
+   executing INSN if we elected to use pre-{in,de}crement addressing.
+   If we have the option to use post-{in,de}crement addressing, all
+   choices are linked cyclically together with the SIBLING field.
+   Otherwise, it's a one-link-cycle, i.e. SIBLING points at the
+   struct rel_use it is a member of.
+
+   MATCH_OFFSET is the offset that is available after the execution
+   of INSN.  It is the same as OFFSET for straight register-indirect
+   addressing and for pre-{in,de}crement addressing, while it differs
+   for the post-{in,de}crement addressing modes.
+
+   If SET_IN_PARALLEL is set, MATCH_OFFSET differs from OFFSET, yet
+   this is no post-{in,de}crement addressing.  Rather, it is a set
+   inside a PARALLEL that adds some constant to a register that holds
+   one value of a set of related values that we keep track of.
+
+   NEXT_CHAIN is the link in a chain of rel_use structures.  If nonzero,
+   we will ignore this rel_use in a hash table lookup, since it has
+   already been appended to.  This field can point to its containing
+   rel_use; this means that we found a reason not to append to this
+   chain anymore (e.g. if a use comes with a clobber).
+
+   ADDRP then points only to the set destination of this set; another
+   struct rel_use is used for the source of the set.
+
+   NO_LINK_PRED is nonzero for the last use in a chain if it cannot be
+   the predecessor for a another chain to be linked to.  This can happen
+   for uses that come with a clobber, and for uses by a register that
+   is live at the end of the processed range of insns (usually a basic
+   block).  */
+
+struct rel_use
+{
+  rtx insn, *addrp;
+  int luid;
+  int call_tally;
+  enum reg_class class;
+  HOST_WIDE_INT offset;
+  HOST_WIDE_INT match_offset;
+  struct rel_use *next_chain;
+  struct rel_use **prev_chain_ref;
+  struct rel_use *next_hash;
+  struct rel_use *sibling;
+  unsigned int set_in_parallel:1;
+  unsigned int no_link_pred:1;
+};
+
+/* Describe a modification we have to do to the rtl when doing the
+   related value optimization.
+   There are two types of modifications: emitting a new add or move
+   insn, or updating an address within an existing insn.  We distinguish
+   between these two cases by testing whether the INSN field is nonzero.  */
+struct rel_mod
+{
+  /* Nonzero if we have to emit a new addition before this insn.
+     Otherwise, this describes an address update.  */
+  rtx insn;
+  /* The chain which this modification belongs to.  */
+  struct rel_use_chain *chain;
+  /* The position within the insn stream.  Used for sorting the set of
+     modifications in ascending order.  */
+  int luid;
+  /* Used to make the sort stable.  */
+  int count;
+  /* If this structure describes an addition, this is nonzero if the
+     source register is the base reg.  */
+  unsigned int from_base:1;
+};
+
+struct related **regno_related, *rel_base_list, *unrelatedly_used;
+
+#define rel_alloc(N) obstack_alloc(&related_obstack, (N))
+#define rel_new(X) ((X) = rel_alloc (sizeof *(X)))
+
+static struct obstack related_obstack;
+
+/* For each integer machine mode, the minimum and maximum constant that
+   can be added with a single constant.
+   This is supposed to define an interval around zero; if there are
+   singular points disconnected from this interval, we want to leave
+   them out.  */
+   
+static HOST_WIDE_INT add_limits[NUM_MACHINE_MODES][2];
+static char have_3addr_const_add[NUM_MACHINE_MODES];
+
+/* Try to find a related value with offset OFFSET from the base
+   register belonging to REGNO, using a register with preferred class
+   that is compatible with CLASS.  LUID is the insn in which we want
+   to use the matched register; this is used to avoid returning a
+   match that is an autoincrement within the same insn.  */
+
+static struct rel_use *
+lookup_related (int regno, enum reg_class class, HOST_WIDE_INT offset,
+		int luid)
+{
+  struct related *base = regno_related[regno]->base;
+  int hash = REL_USE_HASH (offset);
+  struct rel_use *match = base->baseinfo->hashtab[hash];
+  
+  for (; match; match = match->next_hash)
+    {
+      if (offset != match->match_offset)
+	continue;
+
+      /* If MATCH is an autoincrement in the same insn, ensure that it
+	 will not be used; otherwise we can end up with invalid rtl
+	 that uses the register outside the autoincrement.  */
+      if (match->luid == luid && match->offset != match->match_offset)
+	continue;
+
+      /* We are looking for a use which we can append to, so ignore
+	 anything that has already been appended to, and anything that
+	 must terminate a chain for other reasons.  */
+      if (match->next_chain)
+	continue;
+
+      if (regclass_compatible_p (class, match->class))
+	break;
+    }
+  
+  return match;
+}
+
+/* Add NEW_USE at the end of the chain that currently ends with MATCH;
+   If MATCH is not set, create a new chain.
+   BASE is the base register number the chain belongs to.  */
+
+static void
+rel_build_chain (struct rel_use *new_use, struct rel_use *match,
+		 struct related *base)
+{
+  int hash;
+
+  if (match)
+    {
+      struct rel_use *sibling = match;
+
+      do
+	{
+	  sibling->next_chain = new_use;
+	  if (sibling->prev_chain_ref)
+	    *sibling->prev_chain_ref = match;
+	  sibling = sibling->sibling;
+	}
+      while (sibling != match);
+
+      new_use->prev_chain_ref = &match->next_chain;
+    }
+  else
+    {
+      struct rel_use_chain *new_chain;
+
+      rel_new (new_chain);
+      new_chain->uses = new_use;
+      new_use->prev_chain_ref = &new_chain->uses;
+      new_chain->linked = 0;
+      new_chain->prev = base->baseinfo->chains;
+      base->baseinfo->chains = new_chain;
+    }
+  new_use->next_chain = 0;
+
+  hash = REL_USE_HASH (new_use->offset);
+  new_use->next_hash = base->baseinfo->hashtab[hash];
+  base->baseinfo->hashtab[hash] = new_use;
+}
+
+static struct rel_use *
+create_rel_use (rtx insn, rtx *xp, int regno, int luid, int call_tally)
+{
+  struct rel_use *new_use;
+  HOST_WIDE_INT offset = regno_related[regno]->offset;
+  enum reg_class class = reg_preferred_class (regno);
+
+  rel_new (new_use);
+  new_use->insn = insn;
+  new_use->addrp = xp;
+  new_use->luid = luid;
+  new_use->call_tally = call_tally;
+  new_use->class = class;
+  new_use->set_in_parallel = 0;
+  new_use->offset = offset;
+  new_use->match_offset = offset;
+  new_use->sibling = new_use;
+  new_use->no_link_pred = 0;
+
+  return new_use;
+}
+
+/* Record a new use of reg REGNO, which is found at address XP in INSN.
+   LUID and CALL_TALLY correspond to INSN.
+
+   There is a special case for uses of REGNO that must be preserved and
+   can't be optimized.  This case can happen either if we reach the end
+   of a block and a register which we track is still live, or if we find
+   a use of that register that can't be replaced inside an insn.  In
+   either case, TERMINATE should be set to a nonzero value.  */
+
+static void
+new_reg_use (rtx insn, rtx *xp, int regno, int luid, int call_tally,
+	     int terminate)
+{
+  struct rel_use *new_use, *match;
+  HOST_WIDE_INT offset = regno_related[regno]->offset;
+  enum reg_class class = reg_preferred_class (regno);
+  struct related *base = regno_related[regno]->base;
+
+  new_use = create_rel_use (insn, xp, regno, luid, call_tally);
+  match = lookup_related (regno, class, offset, luid);
+
+  rel_build_chain (new_use, match, base);
+  if (terminate)
+    new_use->next_chain = new_use;
+}
+
+/* Record the use of register ADDR in a memory reference.
+   ADDRP is the memory location where the address is stored.
+   MEM_MODE is the mode of the enclosing MEM.
+   SIZE is the size of the memory reference.
+   PRE_OFFS is the offset that has to be added to the value in ADDR
+   due to PRE_{IN,DE}CREMENT addressing in the original address; likewise,
+   POST_OFFSET denotes POST_{IN,DE}CREMENT addressing.  INSN is the
+   instruction that uses this address, LUID its luid, and CALL_TALLY
+   the current number of calls encountered since the start of the
+   function.  */
+      
+static void
+rel_record_mem (rtx *addrp, rtx addr, int size, int pre_offs, int post_offs,
+		rtx insn, int luid, int call_tally)
+{
+  rtx orig_addr = *addrp;
+  int regno;
+  struct related *base;
+  HOST_WIDE_INT offset;
+  struct rel_use *new_use, *match;
+  int hash;
+
+  gcc_assert (REG_P (addr));
+  
+  regno = REGNO (addr);
+
+  if (! regno_related[regno] || regno_related[regno]->invalidate_luid)
+    {
+      invalidate_related (addr, insn, luid, call_tally);
+      return;
+    }
+
+  offset = regno_related[regno]->offset += pre_offs;
+  base = regno_related[regno]->base;
+
+  if (base == 0)
+    return;
+
+  if (! test_addr)
+    test_addr = gen_rtx_PLUS (Pmode, addr, const0_rtx);
+
+  XEXP (test_addr, 0) = addr;
+  *addrp = test_addr;
+
+  new_use = create_rel_use (insn, addrp, regno, luid, call_tally);
+
+  match = lookup_related (regno, new_use->class, offset, luid);
+
+  /* Skip all the autoinc stuff if we found a match within the same insn.  */
+  if (match && match->luid == luid)
+    goto found_match;
+
+  if (! match)
+    {
+      /* We can choose PRE_{IN,DE}CREMENT on the spot with the information
+	 we have gathered about the preceding instructions, while we have
+	 to record POST_{IN,DE}CREMENT possibilities so that we can check
+	 later if we have a use for their output value.  */
+      /* We use recog here directly because we are only testing here if
+	 the changes could be made, but don't really want to make a
+	 change right now.  The caching from recog_memoized would only
+	 get in the way.  */
+
+      if (HAVE_PRE_INCREMENT)
+	{
+	  match = lookup_related (regno, new_use->class, offset - size, luid);
+	  PUT_CODE (test_addr, PRE_INC);
+	  if (match && match->luid != luid
+	      && recog (PATTERN (insn), insn, NULL) >= 0)
+	    goto found_match;
+	}
+
+      if (HAVE_PRE_DECREMENT)
+	{
+	  match = lookup_related (regno, new_use->class, offset + size, luid);
+	  PUT_CODE (test_addr, PRE_DEC);
+	  if (match && match->luid != luid
+	      && recog (PATTERN (insn), insn, NULL) >= 0)
+	    goto found_match;
+	}
+
+      match = 0;
+    }
+
+  PUT_CODE (test_addr, POST_INC);
+      
+  if (HAVE_POST_INCREMENT && recog (PATTERN (insn), insn, NULL) >= 0)
+    {
+      struct rel_use *inc_use;
+
+      rel_new (inc_use);
+      *inc_use = *new_use;
+      inc_use->sibling = new_use;
+      new_use->sibling = inc_use;
+      inc_use->prev_chain_ref = NULL;
+      inc_use->next_chain = NULL;
+      hash = REL_USE_HASH (inc_use->match_offset = offset + size);
+      inc_use->next_hash = base->baseinfo->hashtab[hash];
+      base->baseinfo->hashtab[hash] = inc_use;
+    }
+
+  PUT_CODE (test_addr, POST_DEC);
+
+  if (HAVE_POST_DECREMENT && recog (PATTERN (insn), insn, NULL) >= 0)
+    {
+      struct rel_use *dec_use;
+
+      rel_new (dec_use);
+      *dec_use = *new_use;
+      dec_use->sibling = new_use->sibling;
+      new_use->sibling = dec_use;
+      dec_use->prev_chain_ref = NULL;
+      dec_use->next_chain = NULL;
+      hash = REL_USE_HASH (dec_use->match_offset = offset + size);
+      dec_use->next_hash = base->baseinfo->hashtab[hash];
+      base->baseinfo->hashtab[hash] = dec_use;
+    }
+
+ found_match:
+      
+  rel_build_chain (new_use, match, base);
+  *addrp = orig_addr;
+
+  regno_related[regno]->offset += post_offs;
+}
+
+/* Note that REG is set to something that we do not regognize as a
+   related value, at an insn with linear uid LUID.  */
+
+static void
+invalidate_related (rtx reg, rtx insn, int luid, int call_tally)
+{
+  int regno = REGNO (reg);
+  struct related *rel = regno_related[regno];
+  if (rel && rel->base)
+    {
+      rel->invalidate_luid = luid;
+      rel->reg_orig_calls_crossed = call_tally - rel->reg_set_call_tally;
+    }
+  if (! rel || rel->base)
+    {
+      rel_new (rel);
+      regno_related[regno] = rel;
+      rel->prev = unrelatedly_used;
+      unrelatedly_used = rel;
+      rel->reg = reg;
+      rel->base = NULL;
+    }
+  rel->invalidate_luid = luid;
+  rel->insn = insn;
+}
+
+/* Record REG as a new base for related values.  INSN is the insn in which
+   we found it, LUID is its luid, and CALL_TALLY the number of calls seen
+   up to this point.  */
+
+static void
+new_base (rtx reg, rtx insn, int luid, int call_tally)
+{
+  int regno = REGNO (reg);
+  struct related *new_related;
+
+  rel_new (new_related);
+  new_related->reg = reg;
+  new_related->insn = insn;
+  new_related->updates = 0;
+  new_related->reg_set_call_tally = call_tally;
+  new_related->base = new_related;
+  new_related->offset = 0;
+  new_related->prev = 0;
+  new_related->invalidate_luid = 0;
+  new_related->death = NULL_RTX;
+  rel_new (new_related->baseinfo);
+  memset ((char *) new_related->baseinfo, 0, sizeof *new_related->baseinfo);
+  new_related->baseinfo->prev_base = rel_base_list;
+  rel_base_list = new_related;
+  new_related->baseinfo->insn_luid = luid;
+  regno_related[regno] = new_related;
+}
+
+/* Check out if INSN sets a new related value.  Return nonzero if we could
+   handle this insn.  */
+
+static int
+recognize_related_for_insn (rtx insn, int luid, int call_tally)
+{
+  rtx set = single_set (insn);
+  rtx src, dst;
+  rtx src_reg, src_const;
+  int src_regno, dst_regno;
+  struct related *new_related;
+
+  /* We don't care about register class differences here, since
+     we might still find multiple related values share the same
+     class even if it is disjunct from the class of the original
+     register.  */
+
+  if (set == 0)
+    return 0;
+
+  dst = SET_DEST (set);
+  src = SET_SRC (set);
+
+  /* First check that we have actually something like
+     (set (reg pseudo_dst) (plus (reg pseudo_src) (const_int))) .  */
+  if (GET_CODE (src) == PLUS)
+    {
+      src_reg = XEXP (src, 0);
+      src_const = XEXP (src, 1);
+    }
+  else if (REG_P (src) && GET_MODE_CLASS (GET_MODE (src)) == MODE_INT)
+    {
+      src_reg = src;
+      src_const = const0_rtx;
+    }
+  else
+    return 0;
+
+  if (!REG_P (src_reg) || GET_CODE (src_const) != CONST_INT || !REG_P (dst))
+    return 0;
+
+  dst_regno = REGNO (dst);
+  src_regno = REGNO (src_reg);
+
+  if (src_regno < FIRST_PSEUDO_REGISTER
+      || dst_regno < FIRST_PSEUDO_REGISTER)
+    return 0;
+
+  /* Check if this is merely an update of a register with a
+     value belonging to a group of related values we already
+     track.  */
+  if (regno_related[dst_regno] && ! regno_related[dst_regno]->invalidate_luid)
+    {
+      struct update *new_update;
+
+      /* If the base register changes, don't handle this as a
+	 related value.  We can currently only attribute the
+	 register to one base, and keep record of one lifetime
+	 during which we might re-use the register.  */
+      if (! regno_related[src_regno]
+	  || regno_related[src_regno]->invalidate_luid
+	  || (regno_related[dst_regno]->base
+	      != regno_related[src_regno]->base))
+	return 0;
+
+      regno_related[dst_regno]->offset
+	= regno_related[src_regno]->offset + INTVAL (src_const);
+      rel_new (new_update);
+      new_update->insn = insn;
+      new_update->death_insn = regno_related[dst_regno]->death;
+      regno_related[dst_regno]->death = NULL_RTX;
+      new_update->prev = regno_related[dst_regno]->updates;
+      regno_related[dst_regno]->updates = new_update;
+
+      return 1;
+    }
+
+  if (! regno_related[src_regno] || regno_related[src_regno]->invalidate_luid)
+    {
+      if (src_regno == dst_regno)
+	return 0;
+
+      new_base (src_reg, insn, luid, call_tally);
+    }
+  /* If the destination register has been used since we started
+     tracking this group of related values, there would be tricky
+     lifetime problems that we don't want to tackle right now.  */
+  else if (regno_related[dst_regno]
+	   && (regno_related[dst_regno]->invalidate_luid
+	       >= regno_related[src_regno]->base->baseinfo->insn_luid))
+    return 0;
+
+  rel_new (new_related);
+  new_related->reg = dst;
+  new_related->insn = insn;
+  new_related->updates = 0;
+  new_related->reg_set_call_tally = call_tally;
+  new_related->base = regno_related[src_regno]->base;
+  new_related->offset = regno_related[src_regno]->offset + INTVAL (src_const);
+  new_related->invalidate_luid = 0;
+  new_related->death = NULL_RTX;
+  new_related->prev = regno_related[src_regno]->prev;
+  regno_related[src_regno]->prev = new_related;
+  regno_related[dst_regno] = new_related;
+
+  return 1;
+}
+
+/* Record a use of a register at *XP, which is not inside a MEM which we
+   consider changing except for plain register substitution.  */
+static void
+record_reg_use (rtx *xp, rtx insn, int luid, int call_tally)
+{
+  rtx x = *xp;
+  int regno = REGNO (x);
+	
+  if (! regno_related[regno])
+    {
+      rel_new (regno_related[regno]);
+      regno_related[regno]->prev = unrelatedly_used;
+      unrelatedly_used = regno_related[regno];
+      regno_related[regno]->reg = x;
+      regno_related[regno]->base = NULL;
+      regno_related[regno]->invalidate_luid = luid;
+      regno_related[regno]->insn = insn;
+    }
+  else if (regno_related[regno]->invalidate_luid)
+    {
+      regno_related[regno]->invalidate_luid = luid;
+      regno_related[regno]->insn = insn;
+    }
+  else
+    new_reg_use (insn, xp, regno, luid, call_tally, 0);
+}
+
+/* Check the RTL fragment pointed to by XP for related values - that is,
+   if any new are created, or if they are assigned new values.  Also
+   note any other sets so that we can track lifetime conflicts.
+   INSN is the instruction XP points into, LUID its luid, and CALL_TALLY
+   the number of preceding calls in the function.  */
+
+static void
+find_related (rtx *xp, rtx insn, int luid, int call_tally)
+{
+  rtx x = *xp;
+  enum rtx_code code = GET_CODE (x);
+  const char *fmt;
+  int i;
+
+  if (code == REG)
+    record_reg_use (xp, insn, luid, call_tally);
+  else if (code == MEM)
+    {
+      enum machine_mode mem_mode = GET_MODE (x);
+      int size = GET_MODE_SIZE (mem_mode);
+      rtx *addrp= &XEXP (x, 0), addr = *addrp;
+
+      switch (GET_CODE (addr))
+	{
+	case REG:
+	  rel_record_mem (addrp, addr, size, 0, 0,
+			  insn, luid, call_tally);
+	  return;
+	case PRE_INC:
+	  rel_record_mem (addrp, XEXP (addr, 0), size, size, 0,
+			  insn, luid, call_tally);
+	  return;
+	case POST_INC:
+	  rel_record_mem (addrp, XEXP (addr, 0), size, 0, size,
+			  insn, luid, call_tally);
+	  return;
+	case PRE_DEC:
+	  rel_record_mem (addrp, XEXP (addr, 0), size, -size, 0,
+			  insn, luid, call_tally);
+	  return;
+	case POST_DEC:
+	  rel_record_mem (addrp, XEXP (addr, 0), size, 0, -size,
+			  insn, luid, call_tally);
+	  return;
+	default:
+	  break;
+	}
+    }
+  
+  fmt = GET_RTX_FORMAT (code);
+
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+	find_related (&XEXP (x, i), insn, luid, call_tally);
+      
+      if (fmt[i] == 'E')
+	{
+	  register int j;
+	  
+	  for (j = 0; j < XVECLEN (x, i); j++)
+	    find_related (&XVECEXP (x, i, j), insn, luid, call_tally);
+	}
+    }
+}
+
+/* Process one insn for optimize_related_values.  INSN is the insn, LUID
+   and CALL_TALLY its corresponding luid and number of calls seen so
+   far.  */
+static void
+find_related_toplev (rtx insn, int luid, int call_tally)
+{
+  int i;
+
+  /* First try to process the insn as a whole.  */
+  if (recognize_related_for_insn (insn, luid, call_tally))
+    return;
+
+  if (GET_CODE (PATTERN (insn)) == USE
+      || GET_CODE (PATTERN (insn)) == CLOBBER)
+    {
+      rtx *xp = &XEXP (PATTERN (insn), 0);
+      int regno;
+      
+      if (!REG_P (*xp))
+	{
+	  find_related (xp, insn, luid, call_tally);
+	  return;
+	}
+
+      regno = REGNO (*xp);
+      if (GET_CODE (PATTERN (insn)) == USE
+	  && regno_related[regno]
+	  && ! regno_related[regno]->invalidate_luid)
+	new_reg_use (insn, xp, regno, luid, call_tally, 1);
+      invalidate_related (*xp, insn, luid, call_tally);
+      return;
+    }
+
+  if (CALL_P (insn) && CALL_INSN_FUNCTION_USAGE (insn))
+    {
+      rtx usage;
+
+      for (usage = CALL_INSN_FUNCTION_USAGE (insn);
+	   usage;
+	   usage = XEXP (usage, 1))
+	find_related (&XEXP (usage, 0), insn, luid, call_tally);
+    }
+
+  extract_insn (insn);
+  /* Process all inputs.  */
+  for (i = 0; i < recog_data.n_operands; i++)
+    {
+      rtx *loc = recog_data.operand_loc[i];
+      rtx op = *loc;
+
+      if (op == NULL)
+	continue;
+
+      while (GET_CODE (op) == SUBREG
+	     || GET_CODE (op) == ZERO_EXTRACT
+	     || GET_CODE (op) == SIGN_EXTRACT
+	     || GET_CODE (op) == STRICT_LOW_PART)
+	loc = &XEXP (op, 0), op = *loc;
+
+      if (recog_data.operand_type[i] == OP_IN || !REG_P (op))
+	find_related (loc, insn, luid, call_tally);
+    }
+
+
+  /* If we have an OP_IN type operand with match_dups, process those
+     duplicates also.  */
+  for (i = 0; i < recog_data.n_dups; i++)
+    {
+      int opno = recog_data.dup_num[i];
+      rtx *loc = recog_data.dup_loc[i];
+      rtx op = *loc;
+
+      while (GET_CODE (op) == SUBREG
+	     || GET_CODE (op) == ZERO_EXTRACT
+	     || GET_CODE (op) == SIGN_EXTRACT
+	     || GET_CODE (op) == STRICT_LOW_PART)
+	loc = &XEXP (op, 0), op = *loc;
+
+      if (recog_data.operand_type[opno] == OP_IN || !REG_P (op))
+	find_related (loc, insn, luid, call_tally);
+    }
+  
+  /* Process outputs.  */
+  for (i = 0; i < recog_data.n_operands; i++)
+    {
+      enum op_type type = recog_data.operand_type[i];
+      rtx *loc = recog_data.operand_loc[i];
+      rtx op = *loc;
+
+      if (op == NULL)
+	continue;
+
+      while (GET_CODE (op) == SUBREG
+	     || GET_CODE (op) == ZERO_EXTRACT
+	     || GET_CODE (op) == SIGN_EXTRACT
+	     || GET_CODE (op) == STRICT_LOW_PART)
+	loc = &XEXP (op, 0), op = *loc;
+
+      /* Detect if we're storing into only one word of a multiword
+	 subreg.  */
+      if (loc != recog_data.operand_loc[i] && type == OP_OUT)
+	type = OP_INOUT;
+
+      if (REG_P (op))
+	{
+	  int regno = REGNO (op);
+
+	  if (type == OP_INOUT)
+	    {							
+	      /* This is a use we can't handle.  Add a dummy use of this
+		 register as well as invalidating it.  */
+	      if (regno_related[regno]
+		  && ! regno_related[regno]->invalidate_luid)
+		new_reg_use (insn, loc, regno, luid, call_tally, 1);
+	    }
+
+	  if (type != OP_IN)
+	    /* A set of a register invalidates it (unless the set was
+	       handled by recognize_related_for_insn).  */
+	    invalidate_related (op, insn, luid, call_tally);
+	}
+    }
+}
+
+/* Comparison functions for qsort.  */
+static int
+chain_starts_earlier (const void *chain1, const void *chain2)
+{
+  int d = ((*(struct rel_use_chain **)chain2)->start_luid
+	   - (*(struct rel_use_chain **)chain1)->start_luid);
+  if (! d)
+    d = ((*(struct rel_use_chain **)chain2)->uses->offset
+         - (*(struct rel_use_chain **)chain1)->uses->offset);
+  if (! d)
+    d = ((*(struct rel_use_chain **)chain2)->uses->set_in_parallel
+         - (*(struct rel_use_chain **)chain1)->uses->set_in_parallel);
+  
+  /* If set_in_parallel is not set on both chain's first use, they must
+     differ in start_luid or offset, since otherwise they would use the
+     same chain.
+     Thus the remaining problem is with set_in_parallel uses; for these, we
+     know that *addrp is a register.  Since the same register may not be set
+     multiple times in the same insn, the registers must be different.  */
+     
+  if (! d)
+    d = (REGNO (*(*(struct rel_use_chain **)chain2)->uses->addrp)
+         - REGNO (*(*(struct rel_use_chain **)chain1)->uses->addrp));
+  return d;
+}
+
+static int
+chain_ends_later (const void *chain1, const void *chain2)
+{
+  int d = ((*(struct rel_use_chain **)chain1)->end->no_link_pred
+	   - (*(struct rel_use_chain **)chain2)->end->no_link_pred);
+  if (! d)
+    d = ((*(struct rel_use_chain **)chain1)->end_luid
+	 - (*(struct rel_use_chain **)chain2)->end_luid);
+  if (! d)
+    d = ((*(struct rel_use_chain **)chain2)->uses->offset
+         - (*(struct rel_use_chain **)chain1)->uses->offset);
+  if (! d)
+    d = ((*(struct rel_use_chain **)chain2)->uses->set_in_parallel
+         - (*(struct rel_use_chain **)chain1)->uses->set_in_parallel);
+  
+  /* If set_in_parallel is not set on both chain's first use, they must
+     differ in start_luid or offset, since otherwise they would use the
+     same chain.
+     Thus the remaining problem is with set_in_parallel uses; for these, we
+     know that *addrp is a register.  Since the same register may not be set
+     multiple times in the same insn, the registers must be different.  */
+     
+  if (! d)
+    {
+      rtx reg1 = (*(*(struct rel_use_chain **)chain1)->uses->addrp);
+      rtx reg2 = (*(*(struct rel_use_chain **)chain2)->uses->addrp);
+
+      switch (GET_CODE (reg1))
+	{
+	case REG:
+	  break;
+
+	case PRE_INC:
+	case POST_INC:
+	case PRE_DEC:
+	case POST_DEC:
+	  reg1 = XEXP (reg1, 0);
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+
+      switch (GET_CODE (reg2))
+	{
+	case REG:
+	  break;
+
+	case PRE_INC:
+	case POST_INC:
+	case PRE_DEC:
+	case POST_DEC:
+	  reg2 = XEXP (reg2, 0);
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+
+	d = (REGNO (reg2) - REGNO (reg1));
+    }
+  return d;
+}
+
+/* Called through qsort, used to sort rel_mod structures in ascending
+   order by luid.  */
+static int
+mod_before (const void *ptr1, const void *ptr2)
+{
+  const struct rel_mod *insn1 = ptr1;
+  const struct rel_mod *insn2 = ptr2;
+  if (insn1->luid != insn2->luid)
+    return insn1->luid - insn2->luid;
+  /* New add insns get inserted before the luid, modifications are
+     performed within this luid.  */
+  if (insn1->insn == 0 && insn2->insn != 0)
+    return 1;
+  if (insn2->insn == 0 && insn1->insn != 0)
+    return -1;
+  return insn1->count - insn2->count;
+}
+
+/* Update REG_N_SETS given a newly generated insn.  Called through
+   note_stores.  */
+static void
+count_sets (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED)
+{
+  if (REG_P (x))
+    REG_N_SETS (REGNO (x))++;
+}
+
+/* First pass of performing the optimization on a set of related values:
+   remove all the setting insns, death notes and refcount increments that
+   are now obsolete.
+   INSERT_BEFORE is an insn which we not must delete except by by turning it
+   into a note, since it is needed later.  */
+static void
+remove_setting_insns (struct related *rel_base, rtx insert_before)
+{
+  struct related *rel;
+
+  for (rel = rel_base; rel; rel = rel->prev)
+    {
+      struct update *update;
+      int regno = REGNO (rel->reg);
+
+      if (rel != rel_base)
+	{
+	  /* The first setting insn might be the start of a basic block.  */
+	  if (rel->insn == rel_base->insn
+	      /* We have to preserve insert_before.  */
+	      || rel->insn == insert_before)
+	    {
+	      PUT_CODE (rel->insn, NOTE);
+	      NOTE_LINE_NUMBER (rel->insn) = NOTE_INSN_DELETED;
+	      NOTE_SOURCE_FILE (rel->insn) = 0;
+	    }
+	  else
+	    delete_insn (rel->insn);
+	  REG_N_SETS (regno)--;
+	}
+
+      REG_N_CALLS_CROSSED (regno) -= rel->reg_orig_calls_crossed;
+	  
+      for (update = rel->updates; update; update = update->prev)
+	{
+	  rtx death_insn = update->death_insn;
+	      
+	  if (death_insn)
+	    {
+	      rtx death_note
+		= find_reg_note (death_insn, REG_DEAD, rel->reg);
+	      if (! death_note)
+		death_note
+		  = find_reg_note (death_insn, REG_UNUSED, rel->reg);
+	      remove_note (death_insn, death_note);
+	      REG_N_DEATHS (regno)--;
+	    }
+	      
+	  /* We have to preserve insert_before.  */
+	  if (update->insn == insert_before)
+	    {
+	      PUT_CODE (update->insn, NOTE);
+	      NOTE_LINE_NUMBER (update->insn) = NOTE_INSN_DELETED;
+	      NOTE_SOURCE_FILE (update->insn) = 0;
+	    }
+	  else
+	    delete_insn (update->insn);
+	      
+	  REG_N_SETS (regno)--;
+	}
+	  
+      if (rel->death)
+	{
+	  rtx death_note = find_reg_note (rel->death, REG_DEAD, rel->reg);
+	  if (! death_note)
+	    death_note = find_reg_note (rel->death, REG_UNUSED, rel->reg);
+	  remove_note (rel->death, death_note);
+	  rel->death = death_note;
+	  REG_N_DEATHS (regno)--;
+	}
+    }
+}
+
+/* Create a new add (or move) instruction as described by the modification
+   MOD, which is for the rel_use USE.  BASE_REG is the base register for
+   this set of related values, REL_BASE_REG_USER is the chain that uses
+   it.  */
+static rtx
+perform_addition (struct rel_mod *mod, struct rel_use *use, rtx base_reg,
+		  struct rel_use_chain *rel_base_reg_user)
+{
+  HOST_WIDE_INT use_offset = use->offset;
+  /* We have to generate a new addition or move insn and emit it
+     before the current use in this chain.  */
+  HOST_WIDE_INT new_offset = use_offset;
+  rtx reg = mod->chain->reg;
+  rtx src_reg;
+
+  if (mod->from_base)
+    {
+      src_reg = base_reg;
+      if (rel_base_reg_user)
+	use_offset -= rel_base_reg_user->match_offset;
+    }
+  else
+    {
+      src_reg = reg;
+      use_offset -= mod->chain->match_offset;
+    }
+
+  if (use_offset != 0 || src_reg != reg)
+    {
+      rtx new;
+      if (use_offset == 0)
+	new = gen_move_insn (reg, src_reg);
+      else
+	new = gen_add3_insn (reg, src_reg, GEN_INT (use_offset));
+
+      gcc_assert (new);
+
+      if (GET_CODE (new) == SEQUENCE)
+	{
+	  int i;
+
+	  for (i = XVECLEN (new, 0) - 1; i >= 0; i--)
+	    note_stores (PATTERN (XVECEXP (new, 0, i)), count_sets,
+			 NULL);
+	}
+      else
+	note_stores (new, count_sets, NULL);
+      new = emit_insn_before (new, mod->insn);
+
+      mod->chain->match_offset = new_offset;
+      return new;
+    }
+  return 0;
+}
+
+/* Perform the modification described by MOD, which applies to the use
+   described by USE.
+   This function calls validate_change; the caller must call
+   apply_change_group after all modifications for the same insn have
+   been performed.  */
+static void
+modify_address (struct rel_mod *mod, struct rel_use *use,
+		HOST_WIDE_INT current_offset)
+{
+  HOST_WIDE_INT use_offset = use->offset;
+  rtx reg = mod->chain->reg;
+  /* We have to perform a modification on a given use.  The
+     current use will be removed from the chain afterwards.  */
+  rtx addr = *use->addrp;
+
+  if (!REG_P (addr))
+    remove_note (use->insn,
+		 find_reg_note (use->insn, REG_INC,
+				XEXP (addr, 0)));
+
+  if (use_offset == current_offset)
+    {
+      if (use->set_in_parallel)
+	{
+	  REG_N_SETS (REGNO (addr))--;
+	  addr = reg;
+	}
+      else if (use->match_offset > use_offset)
+	addr = gen_rtx_POST_INC (Pmode, reg);
+      else if (use->match_offset < use_offset)
+	addr = gen_rtx_POST_DEC (Pmode, reg);
+      else
+	addr = reg;
+    }
+  else if (use_offset > current_offset)
+    addr = gen_rtx_PRE_INC (Pmode, reg);
+  else
+    addr = gen_rtx_PRE_DEC (Pmode, reg);
+
+  /* Group changes from the same chain for the same insn
+     together, to avoid failures for match_dups.  */
+  validate_change (use->insn, use->addrp, addr, 1);
+
+  if (addr != reg)
+    REG_NOTES (use->insn)
+      = gen_rtx_EXPR_LIST (REG_INC, reg, REG_NOTES (use->insn));
+
+  /* Update the chain's state: set match_offset as appropriate,
+     and move towards the next use.  */
+  mod->chain->match_offset = use->match_offset;
+  mod->chain->uses = use->next_chain;
+  if (mod->chain->uses == 0 && mod->chain->linked)
+    {
+      struct rel_use_chain *linked = mod->chain->linked;
+      mod->chain->linked = linked->linked;
+      mod->chain->uses = linked->uses;
+    }
+}
+
+/* Try to link SUCC_CHAIN as sucessor of PRED_CHAIN.  BASE_MODE is
+   the machine mode of the base register.  Return nonzero on success.  */
+static int
+link_chains (struct rel_use_chain *pred_chain,
+	     struct rel_use_chain *succ_chain, enum machine_mode base_mode)
+{
+  if (succ_chain->start_luid > pred_chain->end_luid
+      && ! pred_chain->end->no_link_pred
+      && regclass_compatible_p (succ_chain->uses->class,
+				pred_chain->uses->class)
+      /* add_limits is not valid for MODE_PARTIAL_INT .  */
+      && GET_MODE_CLASS (base_mode) == MODE_INT
+      && !have_3addr_const_add[(int) base_mode]
+      && (succ_chain->uses->offset - pred_chain->match_offset
+	  >= add_limits[(int) base_mode][0])
+      && (succ_chain->uses->offset - pred_chain->match_offset
+	  <= add_limits[(int) base_mode][1]))
+    {
+      /* We can link these chains together.  */
+      pred_chain->linked = succ_chain;
+      succ_chain->start_luid = 0;
+      pred_chain->end_luid = succ_chain->end_luid;
+      return 1;
+    }
+  return 0;
+}
+
+/* Perform the optimization for a single set of related values.
+   INSERT_BEFORE is an instruction before which we may emit instructions
+   to initialize registers that remain live beyond the end of the group
+   of instructions which have been examined.  */
+
+static void
+optimize_related_values_1 (struct related *rel_base, int luid, int call_tally,
+			   rtx insert_before, FILE *regmove_dump_file)
+{
+  struct related_baseinfo *baseinfo = rel_base->baseinfo;
+  struct related *rel;
+  struct rel_use_chain *chain, **chain_starttab, **chain_endtab;
+  struct rel_use_chain **pred_chainp, *pred_chain;
+  int num_regs, num_av_regs, num_chains, num_linked, max_end_luid, i;
+  int max_start_luid;
+  struct rel_use_chain *rel_base_reg_user;
+  enum machine_mode mode;
+  HOST_WIDE_INT rel_base_reg_user_offset = 0;
+
+  /* For any registers that are still live, we have to arrange
+     to have them set to their proper values.
+     Also count with how many registers (not counting base) we are
+     dealing with here.  */
+  for (num_regs = -1, rel = rel_base; rel; rel = rel->prev, num_regs++)
+    {
+      int regno = REGNO (rel->reg);
+
+      if (! rel->death && ! rel->invalidate_luid)
+	{
+	  new_reg_use (insert_before, &rel->reg, regno, luid, call_tally, 1);
+	  rel->reg_orig_calls_crossed = call_tally - rel->reg_set_call_tally;
+	}
+    }
+
+  /* Now for every chain of values related to the base, set start
+     and end luid, match_offset, and reg.  Also count the number of these
+     chains, and determine the largest end luid.  */
+  num_chains = 0;
+  
+  for (max_end_luid = 0, chain = baseinfo->chains; chain; chain = chain->prev)
+    {
+      struct rel_use *use, *next;
+
+      num_chains++;
+      next = chain->uses;
+      chain->start_luid = next->luid;
+      do
+	{
+	  use = next;
+	  next = use->next_chain;
+	}
+      while (next && next != use);
+
+      use->no_link_pred = next != NULL;
+      use->next_chain = 0;
+
+      chain->end = use;
+      chain->end_luid = use->luid;
+      chain->match_offset = use->match_offset;
+      chain->calls_crossed = use->call_tally - chain->uses->call_tally;
+      
+      chain->reg = ! use->no_link_pred ? NULL_RTX : *use->addrp;
+
+      if (use->luid > max_end_luid)
+	max_end_luid = use->luid;
+
+      if (regmove_dump_file)
+	fprintf (regmove_dump_file, "Chain start: %d end: %d\n",
+		 chain->start_luid, chain->end_luid);
+    }
+
+  if (regmove_dump_file)
+    fprintf (regmove_dump_file,
+	     "Insn %d reg %d: found %d chains.\n",
+	     INSN_UID (rel_base->insn), REGNO (rel_base->reg), num_chains);
+
+  if (! num_chains)
+    return;
+
+  /* For every chain, we try to find another chain the lifetime of which
+     ends before the lifetime of said chain starts.
+     So we first sort according to luid of first and last instruction that
+     is in the chain, respectively;  this is O(n * log n) on average.  */
+  chain_starttab = rel_alloc (num_chains * sizeof *chain_starttab);
+  chain_endtab = rel_alloc (num_chains * sizeof *chain_starttab);
+  
+  for (chain = baseinfo->chains, i = 0; chain; chain = chain->prev, i++)
+    {
+      chain_starttab[i] = chain;
+      chain_endtab[i] = chain;
+    }
+  
+  qsort (chain_starttab, num_chains, sizeof *chain_starttab,
+	 chain_starts_earlier);
+  qsort (chain_endtab, num_chains, sizeof *chain_endtab, chain_ends_later);
+
+  /* Now we go through every chain, starting with the one that starts
+     second (we can skip the first because we know there would be no match),
+     and check it against the chain that ends first.  */
+  /* ??? We assume here that reg_class_compatible_p will seldom return false.
+     If that is not true, we should do a more thorough search for suitable
+     chain combinations.  */
+  pred_chainp = chain_endtab;
+  pred_chain = *pred_chainp;
+  max_start_luid = chain_starttab[num_chains - 1]->start_luid;
+  
+  mode = GET_MODE (rel_base->reg);
+  for (num_linked = 0, i = num_chains - 2; i >= 0; i--)
+    {
+      struct rel_use_chain *succ_chain = chain_starttab[i];
+
+      if ((pred_chain->calls_crossed
+	   ? succ_chain->calls_crossed
+	   : succ_chain->end->call_tally == pred_chain->uses->call_tally)
+	  && link_chains (pred_chain, succ_chain, mode))
+	{
+	  num_linked++;
+	  pred_chain = *++pred_chainp;
+	}
+      else
+	max_start_luid = succ_chain->start_luid;
+    }
+
+  if (regmove_dump_file && num_linked)
+    fprintf (regmove_dump_file, "Linked to %d sets of chains.\n",
+	     num_chains - num_linked);
+
+  /* Now count the number of registers that are available for reuse.  */
+  /* ??? In rare cases, we might reuse more if we took different
+     end luids of the chains into account.  Or we could just allocate
+     some new regs.  But that would probably not be worth the effort.  */
+  /* ??? We should pay attention to preferred register classes here too,
+     if the to-be-allocated register have a life outside the range that
+     we handle.  */
+  for (num_av_regs = 0, rel = rel_base->prev; rel; rel = rel->prev)
+    {
+      if (! rel->invalidate_luid
+	  || rel->invalidate_luid > max_end_luid)
+	num_av_regs++;
+    }
+
+  /* Propagate mandatory register assignments to the first chain in
+     all sets of linked chains, and set rel_base_reg_user.  */
+  for (rel_base_reg_user = 0, i = 0; i < num_chains; i++)
+    {
+      struct rel_use_chain *chain = chain_starttab[i];
+      if (chain->linked)
+	chain->reg = chain->linked->reg;
+      if (chain->reg == rel_base->reg)
+	rel_base_reg_user = chain;
+    }
+    
+  /* If rel_base->reg is not a mandatory allocated register, allocate
+     it to that chain that starts first and has no allocated register,
+     and that allows the addition of the start value in a single
+     instruction.  */
+  if (! rel_base_reg_user)
+    {
+      for (i = num_chains - 1; i >= 0; --i)
+	{
+	  struct rel_use_chain *chain = chain_starttab[i];
+	  if (! chain->reg
+	      && chain->start_luid
+	      && (!have_3addr_const_add[(int) mode] || !chain->uses->offset)
+	      && chain->uses->offset >= add_limits[(int) mode][0]
+	      && chain->uses->offset <= add_limits[(int) mode][1]
+	      /* Also can't use this chain if its register is clobbered
+		 and other chains need to start later.  */
+	      && (! (chain->end->no_link_pred && chain->end->insn)
+		  || chain->end_luid >= max_start_luid)
+	      /* Also can't use it if it lasts longer than the
+		 base reg is available.  */
+	      && (! rel_base->invalidate_luid
+		  || rel_base->invalidate_luid > chain->end_luid))
+	    {
+	      chain->reg = rel_base->reg;
+	      rel_base_reg_user = chain;
+	      if (num_linked < num_chains - 1)
+		{
+		  int old_linked = num_linked;
+
+		  for (i = num_chains - 2; i >= 0; i--)
+		    {
+		      struct rel_use_chain *succ_chain = chain_starttab[i];
+
+		      while (chain->linked)
+			chain = chain->linked;
+		      if (succ_chain->start_luid
+			  && ! succ_chain->reg
+			  && link_chains (chain, succ_chain, mode))
+			{
+			  num_linked++;
+			  chain = succ_chain;
+			}
+		    }
+		  if (regmove_dump_file && num_linked > old_linked)
+		      fprintf (regmove_dump_file,
+			       "Linked to %d sets of chains.\n",
+			       num_chains - num_linked);
+		}
+	      break;
+	    }
+	}
+    }
+  else
+    rel_base_reg_user_offset = rel_base_reg_user->uses->offset;
+
+  /* If there are any chains that need to be initialized after the base
+     register has been invalidated, the optimization cannot be done.  */
+  for (i = 0; i < num_chains; i++)
+    {
+      struct rel_use_chain *chain = chain_starttab[i];
+
+      if (rel_base->invalidate_luid
+	  && chain->start_luid > rel_base->invalidate_luid)
+	return;
+    }
+
+  /* Now check if it is worth doing this optimization after all.
+     Using separate registers per value, like in the code generated by cse,
+     costs two instructions per register (one move and one add).
+     Using the chains we have set up, we need two instructions for every
+     linked set of chains, plus one instruction for every link;
+     however, if the base register is allocated to a chain
+     (i.e. rel_base_reg_user != 0), we don't need a move insn to start
+     that chain.
+     If we have a three-address add, however, the cost per value / chain
+     is just one insn, and linking chains is pointless.
+     We do the optimization if we save instructions, or if we
+     stay with the same number of instructions, but save registers.
+     We also require that we have enough registers available for reuse.
+     Moreover, we have to check that we can add the offset for
+     rel_base_reg_user, in case it is a mandatory allocated register.  */
+  if ((have_3addr_const_add[(int) mode]
+       ? (num_regs > num_chains - (rel_base_reg_user != 0))
+       : (2 * num_regs
+	  > ((2 * num_chains - num_linked - (rel_base_reg_user != 0))
+	     - (num_linked != 0))))
+      && num_av_regs + (rel_base_reg_user != 0) >= num_chains - num_linked
+      && rel_base_reg_user_offset >= add_limits[(int) mode][0]
+      && rel_base_reg_user_offset <= add_limits[(int) mode][1])
+    {
+      unsigned int base_regno = REGNO (rel_base->reg);
+      int num_mods;
+      int num_uses;
+      struct rel_mod *mods;
+      rtx last_changed_insn = 0;
+
+      /* Record facts about the last place where the base register is used.  */
+      int last_base_call_tally = rel_base->reg_set_call_tally;
+      rtx last_base_insn = 0;
+
+      if (regmove_dump_file)
+	fprintf (regmove_dump_file, "Optimization is worth while.\n");
+
+      remove_setting_insns (rel_base, insert_before);
+
+      /* Allocate regs for each chain, and count the number of uses.  */
+      rel = rel_base;
+      for (num_uses = 0, i = 0; i < num_chains; i++)
+	{
+	  struct rel_use_chain *chain0 = chain_starttab[i];
+	  unsigned int regno;
+	  int first_call_tally, last_call_tally;
+
+	  if (! chain0->start_luid)
+	    continue;
+
+	  /* If this chain has not got a register yet, assign one.  */
+	  if (! chain0->reg)
+	    {
+	      do
+		rel = rel->prev;
+	      while (! rel->death
+		     || (rel->invalidate_luid
+			 && rel->invalidate_luid <= max_end_luid));
+
+	      chain0->reg = rel->reg;
+	      chain0->death_note = rel->death;
+	    }
+	  else
+	    chain0->death_note = 0;
+
+	  /* For all registers except the base register, we can already
+	     determine the number of calls crossed at this point by
+	     examining the call_tally of the first and the last use.
+	     We can't do this for the base register yet, since we don't
+	     know its exact lifetime yet.  */
+	  regno = REGNO (chain0->reg);
+	  first_call_tally = last_call_tally = chain0->uses->call_tally;
+
+	  while (chain0)
+		{
+	      struct rel_use *use;
+	      for (use = chain0->uses; use; use = use->next_chain)
+		    {
+		  num_uses++;
+		  last_call_tally = use->call_tally;
+		    }
+	      chain0 = chain0->linked;
+		}
+
+	  if (regno != base_regno)
+	    REG_N_CALLS_CROSSED (regno) += last_call_tally - first_call_tally;
+	    }
+
+      /* Record all the modifications we need to perform together with
+	 their position, then sort the array by position.  */
+      mods = rel_alloc ((num_chains + num_uses) * sizeof *mods);
+      for (i = num_mods = 0; i < num_chains; i++)
+	{
+	  struct rel_use_chain *chain0 = chain_starttab[i];
+
+	  if (! chain0->start_luid)
+	    continue;
+
+	  for (chain = chain0; chain; chain = chain->linked)
+	    {
+	      struct rel_use *use = chain->uses;
+
+	      /* Initializing insn: an add (or move if offset == 0).  */
+	      mods[num_mods].from_base = use == chain0->uses;
+	      mods[num_mods].chain = chain0;
+	      mods[num_mods].insn = use->insn;
+	      mods[num_mods].luid = use->luid;
+	      mods[num_mods].count = num_mods;
+	      num_mods++;
+
+	      /* All the other uses: no additional insn, but offset
+		 updates.  */
+	      for (; use; use = use->next_chain)
+		{
+		  mods[num_mods].chain = chain0;
+		  mods[num_mods].insn = 0;
+		  mods[num_mods].luid = use->luid;
+		  mods[num_mods].count = num_mods;
+		  num_mods++;
+		}
+	    }
+	}
+
+      gcc_assert (num_mods == num_chains + num_uses);
+      qsort (mods, num_mods, sizeof *mods, mod_before);
+
+      /* Now we have a list of all changes we have to make, sorted in
+	 ascending order so we can go through the basic block from
+	 start to end and keep track of the current state at all times.  */
+      if (rel_base_reg_user)
+	rel_base_reg_user->match_offset = 0;
+      for (i = 0; i < num_mods; i++)
+	{
+	  struct rel_mod *this = mods + i;
+	  struct rel_use *use = this->chain->uses;
+	  HOST_WIDE_INT current_offset = this->chain->match_offset;
+	  rtx reg = this->chain->reg;
+
+	  /* Calling apply_change_group is deferred to this point from
+	     the call to validate_change in modify_address; the reason is
+	     that we want to group together multiple changes to the same insn,
+	     to avoid failures for match_dups.  */
+	  if (last_changed_insn
+	      && (this->insn != 0 || use->insn != last_changed_insn))
+	    {
+	      last_changed_insn = 0;
+	      /* Don't use gcc_assert on the result of apply_change_group
+		 because that would prevent setting a breakpoint on the
+		 failure.  */
+	      if (! apply_change_group ())
+		gcc_assert (0);
+	    }
+
+	  if (this->insn != 0)
+	    {
+	      rtx new = perform_addition (this, use, rel_base->reg,
+					  rel_base_reg_user);
+	      if (this->from_base && new)
+		{
+		  /* If perform_addition emitted more than one insn, find
+		     the last one that actually used the base register.  */
+		  while (! reg_overlap_mentioned_p (rel_base->reg,
+						    PATTERN (new)))
+		    new = PREV_INSN (new);
+		  last_base_call_tally = use->call_tally;
+		  last_base_insn = new;
+		}
+	    }
+	  else
+	    {
+	      if (! use->no_link_pred)
+		modify_address (this, use, current_offset);
+
+	      /* See if the register dies in this insn.  We cannot reliably
+		 detect this for the base register, which is handled later
+		 after all modifications are processed.  We can rely on the
+		 DEATH_NOTE field being 0 for the base register's chain.  */
+	      if (this->chain->death_note && this->chain->uses == 0)
+		{
+		  rtx note = this->chain->death_note;
+		  XEXP (note, 0) = reg;
+
+		  /* Note that passing only PATTERN (LAST_USE->insn) to
+		     reg_set_p here is not enough, since we might have
+		     created an REG_INC for REG above.  */
+
+		  PUT_MODE (note, (reg_set_p (reg, use->insn)
+				   ? REG_UNUSED : REG_DEAD));
+		  XEXP (note, 1) = REG_NOTES (use->insn);
+		  REG_NOTES (use->insn) = note;
+		  REG_N_DEATHS (REGNO (reg))++;
+		}
+
+	      if (REGNO (reg) == base_regno)
+		{
+		  last_base_call_tally = use->call_tally;
+		  last_base_insn = use->insn;
+		}
+	      last_changed_insn = use->insn;
+	    }
+	}
+
+      if (last_changed_insn)
+	if (! apply_change_group ())
+	  gcc_assert (0);
+
+      /* We now have performed all modifications, and we therefore know the
+	 last insn that uses the base register.  This means we can now update
+	 its life information.  */
+      if (rel_base->death)
+	{
+	  rtx note = rel_base->death;
+	  XEXP (note, 0) = rel_base->reg;
+
+	  /* Note that passing only PATTERN (LAST_USE->insn) to
+	     reg_set_p here is not enough, since we might have
+	     created an REG_INC for REG above.  */
+
+	  PUT_MODE (note, (reg_set_p (rel_base->reg, last_base_insn)
+			   ? REG_UNUSED : REG_DEAD));
+	  XEXP (note, 1) = REG_NOTES (last_base_insn);
+	  REG_NOTES (last_base_insn) = note;
+	  REG_N_DEATHS (base_regno)++;
+	}
+      else if (rel_base->invalidate_luid
+	       && ! reg_set_p (rel_base->reg, last_base_insn))
+	{
+	  REG_NOTES (last_base_insn)
+	    = alloc_EXPR_LIST (REG_DEAD, rel_base->reg,
+			       REG_NOTES (last_base_insn));
+	  REG_N_DEATHS (base_regno)++;
+	}
+
+      REG_N_CALLS_CROSSED (base_regno)
+	+= last_base_call_tally - rel_base->reg_set_call_tally;
+    }
+}
+
+/* Finalize the optimization for any related values know so far, and reset
+   the entries in regno_related that we have disturbed.  */
+static void
+optimize_related_values_0 (struct related *rel_base_list,
+			   int luid, int call_tally, rtx insert_before,
+			   FILE *regmove_dump_file)
+{
+  while (rel_base_list)
+    {
+      struct related *rel;
+      optimize_related_values_1 (rel_base_list, luid, call_tally,
+				 insert_before, regmove_dump_file);
+      /* Clear the entries that we used in regno_related.  We do it
+	 item by item here, because doing it with memset for each
+	 basic block would give O(n*n) time complexity.  */
+      for (rel = rel_base_list; rel; rel = rel->prev)
+	regno_related[REGNO (rel->reg)] = 0;
+      rel_base_list = rel_base_list->baseinfo->prev_base;
+    }
+  
+  for ( ; unrelatedly_used; unrelatedly_used = unrelatedly_used->prev)
+    regno_related[REGNO (unrelatedly_used->reg)] = 0;
+}
+
+/* For each integer mode, find minimum and maximum value for a single-
+   instruction reg-constant add.
+   The arm has SImode add patterns that will accept large values - with a
+   matching splitter - but when you use gen_addsi3, you already get
+   multiple instructions.  So getting one insn and testing if it can be
+   changed is not good enough; we need to try to generate each add from
+   scratch.  */
+static void
+init_add_limits (void)
+{
+  static int is_initialized;
+
+  enum machine_mode mode;
+
+  if (is_initialized)
+    return;
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      rtx reg = gen_rtx_REG (mode, LAST_VIRTUAL_REGISTER+1);
+      rtx reg2 = gen_rtx_REG (mode, LAST_VIRTUAL_REGISTER+2);
+      int icode = (int) add_optab->handlers[(int) mode].insn_code;
+      HOST_WIDE_INT tmp;
+      rtx add = NULL, set = NULL;
+      int p, p_max;
+      rtx tmp_add;
+      struct match match;
+
+      have_3addr_const_add[(int) mode] = 0;
+      add_limits[(int) mode][0] = 0;
+      add_limits[(int) mode][1] = 0;
+      
+      if (icode == CODE_FOR_nothing
+	  || ! (*insn_data[icode].operand[0].predicate) (reg, mode)
+	  || ! (*insn_data[icode].operand[1].predicate) (reg, mode)
+	  || ! (*insn_data[icode].operand[2].predicate) (const1_rtx, mode))
+	continue;
+      
+      tmp_add = GEN_FCN (icode) (reg, reg2, const1_rtx);
+      if (tmp_add != NULL_RTX
+	  && !NEXT_INSN (tmp_add)
+	  && !find_matches (tmp_add, &match))
+	have_3addr_const_add[(int) mode] = 1;
+
+      p_max = GET_MODE_BITSIZE (mode) - 1;
+      
+      if (p_max > HOST_BITS_PER_WIDE_INT - 2)
+	p_max = HOST_BITS_PER_WIDE_INT - 2;
+      
+      for (p = 1; p < p_max; p++)
+	{
+	  rtx add_const = GEN_INT (((HOST_WIDE_INT) 1 << p) - 1);
+
+	  if (! (*insn_data[icode].operand[2].predicate) (add_const, mode))
+	    break;
+
+	  tmp_add = GEN_FCN (icode) (reg, reg, add_const);
+      
+	  if (tmp_add == NULL_RTX || NEXT_INSN (tmp_add))
+	    break;
+      
+	  set = single_set (tmp_add);
+      
+	  if (! set
+	      || GET_CODE (SET_SRC (set)) != PLUS
+	      || XEXP (SET_SRC (set), 1) != add_const)
+	    break;
+	  add = tmp_add;
+	}
+      
+      add_limits[(int) mode][1] = tmp = ((HOST_WIDE_INT) 1 << (p - 1)) - 1;
+      
+      /* We need a range of known good values for the constant of the add.
+	 Thus, before checking for the power of two, check for one less first,
+	 in case the power of two is an exceptional value.  */
+      if (add
+	  && validate_change (add, &XEXP (SET_SRC (set), 1), GEN_INT (-tmp), 0))
+	{
+	  if (validate_change (add, &XEXP (SET_SRC (set), 1),
+			       GEN_INT (-tmp - 1), 0))
+	    add_limits[(int) mode][0] = -tmp - 1;
+	  else
+	    add_limits[(int) mode][0] = -tmp;
+	}
+    }
+  is_initialized = 1;
+}
+
+/* Scan the entire function for instances where multiple registers are
+   set to values that differ only by a constant.
+   Then try to reduce the number of instructions and/or registers needed
+   by exploiting auto_increment and true two-address additions.
+   NREGS and REGMOVE_DUMP_FILE are the same as in regmove_optimize.  */
+    
+static void
+optimize_related_values (int nregs, FILE *regmove_dump_file)
+{
+  basic_block bb;
+  rtx insn;
+  int luid = 0;
+  int call_tally = 0;
+
+  if (regmove_dump_file)
+    fprintf (regmove_dump_file, "Starting optimize_related_values.\n");
+
+  init_add_limits ();
+  gcc_obstack_init (&related_obstack);
+  regno_related = rel_alloc (nregs * sizeof *regno_related);
+  memset ((char *) regno_related, 0, nregs * sizeof *regno_related);
+  rel_base_list = 0;
+
+  FOR_EACH_BB (bb)
+    FOR_BB_INSNS (bb, insn)
+      {
+	rtx set = NULL_RTX;
+
+	luid++;
+	
+	/* Don't do anything if this instruction is in the shadow of a
+	   live flags register.  */
+	if (GET_MODE (insn) == HImode)
+	  continue;
+
+	if (INSN_P (insn))
+	  {
+	    rtx note;
+
+	    set = single_set (insn);
+
+	    find_related_toplev (insn, luid, call_tally);
+
+	    for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+	      {
+		if (REG_NOTE_KIND (note) == REG_DEAD
+		    || (REG_NOTE_KIND (note) == REG_UNUSED
+			&& REG_P (XEXP (note, 0))))
+		  {
+		    rtx reg = XEXP (note, 0);
+		    int regno = REGNO (reg);
+		    
+		    if (REG_NOTE_KIND (note) == REG_DEAD
+			&& reg_set_p (reg, PATTERN (insn)))
+		      {
+			remove_note (insn, note);
+			REG_N_DEATHS (regno)--;
+		      }
+		    else if (regno_related[regno]
+			     && ! regno_related[regno]->invalidate_luid)
+		      {
+			regno_related[regno]->death = insn;
+			regno_related[regno]->reg_orig_calls_crossed
+			  = call_tally - regno_related[regno]->reg_set_call_tally;
+		      }
+		  }
+	      }
+	    
+	    /* Inputs to a call insn do not cross the call, therefore CALL_TALLY
+	       must be bumped *after* they have been processed.  */
+	    if (CALL_P (insn))
+	      call_tally++;
+	  }
+	    
+	/* We end current processing at the end of a basic block, or when
+	   a flags register becomes live, or when we see a return value
+	   copy.
+
+	   Otherwise, we might end up with one or more extra instructions
+	   inserted in front of the user, to set up or adjust a register. 
+	   There are cases where flag register uses could be handled smarter,
+	   but most of the time the user will be a branch anyways, so the
+	   extra effort to handle the occasional conditional instruction is
+	   probably not justified by the little possible extra gain.  */
+
+	if (insn == BB_END (bb)
+	    || GET_MODE (insn) == QImode
+	    || (set
+		&& REG_P (SET_DEST (set))
+		&& REG_FUNCTION_VALUE_P (SET_DEST (set))))
+	  {
+	    optimize_related_values_0 (rel_base_list, luid, call_tally,
+				       insn, regmove_dump_file);
+	    rel_base_list = 0;
+	  }
+      }
+  obstack_free (&related_obstack, 0);
+  
+  if (regmove_dump_file)
+    fprintf (regmove_dump_file, "Finished optimize_related_values.\n");
+}
+
 static int *regno_src_regno;
 
 /* Indicate how good a choice REG (which appears as a source) is to replace
@@ -970,35 +2885,36 @@ 		fprintf (regmove_dump_file,
 			 "Fixed operand of insn %d.\n",
 			  INSN_UID (insn));
 
-#ifdef AUTO_INC_DEC
-	      for (p = PREV_INSN (insn); p; p = PREV_INSN (p))
+	      if (AUTO_INC_DEC)
 		{
-		  if (LABEL_P (p)
-		      || JUMP_P (p))
-		    break;
-		  if (! INSN_P (p))
-		    continue;
-		  if (reg_overlap_mentioned_p (dst, PATTERN (p)))
+		  for (p = PREV_INSN (insn); p; p = PREV_INSN (p))
 		    {
-		      if (try_auto_increment (p, insn, 0, dst, newconst, 0))
-			return 1;
-		      break;
+		      if (LABEL_P (p)
+			  || JUMP_P (p))
+			break;
+		      if (! INSN_P (p))
+			continue;
+		      if (reg_overlap_mentioned_p (dst, PATTERN (p)))
+			{
+			  if (try_auto_increment (p, insn, 0, dst, newconst, 0))
+			    return 1;
+			  break;
+			}
 		    }
-		}
-	      for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
-		{
-		  if (LABEL_P (p)
-		      || JUMP_P (p))
-		    break;
-		  if (! INSN_P (p))
-		    continue;
-		  if (reg_overlap_mentioned_p (dst, PATTERN (p)))
+		  for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
 		    {
-		      try_auto_increment (p, insn, 0, dst, newconst, 1);
-		      break;
+		      if (LABEL_P (p)
+			  || JUMP_P (p))
+			break;
+		      if (! INSN_P (p))
+			continue;
+		      if (reg_overlap_mentioned_p (dst, PATTERN (p)))
+			{
+			  try_auto_increment (p, insn, 0, dst, newconst, 1);
+			  break;
+			}
 		    }
 		}
-#endif
 	      return 1;
 	    }
 	}
@@ -1040,7 +2956,7 @@    (or 0 if none should be output).  */
 void
 regmove_optimize (rtx f, int nregs, FILE *regmove_dump_file)
 {
-  int old_max_uid = get_max_uid ();
+  int old_max_uid;
   rtx insn;
   struct match match;
   int pass;
@@ -1057,6 +2973,13 @@   if (flag_non_call_exceptions)
      can suppress some optimizations in those zones.  */
   mark_flags_life_zones (discover_flags_reg ());
 
+  /* See the comment in front of REL_USE_HASH_SIZE what
+     this is about.  */
+  if (AUTO_INC_DEC && flag_regmove && flag_optimize_related_values)
+    optimize_related_values (nregs, regmove_dump_file);
+  /* That could have created new insns.  */
+  old_max_uid = get_max_uid ();
+
   regno_src_regno = xmalloc (sizeof *regno_src_regno * nregs);
   for (i = nregs; --i >= 0; ) regno_src_regno[i] = -1;
 
@@ -1999,6 +3922,8 @@   if (src_note)
       /* Move the death note for SRC from INSN to P.  */
       if (! overlap)
 	remove_note (insn, src_note);
+      if (find_reg_note (p, REG_INC, XEXP (src_note, 0)))
+	PUT_MODE (src_note, REG_UNUSED);
       XEXP (src_note, 1) = REG_NOTES (p);
       REG_NOTES (p) = src_note;
 
@@ -2540,3 +4465,4 @@ struct tree_opt_pass pass_stack_adjustme
   0                                     /* letter */
 };
 
+#include "gt-regmove.h"
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/rtlhooks.c gcc-4.1.1/gcc/rtlhooks.c
--- gcc-4.1.1.orig/gcc/rtlhooks.c	2005-06-25 03:02:01.000000000 +0100
+++ gcc-4.1.1/gcc/rtlhooks.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,5 +1,6 @@
 /* Generic hooks for the RTL middle-end.
    Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of GCC.
 
@@ -44,9 +45,12 @@   rtx result = gen_lowpart_common (mode,
 
   if (result)
     return result;
-  else if (REG_P (x))
+  /* If it's a REG, it must be a hard reg that's not valid in MODE.  */
+  else if (REG_P (x)
+	   /* Or we could have a subreg of a floating point value.  */
+	   || (GET_CODE (x) == SUBREG
+	       && FLOAT_MODE_P (GET_MODE (SUBREG_REG (x)))))
     {
-      /* Must be a hard reg that's not valid in MODE.  */
       result = gen_lowpart_common (mode, copy_to_reg (x));
       gcc_assert (result != 0);
       return result;
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/struct-equiv.c gcc-4.1.1/gcc/struct-equiv.c
--- gcc-4.1.1.orig/gcc/struct-equiv.c	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/struct-equiv.c	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,1357 @@
+/* Control flow optimization code for GNU compiler.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
+
+/* Try to match two basic blocks - or their ends - for structural equivalence.
+   We scan the blocks from their ends backwards, and expect that insns are
+   identical, except for certain cases involving registers.  A mismatch
+   We scan the blocks from their ends backwards, hoping to find a match, I.e.
+   insns are identical, except for certain cases involving registers.  A
+   mismatch between register number RX (used in block X) and RY (used in the
+   same way in block Y) can be handled in one of the following cases:
+   1. RX and RY are local to their respective blocks; they are set there and
+      die there.  If so, they can effectively be ignored.
+   2. RX and RY die in their blocks, but live at the start.  If any path
+      gets redirected through X instead of Y, the caller must emit
+      compensation code to move RY to RX.  If there are overlapping inputs,
+      the function resolve_input_conflict ensures that this can be done.
+      Information about these registers are tracked in the X_LOCAL, Y_LOCAL,
+      LOCAL_COUNT and LOCAL_RVALUE fields.
+   3. RX and RY live throughout their blocks, including the start and the end.
+      Either RX and RY must be identical, or we have to replace all uses in
+      block X with a new pseudo, which is stored in the INPUT_REG field.  The
+      caller can then use block X instead of block Y by copying RY to the new
+      pseudo.
+
+   The main entry point to this file is struct_equiv_block_eq.  This function
+   uses a struct equiv_info to accept some of its inputs, to keep track of its
+   internal state, to pass down to its helper functions, and to communicate
+   some of the results back to the caller.
+
+   Most scans will result in a failure to match a sufficient number of insns
+   to make any optimization worth while, therefore the process is geared more
+   to quick scanning rather than the ability to exactly backtrack when we
+   find a mismatch.  The information gathered is still meaningful to make a
+   preliminary decision if we want to do an optimization, we might only
+   slightly overestimate the number of matchable insns, and underestimate
+   the number of inputs an miss an input conflict.  Sufficient information
+   is gathered so that when we make another pass, we won't have to backtrack
+   at the same point.
+   Another issue is that information in memory attributes and/or REG_NOTES
+   might have to be merged or discarded to make a valid match.  We don't want
+   to discard such information when we are not certain that we want to merge
+   the two (partial) blocks.
+   For these reasons, struct_equiv_block_eq has to be called first with the
+   STRUCT_EQUIV_START bit set in the mode parameter.  This will calculate the
+   number of matched insns and the number and types of inputs.  If the
+   need_rerun field is set, the results are only tentative, and the caller
+   has to call again with STRUCT_EQUIV_RERUN till need_rerun is false in
+   order to get a reliable match.
+   To install the changes necessary for the match, the function has to be
+   called again with STRUCT_EQUIV_FINAL.
+
+   While scanning an insn, we process first all the SET_DESTs, then the
+   SET_SRCes, then the REG_NOTES, in order to keep the register liveness
+   information consistent.
+   If we were to mix up the order for sources / destinations in an insn where
+   a source is also a destination, we'd end up being mistaken to think that
+   the register is not live in the preceding insn.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "regs.h"
+#include "output.h"
+#include "insn-config.h"
+#include "flags.h"
+#include "recog.h"
+#include "tm_p.h"
+#include "target.h"
+#include "emit-rtl.h"
+#include "reload.h"
+
+static void merge_memattrs (rtx, rtx);
+static bool set_dest_equiv_p (rtx x, rtx y, struct equiv_info *info);
+static bool set_dest_addr_equiv_p (rtx x, rtx y, struct equiv_info *info);
+static void find_dying_inputs (struct equiv_info *info);
+static bool resolve_input_conflict (struct equiv_info *info);
+
+/* After reload, some moves, as indicated by SECONDARY_RELOAD_CLASS and
+   SECONDARY_MEMORY_NEEDED, cannot be done directly.  For our purposes, we
+   consider them impossible to generate after reload (even though some
+   might be synthesized when you throw enough code at them).
+   Since we don't know while processing a cross-jump if a local register
+   that is currently live will eventually be live and thus be an input,
+   we keep track of potential inputs that would require an impossible move
+   by using a prohibitively high cost for them.
+   This number, multiplied with the larger of STRUCT_EQUIV_MAX_LOCAL and
+   FIRST_PSEUDO_REGISTER, must fit in the input_cost field of
+   struct equiv_info.  */
+#define IMPOSSIBLE_MOVE_FACTOR 20000
+
+
+
+/* Removes the memory attributes of MEM expression
+   if they are not equal.  */
+
+void
+merge_memattrs (rtx x, rtx y)
+{
+  int i;
+  int j;
+  enum rtx_code code;
+  const char *fmt;
+
+  if (x == y)
+    return;
+  if (x == 0 || y == 0)
+    return;
+
+  code = GET_CODE (x);
+
+  if (code != GET_CODE (y))
+    return;
+
+  if (GET_MODE (x) != GET_MODE (y))
+    return;
+
+  if (code == MEM && MEM_ATTRS (x) != MEM_ATTRS (y))
+    {
+      if (! MEM_ATTRS (x))
+	MEM_ATTRS (y) = 0;
+      else if (! MEM_ATTRS (y))
+	MEM_ATTRS (x) = 0;
+      else
+	{
+	  rtx mem_size;
+
+	  if (MEM_ALIAS_SET (x) != MEM_ALIAS_SET (y))
+	    {
+	      set_mem_alias_set (x, 0);
+	      set_mem_alias_set (y, 0);
+	    }
+
+	  if (! mem_expr_equal_p (MEM_EXPR (x), MEM_EXPR (y)))
+	    {
+	      set_mem_expr (x, 0);
+	      set_mem_expr (y, 0);
+	      set_mem_offset (x, 0);
+	      set_mem_offset (y, 0);
+	    }
+	  else if (MEM_OFFSET (x) != MEM_OFFSET (y))
+	    {
+	      set_mem_offset (x, 0);
+	      set_mem_offset (y, 0);
+	    }
+
+	  if (!MEM_SIZE (x))
+	    mem_size = NULL_RTX;
+	  else if (!MEM_SIZE (y))
+	    mem_size = NULL_RTX;
+	  else
+	    mem_size = GEN_INT (MAX (INTVAL (MEM_SIZE (x)),
+				     INTVAL (MEM_SIZE (y))));
+	  set_mem_size (x, mem_size);
+	  set_mem_size (y, mem_size);
+
+	  set_mem_align (x, MIN (MEM_ALIGN (x), MEM_ALIGN (y)));
+	  set_mem_align (y, MEM_ALIGN (x));
+	}
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      switch (fmt[i])
+	{
+	case 'E':
+	  /* Two vectors must have the same length.  */
+	  if (XVECLEN (x, i) != XVECLEN (y, i))
+	    return;
+
+	  for (j = 0; j < XVECLEN (x, i); j++)
+	    merge_memattrs (XVECEXP (x, i, j), XVECEXP (y, i, j));
+
+	  break;
+
+	case 'e':
+	  merge_memattrs (XEXP (x, i), XEXP (y, i));
+	}
+    }
+  return;
+}
+
+/* In SET, assign the bit for the register number of REG the value VALUE.
+   If REG is a hard register, do so for all its constituent registers.
+   Return the number of registers that have become included (as a positive
+   number) or excluded (as a negative number).  */
+static int
+assign_reg_reg_set (regset set, rtx reg, int value)
+{
+  unsigned regno = REGNO (reg);
+  int nregs, i, old;
+
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      gcc_assert (!reload_completed);
+      nregs = 1;
+    }
+  else
+    nregs = hard_regno_nregs[regno][GET_MODE (reg)];
+  for (old = 0, i = nregs; --i >= 0; regno++)
+    {
+      if ((value != 0) == REGNO_REG_SET_P (set, regno))
+	continue;
+      if (value)
+	old++, SET_REGNO_REG_SET (set, regno);
+      else
+	old--, CLEAR_REGNO_REG_SET (set, regno);
+    }
+  return old;
+}
+
+/* Record state about current inputs / local registers / liveness
+   in *P.  */
+static inline void
+struct_equiv_make_checkpoint (struct struct_equiv_checkpoint *p,
+			      struct equiv_info *info)
+{
+  *p = info->cur;
+}
+
+/* Call struct_equiv_make_checkpoint (P, INFO) if the current partial block
+   is suitable to split off - i.e. there is no dangling cc0 user - and
+   if the current cost of the common instructions, minus the cost for
+   setting up the inputs, is higher than what has been recorded before
+   in CHECKPOINT[N].  Also, if we do so, confirm or cancel any pending
+   changes.  */
+static void
+struct_equiv_improve_checkpoint (struct struct_equiv_checkpoint *p,
+				 struct equiv_info *info)
+{
+#ifdef HAVE_cc0
+  if (reg_mentioned_p (cc0_rtx, info->cur.x_start)
+      && !sets_cc0_p (info->cur.x_start))
+    return;
+#endif
+  if (info->cur.input_count >= IMPOSSIBLE_MOVE_FACTOR)
+    return;
+  if (info->input_cost >= 0
+      ? (COSTS_N_INSNS(info->cur.ninsns - p->ninsns)
+	 > info->input_cost * (info->cur.input_count - p->input_count))
+      : info->cur.ninsns > p->ninsns && !info->cur.input_count)
+    {
+      if (info->check_input_conflict && ! resolve_input_conflict (info))
+	return;
+      /* We have a profitable set of changes.  If this is the final pass,
+	 commit them now.  Otherwise, we don't know yet if we can make any
+	 change, so put the old code back for now.  */
+      if (info->mode & STRUCT_EQUIV_FINAL)
+	confirm_change_group ();
+      else
+	cancel_changes (0);
+      struct_equiv_make_checkpoint (p, info);
+    }
+}
+
+/* Restore state about current inputs / local registers / liveness
+   from P.  */
+static void
+struct_equiv_restore_checkpoint (struct struct_equiv_checkpoint *p,
+				 struct equiv_info *info)
+{
+  info->cur.ninsns = p->ninsns;
+  info->cur.x_start = p->x_start;
+  info->cur.y_start = p->y_start;
+  info->cur.input_count = p->input_count;
+  info->cur.input_valid = p->input_valid;
+  while (info->cur.local_count > p->local_count)
+    {
+      info->cur.local_count--;
+      info->cur.version--;
+      if (REGNO_REG_SET_P (info->x_local_live,
+			   REGNO (info->x_local[info->cur.local_count])))
+	{
+	  assign_reg_reg_set (info->x_local_live,
+			      info->x_local[info->cur.local_count], 0);
+	  assign_reg_reg_set (info->y_local_live,
+			      info->y_local[info->cur.local_count], 0);
+	  info->cur.version--;
+	}
+    }
+  if (info->cur.version != p->version)
+    info->need_rerun = true;
+}
+
+
+/* Update register liveness to reflect that X is now life (if rvalue is
+   nonzero) or dead (if rvalue is zero) in INFO->x_block, and likewise Y
+   in INFO->y_block.  Return the number of registers the liveness of which
+   changed in each block (as a negative number if registers became dead).  */
+static int
+note_local_live (struct equiv_info *info, rtx x, rtx y, int rvalue)
+{
+  unsigned x_regno = REGNO (x);
+  unsigned y_regno = REGNO (y);
+  int x_nominal_nregs = (x_regno >= FIRST_PSEUDO_REGISTER
+			 ? 1 : hard_regno_nregs[x_regno][GET_MODE (x)]);
+  int y_nominal_nregs = (y_regno >= FIRST_PSEUDO_REGISTER
+			 ? 1 : hard_regno_nregs[y_regno][GET_MODE (y)]);
+  int x_change = assign_reg_reg_set (info->x_local_live, x, rvalue);
+  int y_change = assign_reg_reg_set (info->y_local_live, y, rvalue);
+
+  gcc_assert (x_nominal_nregs && y_nominal_nregs);
+  gcc_assert (x_change * y_nominal_nregs == y_change * x_nominal_nregs);
+  if (y_change)
+    {
+      if (reload_completed)
+	{
+	  unsigned x_regno ATTRIBUTE_UNUSED = REGNO (x);
+	  unsigned y_regno = REGNO (y);
+	  enum machine_mode x_mode = GET_MODE (x);
+
+	  if (SECONDARY_OUTPUT_RELOAD_CLASS (REGNO_REG_CLASS (y_regno),
+					     x_mode, x)
+	      != NO_REGS
+#ifdef SECONDARY_MEMORY_NEEDED
+	      || SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (y_regno),
+					  REGNO_REG_CLASS (x_regno), x_mode)
+#endif
+	      )
+	  y_change *= IMPOSSIBLE_MOVE_FACTOR;
+	}
+      info->cur.input_count += y_change;
+      info->cur.version++;
+    }
+  return x_change;
+}
+
+/* Check if *XP is equivalent to Y.  Until an an unreconcilable difference is
+   found, use in-group changes with validate_change on *XP to make register
+   assignments agree.  It is the (not necessarily direct) callers
+   responsibility to verify / confirm / cancel these changes, as appropriate.
+   RVALUE indicates if the processed piece of rtl is used as a destination, in
+   which case we can't have different registers being an input.  Returns
+   nonzero if the two blocks have been identified as equivalent, zero otherwise.
+   RVALUE == 0: destination
+   RVALUE == 1: source
+   RVALUE == -1: source, ignore SET_DEST of SET / clobber.  */
+bool
+rtx_equiv_p (rtx *xp, rtx y, int rvalue, struct equiv_info *info)
+{
+  rtx x = *xp;
+  enum rtx_code code;
+  int length;
+  const char *format;
+  int i;
+
+  if (!y || !x)
+    return x == y;
+  code = GET_CODE (y);
+  if (code != REG && x == y)
+    return true;
+  if (GET_CODE (x) != code
+      || GET_MODE (x) != GET_MODE (y))
+    return false;
+
+  /* ??? could extend to allow CONST_INT inputs.  */
+  switch (code)
+    {
+    case REG:
+      {
+	unsigned x_regno = REGNO (x);
+	unsigned y_regno = REGNO (y);
+	int x_common_live, y_common_live;
+
+	if (reload_completed
+	    && (x_regno >= FIRST_PSEUDO_REGISTER
+		|| y_regno >= FIRST_PSEUDO_REGISTER))
+	  {
+	    /* We should only see this in REG_NOTEs.  */
+	    gcc_assert (!info->live_update);
+	    /* Returning false will cause us to remove the notes.  */
+	    return false;
+	  }
+#ifdef STACK_REGS
+	/* After reg-stack, can only accept literal matches of stack regs.  */
+	if (info->mode & CLEANUP_POST_REGSTACK
+	    && (IN_RANGE (x_regno, FIRST_STACK_REG, LAST_STACK_REG)
+		|| IN_RANGE (y_regno, FIRST_STACK_REG, LAST_STACK_REG)))
+	  return x_regno == y_regno;
+#endif
+
+	/* If the register is a locally live one in one block, the
+	   corresponding one must be locally live in the other, too, and
+	   match of identical regnos doesn't apply.  */
+	if (REGNO_REG_SET_P (info->x_local_live, x_regno))
+	  {
+	    if (!REGNO_REG_SET_P (info->y_local_live, y_regno))
+	      return false;
+	  }
+	else if (REGNO_REG_SET_P (info->y_local_live, y_regno))
+	  return false;
+	else if (x_regno == y_regno)
+	  {
+	    if (!rvalue && info->cur.input_valid
+		&& (reg_overlap_mentioned_p (x, info->x_input)
+		    || reg_overlap_mentioned_p (x, info->y_input)))
+	      return false;
+
+	    /* Update liveness information.  */
+	    if (info->live_update
+		&& assign_reg_reg_set (info->common_live, x, rvalue))
+	      info->cur.version++;
+
+	    return true;
+	  }
+
+	x_common_live = REGNO_REG_SET_P (info->common_live, x_regno);
+	y_common_live = REGNO_REG_SET_P (info->common_live, y_regno);
+	if (x_common_live != y_common_live)
+	  return false;
+	else if (x_common_live)
+	  {
+	    if (! rvalue || info->input_cost < 0 || no_new_pseudos)
+	      return false;
+	    /* If info->live_update is not set, we are processing notes.
+	       We then allow a match with x_input / y_input found in a
+	       previous pass.  */
+	    if (info->live_update && !info->cur.input_valid)
+	      {
+		info->cur.input_valid = true;
+		info->x_input = x;
+		info->y_input = y;
+		info->cur.input_count += optimize_size ? 2 : 1;
+		if (info->input_reg
+		    && GET_MODE (info->input_reg) != GET_MODE (info->x_input))
+		  info->input_reg = NULL_RTX;
+		if (!info->input_reg)
+		  info->input_reg = gen_reg_rtx (GET_MODE (info->x_input));
+	      }
+	    else if ((info->live_update
+		      ? ! info->cur.input_valid : ! info->x_input)
+		     || ! rtx_equal_p (x, info->x_input)
+		     || ! rtx_equal_p (y, info->y_input))
+	      return false;
+	    validate_change (info->cur.x_start, xp, info->input_reg, 1);
+	  }
+	else
+	  {
+	    int x_nregs = (x_regno >= FIRST_PSEUDO_REGISTER
+			   ? 1 : hard_regno_nregs[x_regno][GET_MODE (x)]);
+	    int y_nregs = (y_regno >= FIRST_PSEUDO_REGISTER
+			   ? 1 : hard_regno_nregs[y_regno][GET_MODE (y)]);
+	    int size = GET_MODE_SIZE (GET_MODE (x));
+	    enum machine_mode x_mode = GET_MODE (x);
+	    unsigned x_regno_i, y_regno_i;
+	    int x_nregs_i, y_nregs_i, size_i;
+	    int local_count = info->cur.local_count;
+
+	    /* This might be a register local to each block.  See if we have
+	       it already registered.  */
+	    for (i = local_count - 1; i >= 0; i--)
+	      {
+		x_regno_i = REGNO (info->x_local[i]);
+		x_nregs_i = (x_regno_i >= FIRST_PSEUDO_REGISTER
+			     ? 1 : hard_regno_nregs[x_regno_i][GET_MODE (x)]);
+		y_regno_i = REGNO (info->y_local[i]);
+		y_nregs_i = (y_regno_i >= FIRST_PSEUDO_REGISTER
+			     ? 1 : hard_regno_nregs[y_regno_i][GET_MODE (y)]);
+		size_i = GET_MODE_SIZE (GET_MODE (info->x_local[i]));
+
+		/* If we have a new pair of registers that is wider than an
+		   old pair and enclosing it with matching offsets,
+		   remove the old pair.  If we find a matching, wider, old
+		   pair, use the old one.  If the width is the same, use the
+		   old one if the modes match, but the new if they don't.
+		   We don't want to get too fancy with subreg_regno_offset
+		   here, so we just test two straightforward cases each.  */
+		if (info->live_update
+		    && (x_mode != GET_MODE (info->x_local[i])
+			? size >= size_i : size > size_i))
+		  {
+		    /* If the new pair is fully enclosing a matching
+		       existing pair, remove the old one.  N.B. because
+		       we are removing one entry here, the check below
+		       if we have space for a new entry will succeed.  */
+		    if ((x_regno <= x_regno_i
+			 && x_regno + x_nregs >= x_regno_i + x_nregs_i
+			 && x_nregs == y_nregs && x_nregs_i == y_nregs_i
+			 && x_regno - x_regno_i == y_regno - y_regno_i)
+			|| (x_regno == x_regno_i && y_regno == y_regno_i
+			    && x_nregs >= x_nregs_i && y_nregs >= y_nregs_i))
+		      {
+			info->cur.local_count = --local_count;
+			info->x_local[i] = info->x_local[local_count];
+			info->y_local[i] = info->y_local[local_count];
+			continue;
+		      }
+		  }
+		else
+		  {
+
+		    /* If the new pair is fully enclosed within a matching
+		       existing pair, succeed.  */
+		    if (x_regno >= x_regno_i
+			&& x_regno + x_nregs <= x_regno_i + x_nregs_i
+			&& x_nregs == y_nregs && x_nregs_i == y_nregs_i
+			&& x_regno - x_regno_i == y_regno - y_regno_i)
+		      break;
+		    if (x_regno == x_regno_i && y_regno == y_regno_i
+			&& x_nregs <= x_nregs_i && y_nregs <= y_nregs_i)
+		      break;
+		}
+
+		/* Any other overlap causes a match failure.  */
+		if (x_regno + x_nregs > x_regno_i
+		    && x_regno_i + x_nregs_i > x_regno)
+		  return false;
+		if (y_regno + y_nregs > y_regno_i
+		    && y_regno_i + y_nregs_i > y_regno)
+		  return false;
+	      }
+	    if (i < 0)
+	      {
+		/* Not found.  Create a new entry if possible.  */
+		if (!info->live_update
+		    || info->cur.local_count >= STRUCT_EQUIV_MAX_LOCAL)
+		  return false;
+		info->x_local[info->cur.local_count] = x;
+		info->y_local[info->cur.local_count] = y;
+		info->cur.local_count++;
+		info->cur.version++;
+	      }
+	    note_local_live (info, x, y, rvalue);
+	  }
+	return true;
+      }
+    case SET:
+      gcc_assert (rvalue < 0);
+      /* Ignore the destinations role as a destination.  Still, we have
+	 to consider input registers embedded in the addresses of a MEM.
+	 N.B., we process the rvalue aspect of STRICT_LOW_PART /
+	 ZERO_EXTEND / SIGN_EXTEND along with their lvalue aspect.  */
+      if(!set_dest_addr_equiv_p (SET_DEST (x), SET_DEST (y), info))
+	return false;
+      /* Process source.  */
+      return rtx_equiv_p (&SET_SRC (x), SET_SRC (y), 1, info);
+    case PRE_MODIFY:
+      /* Process destination.  */
+      if (!rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 0, info))
+	return false;
+      /* Process source.  */
+      return rtx_equiv_p (&XEXP (x, 1), XEXP (y, 1), 1, info);
+    case POST_MODIFY:
+      {
+	rtx x_dest0, x_dest1;
+
+	/* Process destination.  */
+	x_dest0 = XEXP (x, 0);
+	gcc_assert (REG_P (x_dest0));
+	if (!rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 0, info))
+	  return false;
+	x_dest1 = XEXP (x, 0);
+	/* validate_change might have changed the destination.  Put it back
+	   so that we can do a proper match for its role a an input.  */
+	XEXP (x, 0) = x_dest0;
+	if (!rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 1, info))
+	  return false;
+	gcc_assert (x_dest1 == XEXP (x, 0));
+	/* Process source.  */
+	return rtx_equiv_p (&XEXP (x, 1), XEXP (y, 1), 1, info);
+      }
+    case CLOBBER:
+      gcc_assert (rvalue < 0);
+      return true;
+    /* Some special forms are also rvalues when they appear in lvalue
+       positions.  However, we must ont try to match a register after we
+       have already altered it with validate_change, consider the rvalue
+       aspect while we process the lvalue.  */
+    case STRICT_LOW_PART:
+    case ZERO_EXTEND:
+    case SIGN_EXTEND:
+      {
+	rtx x_inner, y_inner;
+	enum rtx_code code;
+	int change;
+
+	if (rvalue)
+	  break;
+	x_inner = XEXP (x, 0);
+	y_inner = XEXP (y, 0);
+	if (GET_MODE (x_inner) != GET_MODE (y_inner))
+	  return false;
+	code = GET_CODE (x_inner);
+	if (code != GET_CODE (y_inner))
+	  return false;
+	/* The address of a MEM is an input that will be processed during
+	   rvalue == -1 processing.  */
+	if (code == SUBREG)
+	  {
+	    if (SUBREG_BYTE (x_inner) != SUBREG_BYTE (y_inner))
+	      return false;
+	    x = x_inner;
+	    x_inner = SUBREG_REG (x_inner);
+	    y_inner = SUBREG_REG (y_inner);
+	    if (GET_MODE (x_inner) != GET_MODE (y_inner))
+	      return false;
+	    code = GET_CODE (x_inner);
+	    if (code != GET_CODE (y_inner))
+	      return false;
+	  }
+	if (code == MEM)
+	  return true;
+	gcc_assert (code == REG);
+	if (! rtx_equiv_p (&XEXP (x, 0), y_inner, rvalue, info))
+	  return false;
+	if (REGNO (x_inner) == REGNO (y_inner))
+	  {
+	    change = assign_reg_reg_set (info->common_live, x_inner, 1);
+	    info->cur.version++;
+	  }
+	else
+	  change = note_local_live (info, x_inner, y_inner, 1);
+	gcc_assert (change);
+	return true;
+      }
+    /* The AUTO_INC / POST_MODIFY / PRE_MODIFY sets are modelled to take
+       place during input processing, however, that is benign, since they
+       are paired with reads.  */
+    case MEM:
+      return !rvalue || rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), rvalue, info);
+    case POST_INC: case POST_DEC: case PRE_INC: case PRE_DEC:
+      return (rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 0, info)
+	      && rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 1, info));
+    case PARALLEL:
+      /* If this is a top-level PATTERN PARALLEL, we expect the caller to 
+	 have handled the SET_DESTs.  A complex or vector PARALLEL can be
+	 identified by having a mode.  */
+      gcc_assert (rvalue < 0 || GET_MODE (x) != VOIDmode);
+      break;
+    case LABEL_REF:
+      /* Check special tablejump match case.  */
+      if (XEXP (y, 0) == info->y_label)
+	return (XEXP (x, 0) == info->x_label);
+      /* We can't assume nonlocal labels have their following insns yet.  */
+      if (LABEL_REF_NONLOCAL_P (x) || LABEL_REF_NONLOCAL_P (y))
+	return XEXP (x, 0) == XEXP (y, 0);
+
+      /* Two label-refs are equivalent if they point at labels
+	 in the same position in the instruction stream.  */
+      return (next_real_insn (XEXP (x, 0))
+	      == next_real_insn (XEXP (y, 0)));
+    case SYMBOL_REF:
+      return XSTR (x, 0) == XSTR (y, 0);
+    /* Some rtl is guaranteed to be shared, or unique;  If we didn't match
+       EQ equality above, they aren't the same.  */
+    case CONST_INT:
+    case CODE_LABEL:
+      return false;
+    default:
+      break;
+    }
+
+  /* For commutative operations, the RTX match if the operands match in any
+     order.  */
+  if (targetm.commutative_p (x, UNKNOWN))
+    return ((rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), rvalue, info)
+	     && rtx_equiv_p (&XEXP (x, 1), XEXP (y, 1), rvalue, info))
+	    || (rtx_equiv_p (&XEXP (x, 0), XEXP (y, 1), rvalue, info)
+		&& rtx_equiv_p (&XEXP (x, 1), XEXP (y, 0), rvalue, info)));
+
+  /* Process subexpressions - this is similar to rtx_equal_p.  */
+  length = GET_RTX_LENGTH (code);
+  format = GET_RTX_FORMAT (code);
+
+  for (i = 0; i < length; ++i)
+    {
+      switch (format[i])
+	{
+	case 'w':
+	  if (XWINT (x, i) != XWINT (y, i))
+	    return false;
+	  break;
+	case 'n':
+	case 'i':
+	  if (XINT (x, i) != XINT (y, i))
+	    return false;
+	  break;
+	case 'V':
+	case 'E':
+	  if (XVECLEN (x, i) != XVECLEN (y, i))
+	    return false;
+	  if (XVEC (x, i) != 0)
+	    {
+	      int j;
+	      for (j = 0; j < XVECLEN (x, i); ++j)
+		{
+		  if (! rtx_equiv_p (&XVECEXP (x, i, j), XVECEXP (y, i, j),
+				     rvalue, info))
+		    return false;
+		}
+	    }
+	  break;
+	case 'e':
+	  if (! rtx_equiv_p (&XEXP (x, i), XEXP (y, i), rvalue, info))
+	    return false;
+	  break;
+	case 'S':
+	case 's':
+	  if ((XSTR (x, i) || XSTR (y, i))
+	      && (! XSTR (x, i) || ! XSTR (y, i)
+		  || strcmp (XSTR (x, i), XSTR (y, i))))
+	    return false;
+	  break;
+	case 'u':
+	  /* These are just backpointers, so they don't matter.  */
+	  break;
+	case '0':
+	case 't':
+	  break;
+	  /* It is believed that rtx's at this level will never
+	     contain anything but integers and other rtx's,
+	     except for within LABEL_REFs and SYMBOL_REFs.  */
+	default:
+	  gcc_unreachable ();
+	}
+    }
+  return true;
+}
+
+/* Do only the rtx_equiv_p SET_DEST processing for SETs and CLOBBERs.
+   Since we are scanning backwards, this the first step in processing each
+   insn.  Return true for success.  */
+static bool
+set_dest_equiv_p (rtx x, rtx y, struct equiv_info *info)
+{
+  if (!x || !y)
+    return x == y;
+  if (GET_CODE (x) != GET_CODE (y))
+    return false;
+  else if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
+    return rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 0, info);
+  else if (GET_CODE (x) == PARALLEL)
+    {
+      int j;
+
+      if (XVECLEN (x, 0) != XVECLEN (y, 0))
+	return false;
+      for (j = 0; j < XVECLEN (x, 0); ++j)
+	{
+	  rtx xe = XVECEXP (x, 0, j);
+	  rtx ye = XVECEXP (y, 0, j);
+
+	  if (GET_CODE (xe) != GET_CODE (ye))
+	    return false;
+	  if ((GET_CODE (xe) == SET || GET_CODE (xe) == CLOBBER)
+	      && ! rtx_equiv_p (&XEXP (xe, 0), XEXP (ye, 0), 0, info))
+	    return false;
+	}
+    }
+  return true;
+}
+
+/* Process MEMs in SET_DEST destinations.  We must not process this together
+   with REG SET_DESTs, but must do it separately, lest when we see
+   [(set (reg:SI foo) (bar))
+    (set (mem:SI (reg:SI foo) (baz)))]
+   struct_equiv_block_eq could get confused to assume that (reg:SI foo)
+   is not live before this instruction.  */
+static bool
+set_dest_addr_equiv_p (rtx x, rtx y, struct equiv_info *info)
+{
+  enum rtx_code code = GET_CODE (x);
+  int length;
+  const char *format;
+  int i;
+
+  if (code != GET_CODE (y))
+    return false;
+  if (code == MEM)
+    return rtx_equiv_p (&XEXP (x, 0), XEXP (y, 0), 1, info);
+
+  /* Process subexpressions.  */
+  length = GET_RTX_LENGTH (code);
+  format = GET_RTX_FORMAT (code);
+
+  for (i = 0; i < length; ++i)
+    {
+      switch (format[i])
+	{
+	case 'V':
+	case 'E':
+	  if (XVECLEN (x, i) != XVECLEN (y, i))
+	    return false;
+	  if (XVEC (x, i) != 0)
+	    {
+	      int j;
+	      for (j = 0; j < XVECLEN (x, i); ++j)
+		{
+		  if (! set_dest_addr_equiv_p (XVECEXP (x, i, j),
+					       XVECEXP (y, i, j), info))
+		    return false;
+		}
+	    }
+	  break;
+	case 'e':
+	  if (! set_dest_addr_equiv_p (XEXP (x, i), XEXP (y, i), info))
+	    return false;
+	  break;
+	default:
+	  break;
+	}
+    }
+  return true;
+}
+
+/* Check if the set of REG_DEAD notes attached to I1 and I2 allows us to
+   go ahead with merging I1 and I2, which otherwise look fine.
+   Inputs / local registers for the inputs of I1 and I2 have already been
+   set up.  */
+static bool
+death_notes_match_p (rtx i1 ATTRIBUTE_UNUSED, rtx i2 ATTRIBUTE_UNUSED,
+		     struct equiv_info *info ATTRIBUTE_UNUSED)
+{
+#ifdef STACK_REGS
+  /* If cross_jump_death_matters is not 0, the insn's mode
+     indicates whether or not the insn contains any stack-like regs.  */
+
+  if ((info->mode & CLEANUP_POST_REGSTACK) && stack_regs_mentioned (i1))
+    {
+      /* If register stack conversion has already been done, then
+	 death notes must also be compared before it is certain that
+	 the two instruction streams match.  */
+
+      rtx note;
+      HARD_REG_SET i1_regset, i2_regset;
+
+      CLEAR_HARD_REG_SET (i1_regset);
+      CLEAR_HARD_REG_SET (i2_regset);
+
+      for (note = REG_NOTES (i1); note; note = XEXP (note, 1))
+	if (REG_NOTE_KIND (note) == REG_DEAD && STACK_REG_P (XEXP (note, 0)))
+	  SET_HARD_REG_BIT (i1_regset, REGNO (XEXP (note, 0)));
+
+      for (note = REG_NOTES (i2); note; note = XEXP (note, 1))
+	if (REG_NOTE_KIND (note) == REG_DEAD && STACK_REG_P (XEXP (note, 0)))
+	  {
+	    unsigned regno = REGNO (XEXP (note, 0));
+	    int i;
+
+	    for (i = info->cur.local_count - 1; i >= 0; i--)
+	      if (regno == REGNO (info->y_local[i]))
+		{
+		  regno = REGNO (info->x_local[i]);
+		  break;
+		}
+	    SET_HARD_REG_BIT (i2_regset, regno);
+	  }
+
+      GO_IF_HARD_REG_EQUAL (i1_regset, i2_regset, done);
+
+      return false;
+
+    done:
+      ;
+    }
+#endif
+  return true;
+}
+
+/* Return true if I1 and I2 are equivalent and thus can be crossjumped.  */
+
+bool
+insns_match_p (rtx i1, rtx i2, struct equiv_info *info)
+{
+  int rvalue_change_start;
+  struct struct_equiv_checkpoint before_rvalue_change;
+
+  /* Verify that I1 and I2 are equivalent.  */
+  if (GET_CODE (i1) != GET_CODE (i2))
+    return false;
+
+  info->cur.x_start = i1;
+  info->cur.y_start = i2;
+
+  /* If this is a CALL_INSN, compare register usage information.
+     If we don't check this on stack register machines, the two
+     CALL_INSNs might be merged leaving reg-stack.c with mismatching
+     numbers of stack registers in the same basic block.
+     If we don't check this on machines with delay slots, a delay slot may
+     be filled that clobbers a parameter expected by the subroutine.
+
+     ??? We take the simple route for now and assume that if they're
+     equal, they were constructed identically.  */
+
+  if (CALL_P (i1))
+    {
+      if (SIBLING_CALL_P (i1) != SIBLING_CALL_P (i2)
+	  || ! set_dest_equiv_p (PATTERN (i1), PATTERN (i2), info)
+	  || ! set_dest_equiv_p (CALL_INSN_FUNCTION_USAGE (i1),
+				 CALL_INSN_FUNCTION_USAGE (i2), info)
+	  || ! rtx_equiv_p (&CALL_INSN_FUNCTION_USAGE (i1),
+			    CALL_INSN_FUNCTION_USAGE (i2), -1, info))
+	{
+	  cancel_changes (0);
+	  return false;
+	}
+    }
+  else if (INSN_P (i1))
+    {
+      if (! set_dest_equiv_p (PATTERN (i1), PATTERN (i2), info))
+	{
+	  cancel_changes (0);
+	  return false;
+	}
+    }
+  rvalue_change_start = num_validated_changes ();
+  struct_equiv_make_checkpoint (&before_rvalue_change, info);
+  /* Check death_notes_match_p *after* the inputs have been processed,
+     so that local inputs will already have been set up.  */
+  if (! INSN_P (i1)
+      || (!bitmap_bit_p (info->equiv_used, info->cur.ninsns)
+	  && rtx_equiv_p (&PATTERN (i1), PATTERN (i2), -1, info)
+	  && death_notes_match_p (i1, i2, info)
+	  && verify_changes (0)))
+    return true;
+
+  /* Do not do EQUIV substitution after reload.  First, we're undoing the
+     work of reload_cse.  Second, we may be undoing the work of the post-
+     reload splitting pass.  */
+  /* ??? Possibly add a new phase switch variable that can be used by
+     targets to disallow the troublesome insns after splitting.  */
+  if (!reload_completed)
+    {
+      rtx equiv1, equiv2;
+
+      cancel_changes (rvalue_change_start);
+      struct_equiv_restore_checkpoint (&before_rvalue_change, info);
+
+      /* The following code helps take care of G++ cleanups.  */
+      equiv1 = find_reg_equal_equiv_note (i1);
+      equiv2 = find_reg_equal_equiv_note (i2);
+      if (equiv1 && equiv2
+	  /* If the equivalences are not to a constant, they may
+	     reference pseudos that no longer exist, so we can't
+	     use them.  */
+	  && (! reload_completed
+	      || (CONSTANT_P (XEXP (equiv1, 0))
+		  && rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0)))))
+	{
+	  rtx s1 = single_set (i1);
+	  rtx s2 = single_set (i2);
+
+	  if (s1 != 0 && s2 != 0)
+	    {
+	      validate_change (i1, &SET_SRC (s1), XEXP (equiv1, 0), 1);
+	      validate_change (i2, &SET_SRC (s2), XEXP (equiv2, 0), 1);
+	      /* Only inspecting the new SET_SRC is not good enough,
+		 because there may also be bare USEs in a single_set
+		 PARALLEL.  */
+	      if (rtx_equiv_p (&PATTERN (i1), PATTERN (i2), -1, info)
+		  && death_notes_match_p (i1, i2, info)
+		  && verify_changes (0))
+		{
+		  /* Mark this insn so that we'll use the equivalence in
+		     all subsequent passes.  */
+		  bitmap_set_bit (info->equiv_used, info->cur.ninsns);
+		  return true;
+		}
+	    }
+	}
+    }
+
+  cancel_changes (0);
+  return false;
+}
+
+static bool
+struct_equiv_regs_eq_p (struct equiv_info *info)
+{
+#ifdef STACK_REGS
+  if (info->mode & CLEANUP_POST_REGSTACK)
+    {
+      regset_head diff;
+      unsigned regnum;
+      bitmap_iterator rsi;
+
+      INIT_REG_SET (&diff);
+      bitmap_xor (&diff,
+		  info->x_block->il.rtl->global_live_at_end,
+		  info->y_block->il.rtl->global_live_at_end);
+      EXECUTE_IF_SET_IN_BITMAP (&diff, 0, regnum, rsi)
+	{
+	  if (regnum < FIRST_STACK_REG || regnum > LAST_STACK_REG)
+	    return false;
+	}
+      return true;
+    }
+#endif
+  return (REG_SET_EQUAL_P (info->x_block->il.rtl->global_live_at_end,
+			   info->y_block->il.rtl->global_live_at_end));
+}
+
+/* Set up mode and register information in INFO.  Return true for success.
+   Nonzero CHECK_REGS_EQ indicates that we might be called with blocks that
+   have non-matching successor sets, and thus need to check their live_at_end
+   regsets for match in the first pass.  */
+bool
+struct_equiv_init (int mode, struct equiv_info *info, bool check_regs_eq)
+{
+  info->mode = mode;
+  if (check_regs_eq && (mode & STRUCT_EQUIV_START))
+    {
+      if (!struct_equiv_regs_eq_p (info))
+	return false;
+    }
+  else if (mode & STRUCT_EQUIV_FINAL)
+    gcc_assert (struct_equiv_regs_eq_p (info));
+  if (mode & STRUCT_EQUIV_START)
+    {
+      info->x_input = info->y_input = info->input_reg = NULL_RTX;
+      info->equiv_used = ALLOC_REG_SET (&reg_obstack);
+      info->check_input_conflict = false;
+    }
+  info->had_input_conflict = false;
+  info->cur.ninsns = info->cur.version = 0;
+  info->cur.local_count = info->cur.input_count = 0;
+  info->cur.x_start = info->cur.y_start = NULL_RTX;
+  info->x_label = info->y_label = NULL_RTX;
+  info->need_rerun = false;
+  info->live_update = true;
+  info->cur.input_valid = false;
+  info->common_live = ALLOC_REG_SET (&reg_obstack);
+  info->x_local_live = ALLOC_REG_SET (&reg_obstack);
+  info->y_local_live = ALLOC_REG_SET (&reg_obstack);
+  COPY_REG_SET (info->common_live, info->x_block->il.rtl->global_live_at_end);
+  struct_equiv_make_checkpoint (&info->best_match, info);
+  return true;
+}
+
+/* Insns XI and YI have been matched.  Merge memory attributes and reg
+   notes.  */
+static void
+struct_equiv_merge (rtx xi, rtx yi, struct equiv_info *info)
+{
+  rtx equiv1, equiv2;
+
+  merge_memattrs (xi, yi);
+
+  /* If the merged insns have different REG_EQUAL notes, then
+     remove them.  */
+  info->live_update = false;
+  equiv1 = find_reg_equal_equiv_note (xi);
+  equiv2 = find_reg_equal_equiv_note (yi);
+  if (equiv1 && !equiv2)
+    remove_note (xi, equiv1);
+  else if (!equiv1 && equiv2)
+    remove_note (yi, equiv2);
+  else if (equiv1 && equiv2
+  	 && !rtx_equiv_p (&XEXP (equiv1, 0), XEXP (equiv2, 0),
+  			   1, info))
+    {
+      remove_note (xi, equiv1);
+      remove_note (yi, equiv2);
+    }
+  info->live_update = true;
+}
+
+/* Return number of matched insns.
+   This function must be called up to three times for a successful cross-jump
+   match:
+   first to find out which instructions do match.  While trying to match
+   another instruction that doesn't match, we destroy information in info
+   about the actual inputs.  So if there have been any before the last
+   match attempt, we need to call this function again to recompute the
+   actual inputs up to the actual start of the matching sequence.
+   When we are then satisfied that the cross-jump is worthwhile, we
+   call this function a third time to make any changes needed to make the
+   sequences match: apply equivalences, remove non-matching
+   notes and merge memory attributes.  */
+int
+struct_equiv_block_eq (int mode, struct equiv_info *info)
+{
+  rtx x_stop, y_stop;
+  rtx xi, yi;
+  int i;
+
+  if (mode & STRUCT_EQUIV_START)
+    {
+      x_stop = BB_HEAD (info->x_block);
+      y_stop = BB_HEAD (info->y_block);
+      if (!x_stop || !y_stop)
+	return 0;
+    }
+  else
+    {
+      x_stop = info->cur.x_start;
+      y_stop = info->cur.y_start;
+    }
+  struct_equiv_init (mode, info, false);
+
+  /* Skip simple jumps at the end of the blocks.  Complex jumps still
+     need to be compared for equivalence, which we'll do below.  */
+
+  xi = BB_END (info->x_block);
+  if (onlyjump_p (xi)
+      || (returnjump_p (xi) && !side_effects_p (PATTERN (xi))))
+    {
+      info->cur.x_start = xi;
+      xi = PREV_INSN (xi);
+    }
+
+  yi = BB_END (info->y_block);
+  if (onlyjump_p (yi)
+      || (returnjump_p (yi) && !side_effects_p (PATTERN (yi))))
+    {
+      info->cur.y_start = yi;
+      /* Count everything except for unconditional jump as insn.  */
+      /* ??? Is it right to count unconditional jumps with a clobber?
+	 Should we count conditional returns?  */
+      if (!simplejump_p (yi) && !returnjump_p (yi) && info->cur.x_start)
+	info->cur.ninsns++;
+      yi = PREV_INSN (yi);
+    }
+
+  if (mode & STRUCT_EQUIV_MATCH_JUMPS)
+    {
+      /* The caller is expected to have compared the jumps already, but we
+	 need to match them again to get any local registers and inputs.  */
+      gcc_assert (!info->cur.x_start == !info->cur.y_start);
+      if (info->cur.x_start)
+	{
+	  if (any_condjump_p (info->cur.x_start)
+	      ? !condjump_equiv_p (info, false)
+	      : !insns_match_p (info->cur.x_start, info->cur.y_start, info))
+	    gcc_unreachable ();
+	}
+      else if (any_condjump_p (xi) && any_condjump_p (yi))
+	{
+	  info->cur.x_start = xi;
+	  info->cur.y_start = yi;
+	  xi = PREV_INSN (xi);
+	  yi = PREV_INSN (yi);
+	  info->cur.ninsns++;
+	  if (!condjump_equiv_p (info, false))
+	    gcc_unreachable ();
+	}
+      if (info->cur.x_start && info->mode & STRUCT_EQUIV_FINAL)
+	struct_equiv_merge (info->cur.x_start, info->cur.y_start, info);
+    }
+
+  struct_equiv_improve_checkpoint (&info->best_match, info);
+  info->x_end = xi;
+  info->y_end = yi;
+  if (info->cur.x_start != x_stop)
+    for (;;)
+      {
+	/* Ignore notes.  */
+	while (!INSN_P (xi) && xi != x_stop)
+	  xi = PREV_INSN (xi);
+
+	while (!INSN_P (yi) && yi != y_stop)
+	  yi = PREV_INSN (yi);
+
+	if (!insns_match_p (xi, yi, info))
+	  break;
+	if (INSN_P (xi))
+	  {
+	    if (info->mode & STRUCT_EQUIV_FINAL)
+	      struct_equiv_merge (xi, yi, info);
+	    info->cur.ninsns++;
+	    struct_equiv_improve_checkpoint (&info->best_match, info);
+	  }
+	if (xi == x_stop || yi == y_stop)
+	  {
+	    /* If we reached the start of at least one of the blocks, but
+	       best_match hasn't been advanced back to the first valid insn
+	       yet, represent the increased benefit of completing the block
+	       as an increased instruction count.  */
+	    if (info->best_match.x_start != info->cur.x_start
+		&& (xi == BB_HEAD (info->x_block)
+		    || yi == BB_HEAD (info->y_block)))
+	      {
+		info->cur.ninsns++;
+		struct_equiv_improve_checkpoint (&info->best_match, info);
+		info->cur.ninsns--;
+		if (info->best_match.ninsns > info->cur.ninsns)
+		  info->best_match.ninsns = info->cur.ninsns;
+	      }
+	    break;
+	  }
+	xi = PREV_INSN (xi);
+	yi = PREV_INSN (yi);
+      }
+
+  /* If we failed to match an insn, but had some changes registered from
+     trying to make the insns match, we need to cancel these changes now.  */
+  cancel_changes (0);
+  /* Restore to best_match to get the sequence with the best known-so-far
+     cost-benefit difference.  */
+  struct_equiv_restore_checkpoint (&info->best_match, info);
+
+  /* Include preceding notes and labels in the cross-jump / if-conversion.
+     One, this may bring us to the head of the blocks.
+     Two, it keeps line number notes as matched as may be.  */
+  if (info->cur.ninsns)
+    {
+      xi = info->cur.x_start;
+      yi = info->cur.y_start;
+      while (xi != x_stop && !INSN_P (PREV_INSN (xi)))
+	xi = PREV_INSN (xi);
+
+      while (yi != y_stop && !INSN_P (PREV_INSN (yi)))
+	yi = PREV_INSN (yi);
+
+      info->cur.x_start = xi;
+      info->cur.y_start = yi;
+    }
+
+  if (!info->cur.input_valid)
+    info->x_input = info->y_input = info->input_reg = NULL_RTX;
+  if (!info->need_rerun)
+    {
+      find_dying_inputs (info);
+      if (info->mode & STRUCT_EQUIV_FINAL)
+	{
+	  if (info->check_input_conflict && ! resolve_input_conflict (info))
+	    gcc_unreachable ();
+	}
+      else
+	{
+	  bool input_conflict = info->had_input_conflict;
+
+	  if (!input_conflict
+	      && info->dying_inputs > 1
+	      && bitmap_intersect_p (info->x_local_live, info->y_local_live))
+	    {
+	      regset_head clobbered_regs;
+
+	      INIT_REG_SET (&clobbered_regs);
+	      for (i = 0; i < info->cur.local_count; i++)
+		{
+		  if (assign_reg_reg_set (&clobbered_regs, info->y_local[i], 0))
+		    {
+		      input_conflict = true;
+		      break;
+		    }
+		  assign_reg_reg_set (&clobbered_regs, info->x_local[i], 1);
+		}
+	      CLEAR_REG_SET (&clobbered_regs);
+	    }
+	  if (input_conflict && !info->check_input_conflict)
+	    info->need_rerun = true;
+	  info->check_input_conflict = input_conflict;
+	}
+    }
+
+  if (info->mode & STRUCT_EQUIV_NEED_FULL_BLOCK
+      && (info->cur.x_start != x_stop || info->cur.y_start != y_stop))
+    return 0;
+  return info->cur.ninsns;
+}
+
+/* For each local register, set info->local_rvalue to true iff the register
+   is a dying input.  Store the total number of these in info->dying_inputs.  */
+static void
+find_dying_inputs (struct equiv_info *info)
+{
+  int i;
+
+  info->dying_inputs = 0;
+  for (i = info->cur.local_count-1; i >=0; i--)
+    {
+      rtx x = info->x_local[i];
+      unsigned regno = REGNO (x);
+      int nregs = (regno >= FIRST_PSEUDO_REGISTER
+		   ? 1 : hard_regno_nregs[regno][GET_MODE (x)]);
+
+      for (info->local_rvalue[i] = false; nregs > 0; regno++, --nregs)
+	if (REGNO_REG_SET_P (info->x_local_live, regno))
+	  {
+	    info->dying_inputs++;
+	    info->local_rvalue[i] = true;
+	    break;
+	  }
+    }
+}
+
+/* For each local register that is a dying input, y_local[i] will be
+   copied to x_local[i].  We'll do this in ascending order.  Try to
+   re-order the locals to avoid conflicts like r3 = r2; r4 = r3; .
+   Return true iff the re-ordering is successful, or not necessary.  */
+static bool
+resolve_input_conflict (struct equiv_info *info)
+{
+  int i, j, end;
+  int nswaps = 0;
+  rtx save_x_local[STRUCT_EQUIV_MAX_LOCAL];
+  rtx save_y_local[STRUCT_EQUIV_MAX_LOCAL];
+
+  find_dying_inputs (info);
+  if (info->dying_inputs <= 1)
+    return true;
+  memcpy (save_x_local, info->x_local, sizeof save_x_local);
+  memcpy (save_y_local, info->y_local, sizeof save_y_local);
+  end = info->cur.local_count - 1;
+  for (i = 0; i <= end; i++)
+    {
+      /* Cycle detection with regsets is expensive, so we just check that
+	 we don't exceed the maximum number of swaps needed in the acyclic
+	 case.  */
+      int max_swaps = end - i;
+
+      /* Check if x_local[i] will be clobbered.  */
+      if (!info->local_rvalue[i])
+	continue;
+      /* Check if any later value needs to be copied earlier.  */
+      for (j = i + 1; j <= end; j++)
+	{
+	  rtx tmp;
+
+	  if (!info->local_rvalue[j])
+	    continue;
+	  if (!reg_overlap_mentioned_p (info->x_local[i], info->y_local[j]))
+	    continue;
+	  if (--max_swaps < 0)
+	    {
+	      memcpy (info->x_local, save_x_local, sizeof save_x_local);
+	      memcpy (info->y_local, save_y_local, sizeof save_y_local);
+	      return false;
+	    }
+	  nswaps++;
+	  tmp = info->x_local[i];
+	  info->x_local[i] = info->x_local[j];
+	  info->x_local[j] = tmp;
+	  tmp = info->y_local[i];
+	  info->y_local[i] = info->y_local[j];
+	  info->y_local[j] = tmp;
+	  j = i;
+	}
+    }
+  info->had_input_conflict = true;
+  if (dump_file && nswaps)
+    fprintf (dump_file, "Resolved input conflict, %d %s.\n",
+	     nswaps, nswaps == 1 ? "swap" : "swaps");
+  return true;
+}
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/testsuite/gcc.c-torture/execute/arith-rand-ll.c gcc-4.1.1/gcc/testsuite/gcc.c-torture/execute/arith-rand-ll.c
--- gcc-4.1.1.orig/gcc/testsuite/gcc.c-torture/execute/arith-rand-ll.c	2002-07-01 16:12:49.000000000 +0100
+++ gcc-4.1.1/gcc/testsuite/gcc.c-torture/execute/arith-rand-ll.c	2006-08-10 09:56:05.000000000 +0100
@@ -79,7 +79,7 @@ 	if ((unsigned int) xx << 1 == 0 && yy =
 	  continue;
 	r1 = xx / yy;
 	r2 = xx % yy;
-	if (ABS (r2) >= (unsigned int) ABS (yy) || (signed int) (r1 * yy + r2) != xx)
+	if (ABS (r2) >= (unsigned int) ABS (yy) || (signed int) (r1 * yy + r2) != xx || ((xx < 0) != (r2 < 0) && r2))
 	  abort ();
       }
       { unsigned short xx = x, yy = y, r1, r2;
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/testsuite/g++.dg/eh/alias1.C gcc-4.1.1/gcc/testsuite/g++.dg/eh/alias1.C
--- gcc-4.1.1.orig/gcc/testsuite/g++.dg/eh/alias1.C	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/gcc/testsuite/g++.dg/eh/alias1.C	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,42 @@
+// { dg-do run }
+// { dg-options "-O3" }
+/* PR c++/28139: disjoint alias sets for the store from
+   expand_start_catch_block than for loading P result in P being loaded
+   before it is initialized for sh-elf.  */
+
+extern "C" {
+void exit (int) __attribute__ ((noreturn));
+}
+
+int i_glob = 42;
+int *p0 = &i_glob;
+typedef int **ipp;
+
+void
+g (int i)
+{
+  if (!i_glob)
+    exit ((int)(long long) &i);
+}
+
+static void
+h ()
+{
+  throw &p0;
+}
+
+int
+main()
+{
+  g (42);
+  try
+    {
+     h ();
+    }
+  catch (const ipp &p)
+    {
+      if (**p != 42)
+	exit (1);
+    }
+  return 0;
+}
diff -ruNdp -F'(' gcc-4.1.1.orig/gcc/version.c gcc-4.1.1/gcc/version.c
--- gcc-4.1.1.orig/gcc/version.c	2005-03-16 06:04:10.000000000 +0000
+++ gcc-4.1.1/gcc/version.c	2006-08-10 09:56:05.000000000 +0100
@@ -8,7 +8,7 @@
    in parentheses.  You may also wish to include a number indicating
    the revision of your modified compiler.  */
 
-#define VERSUFFIX ""
+#define VERSUFFIX " (STMicroelectronics Special) [build "__DATE__"]"
 
 /* This is the location of the online document giving instructions for
    reporting bugs.  If you distribute a modified version of GCC,
@@ -17,7 +17,7 @@    reporting bugs to you, not us.  (You 
    forward us bugs reported to you, if you determine that they are
    not bugs in your modifications.)  */
 
-const char bug_report_url[] = "<URL:http://gcc.gnu.org/bugs.html>";
+const char bug_report_url[] = "<file://doc/docbug.htm> on the installation CD";
 
 /* The complete version string, assembled from several pieces.
    BASEVER, DATESTAMP, and DEVPHASE are defined by the Makefile.  */
diff -ruNdp -F'(' gcc-4.1.1.orig/include/ChangeLog.STM gcc-4.1.1/include/ChangeLog.STM
--- gcc-4.1.1.orig/include/ChangeLog.STM	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/include/ChangeLog.STM	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,8 @@
+2006-05-03  Andrew Stubbs  <andrew.stubbs@st.com>
+            J"orn Rennecke <joern.rennecke@st.com>
+
+	* libiberty.h (make_relative_prefix_ignore_links): Declare.
+
+2006-03-27  Andrew Stubbs  <andrew.stubbs@st.com>
+
+	* libiberty.h: Add support for cygpath.c.
diff -ruNdp -F'(' gcc-4.1.1.orig/include/libiberty.h gcc-4.1.1/include/libiberty.h
--- gcc-4.1.1.orig/include/libiberty.h	2005-09-26 21:55:10.000000000 +0100
+++ gcc-4.1.1/include/libiberty.h	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Function declarations for libiberty.
 
    Copyright 2001, 2002, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2006 STMicroelectronics
    
    Note - certain prototypes declared in this header file are for
    functions whoes implementation copyright does not belong to the
@@ -197,6 +198,13 @@ extern long get_run_time (void);
 extern char *make_relative_prefix (const char *, const char *,
                                    const char *) ATTRIBUTE_MALLOC;
 
+/* Generate a relocated path to some installation directory without
+   attempting to follow any soft links.  Allocates
+   return value using malloc.  */
+
+extern char *make_relative_prefix_ignore_links (const char *, const char *,
+						const char *) ATTRIBUTE_MALLOC;
+
 /* Choose a temporary directory to use for scratch files.  */
 
 extern char *choose_temp_base (void) ATTRIBUTE_MALLOC;
@@ -586,5 +594,28 @@    (char *) memcpy (libiberty_nptr, libi
 }
 #endif
 
+#ifdef __MINGW32__
+char *cygpath (const char *path);
+void cygpath_replace (char **path);
+
+/* The following macros are just to prevent putting #ifdef MINGW everywhere.
+   You still need to if you don't want to overwite the original pointer.  */
+
+/* Reassign the pointer PATH without freeing anything.  */
+#define CYGPATH(path) do {path = cygpath (path);} while(0)
+
+/* Free memory. Intended to be used in conjunction with CYGPATH().  */
+#define CYGPATH_FREE(path) free (path)
+
+/* Reassign the pointer PATH and free the previous content.  */
+#define CYGPATH_REPLACE(path) cygpath_replace (path)
+
+#else
+/* If these were properly empty statements then there might be warnings
+   which would kill a -Werror build.  */
+#define CYGPATH(path) do {} while (0)
+#define CYGPATH_FREE(path) do {} while (0)
+#define CYGPATH_REPLACE(path) do {} while (0)
+#endif
 
 #endif /* ! defined (LIBIBERTY_H) */
diff -ruNdp -F'(' gcc-4.1.1.orig/libcpp/ChangeLog.STM gcc-4.1.1/libcpp/ChangeLog.STM
--- gcc-4.1.1.orig/libcpp/ChangeLog.STM	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/libcpp/ChangeLog.STM	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,9 @@
+2006-03-27  Andrew Stubbs  <andrew.stubbs@st.com>
+
+	* files.c (open_file, pch_open_file): Remove CYGDRIVE markers.
+	Add Cygwin pathname support for MinGW.
+
+2006-03-10  J"orn Rennecke <joern.rennecke@st.com>
+
+	* files.c (open_file, pch_open_file): Add CYGDRIVE markers.
+
diff -ruNdp -F'(' gcc-4.1.1.orig/libcpp/files.c gcc-4.1.1/libcpp/files.c
--- gcc-4.1.1.orig/libcpp/files.c	2005-11-04 02:10:19.000000000 +0000
+++ gcc-4.1.1/libcpp/files.c	2006-08-10 09:56:05.000000000 +0100
@@ -6,6 +6,7 @@    Copyright (C) 1986, 1987, 1989, 1992,
    Adapted to ANSI C, Richard Stallman, Jan 1987
    Split out of cpplib.c, Zack Weinberg, Oct 1998
    Reimplemented, Neil Booth, Jul 2003
+   Copyright (c) 2006  STMicroelectronics.
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
@@ -206,7 +207,12 @@   if (file->path[0] == '\0')
       set_stdin_to_binary_mode ();
     }
   else
-    file->fd = open (file->path, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
+    {
+      char *filename = file->path;
+      CYGPATH (filename);
+      file->fd = open (filename, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
+      CYGPATH_FREE (filename);
+    }
 
   if (file->fd != -1)
     {
@@ -259,6 +265,16 @@   pchname = XNEWVEC (char, len);
   memcpy (pchname, path, flen);
   memcpy (pchname + flen, extension, sizeof (extension));
 
+#ifdef __MINGW32__
+    {
+      char *temp = cygpath (pchname);
+      len = strlen (temp) + 1;
+      XRESIZEVEC (char, pchname, len);
+      memcpy (pchname, temp, len);
+      free (temp);
+    }
+#endif
+  
   if (stat (pchname, &st) == 0)
     {
       DIR *pchdir;
diff -ruNdp -F'(' gcc-4.1.1.orig/libiberty/ChangeLog.STM gcc-4.1.1/libiberty/ChangeLog.STM
--- gcc-4.1.1.orig/libiberty/ChangeLog.STM	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/libiberty/ChangeLog.STM	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,22 @@
+2006-05-15  Andrew Stubbs  <andrew.stubbs@st.com>
+
+	* cygpath.c (cygpath): Convert pathnames consisting only of a
+	drive specifier to a valid directory (e.g 'c:' -> 'c:/').
+
+2006-05-03  Andrew Stubbs  <andrew.stubbs@st.com>
+            J"orn Rennecke <joern.rennecke@st.com>
+
+	* make-relative-prefix.c (make_relative_prefix_1): New function,
+	broken out of make_relative_prefix.  Make link resolution dependent
+	on new parameter.
+	(make_relative_prefix): Use make_relative_prefix_1.
+	(make_relative_prefix_ignore_links): New function.
+
+2006-03-27  Andrew Stubbs  <andrew.stubbs@st.com>
+
+libiberty/
+	* cygpath.c: New file.
+	* config/mh-mingw: New file.
+	* configure.ac: Add mh-mingw makefile fragment when host is MinGW.
+	* configure: Regenerate.
+	* Makefile.in: Add cygpath.[co] .
diff -ruNdp -F'(' gcc-4.1.1.orig/libiberty/config/mh-mingw gcc-4.1.1/libiberty/config/mh-mingw
--- gcc-4.1.1.orig/libiberty/config/mh-mingw	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/libiberty/config/mh-mingw	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1 @@
+EXTRA_OFILES=cygpath.o
diff -ruNdp -F'(' gcc-4.1.1.orig/libiberty/configure gcc-4.1.1/libiberty/configure
--- gcc-4.1.1.orig/libiberty/configure	2005-07-22 04:14:38.000000000 +0100
+++ gcc-4.1.1/libiberty/configure	2006-08-10 09:56:05.000000000 +0100
@@ -3532,6 +3532,7 @@ case "${host}" in
   *-*-freebsd2.2.[012])	frag=mh-fbsd21 ;;
   i370-*-opened*)       frag=mh-openedition ;;
   i[34567]86-*-windows*)	frag=mh-windows ;;
+  *-*-mingw*)		frag=mh-mingw ;;
 esac
 
 if [ -n "${frag}" ]; then
diff -ruNdp -F'(' gcc-4.1.1.orig/libiberty/configure.ac gcc-4.1.1/libiberty/configure.ac
--- gcc-4.1.1.orig/libiberty/configure.ac	2005-07-22 04:14:38.000000000 +0100
+++ gcc-4.1.1/libiberty/configure.ac	2006-08-10 09:56:05.000000000 +0100
@@ -166,6 +166,7 @@ case "${host}" in
   *-*-freebsd2.2.[[012]])	frag=mh-fbsd21 ;;
   i370-*-opened*)       frag=mh-openedition ;;
   i[[34567]]86-*-windows*)	frag=mh-windows ;;
+  *-*-mingw*)		frag=mh-mingw ;;
 esac
 
 if [[ -n "${frag}" ]]; then
diff -ruNdp -F'(' gcc-4.1.1.orig/libiberty/cygpath.c gcc-4.1.1/libiberty/cygpath.c
--- gcc-4.1.1.orig/libiberty/cygpath.c	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/libiberty/cygpath.c	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,358 @@
+/* Basic Cygwin pathname support for MinGW.
+
+   Copyright (C) 2006 STMicroelectronics
+
+   This file is part of the libiberty library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.
+
+
+   This file implements a limited amount of support for Cygwin paths.
+   It is intended for use by MinGW programs that must interact with Cygwin.
+
+   It is limited to absolute paths only.  I.e. Those beginning with Cygwin
+   mounts, such as /cygdrive/...  See the comment on cygpath() below.  */
+
+#include "libiberty.h"
+#include <string.h>
+#include <ctype.h>
+#include <windows.h>
+
+
+/* These are all the possible settings for the ST_CYGPATH_MODE
+   environment variable.  */
+static enum
+{
+  mode_unset,
+  mode_off,
+  mode_normal,
+  mode_full
+} mode = mode_unset;
+
+
+/* These are the values extracted from the registry.
+   They are extracted the first time cygpath is called.  */
+static const char *cygdrive = NULL;
+static struct mount
+{
+  /* The name of the Cygwin mount point.  E.g. "/usr/bin"  */
+  char *mount;
+
+  /* The actual Windows path that the mount translates to.  */
+  char *actual;
+
+  struct mount *next;
+} *mounts = NULL;
+
+
+/* Read a string from the Windows Registry.
+   KEY should be a valid handle from RegOpenKeyEx().
+   NAME should be the name of the value within the key.
+   The value should be of type REG_SZ.
+   If the value does not exist, is of the wrong typei, or another error
+   occurs, then NULL is returned.
+   Otherwise a malloced string is returned.  */
+static char *
+read_string_from_registry (HKEY key, const char *name)
+{
+  DWORD valuetype = REG_NONE;
+  DWORD valuesize = 0;
+  char *value = NULL;
+
+  if (RegQueryValueEx (key, name, NULL, &valuetype,
+		       NULL, &valuesize) == ERROR_SUCCESS
+      && valuetype == REG_SZ)
+    {
+      value = xmalloc (valuesize);
+      if (RegQueryValueEx (key, name, NULL, &valuetype, (unsigned char *)value,
+			   &valuesize) != ERROR_SUCCESS)
+	{
+	  free (value);
+	  value = NULL;
+	}
+    }
+
+  return value;
+}
+
+
+/* Fill in the mounts list (mounts is defined statically above).
+   All subkeys (not values) of KEY that contain a REG_SZ value named 'native'
+   are added to the start of the mounts list.  */
+static void
+read_mounts (HKEY key)
+{
+  int mountsize = 15;
+  char *mount = xmalloc (mountsize);
+  DWORD size = mountsize;
+  int index = 0;
+  int retval = 0;
+
+  /* For each subkey ...  */
+  while ((retval = RegEnumKeyEx (key, index, mount, &size, 0, NULL, 0, NULL))
+	 != ERROR_NO_MORE_ITEMS)
+    {
+      struct mount *newmount;
+      HKEY subkey;
+      char *actual;
+
+      switch (retval) {
+      case ERROR_MORE_DATA:
+	/* The buffer wasn't large enough for this key name.
+	   Unlike RegQueryValueEx, RegEnumKeyEx won't tell us how big it
+	   should be, so just make it bigger and try again.
+	   Note that this code path does NOT increment index.
+       	   Most of the time we will only be dealing with short strings.  */
+	mountsize += 10;
+	mount = xrealloc (mount, mountsize);
+	break;
+
+      case ERROR_SUCCESS:
+	/* Find the actual windows path.  */
+  	if (RegOpenKeyEx (key, mount, 0, KEY_READ, &subkey) != ERROR_SUCCESS)
+	  {
+	    index++;
+	    break;
+	  }
+	actual = read_string_from_registry (subkey, "native");	
+	RegCloseKey (subkey);
+	if (actual == NULL)
+	  {
+	    index++;
+	    break;
+	  }
+
+	/* Create the new entry in the mount table.  */
+	newmount = xmalloc (sizeof (struct mount));
+	newmount->mount = xstrdup (mount);
+	newmount->actual = actual;
+	newmount->next = mounts;
+	mounts = newmount;
+	index++;
+	break;
+
+      default:
+	/* Don't infinite loop should any other return value occur.  */
+        index++;
+      }
+
+      /* The last call to RegEnumKeyEx may have clobbered size.
+         Fix it before the next call.  */
+      size = mountsize;
+    }
+
+  free (mount);
+}
+
+
+/* The top level registry reading function.
+   Open the keys, call the above functions to get the right values,
+   and clean up.  */
+static void
+read_registry (void)
+{
+  HKEY hcu_key, hlm_key;
+
+  /* Get key handles for the two places cygwin keeps its registry data.  */
+  if (RegOpenKeyEx (HKEY_CURRENT_USER,
+		    "Software\\Cygnus Solutions\\Cygwin\\mounts v2",
+		    0, KEY_READ, &hcu_key) != ERROR_SUCCESS)
+    hcu_key = NULL;
+
+  if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+		    "SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2",
+		    0, KEY_READ, &hlm_key) != ERROR_SUCCESS)
+    hlm_key = NULL;
+
+  /* Get the virtual mount point used for windows drives.  */
+  if (hcu_key)
+    cygdrive = read_string_from_registry (hcu_key, "cygdrive prefix");
+  if (hlm_key && cygdrive == NULL)
+    cygdrive = read_string_from_registry (hlm_key, "cygdrive prefix");
+
+  /* Read the other mount points.
+     Read hlm before hcu to ensure hcu settings get used by preference
+     by being closer on the mounts stack.  */
+  if (hlm_key)
+    read_mounts (hlm_key);
+  if (hcu_key)
+    read_mounts (hcu_key);
+
+  if (hlm_key)
+    RegCloseKey (hlm_key);
+  if (hcu_key)
+    RegCloseKey (hcu_key);
+}
+
+
+/* Given a path of unknown variety, return the same path with any
+   Cygwin mount points substituted.
+   This function always returns a malloced string which should be
+   freed when the the caller is finished with it.
+
+   The mapping is affected by the ST_CYGPATH_MODE environment variable.
+   See the fprintf messages below for full information.
+
+   It can replace /cygdrive/<letter>/..... style pathnames, even if the
+   user has used 'mount -c' to an alternative string.
+
+   It can replace (if enabled) other Cygwin mount points, such as
+   the usual '/', '/usr/bin', '/usr/lib', as well as any other user defined
+   mount points.
+
+   It does NOT attempt to convert any pathnames that look like native Windows
+   names - such as those starting with '<letter>:' or double slash (UNC).
+
+   It does NOT handle relative pathnames passing through cygwin mounts
+   (e.g. '../cygdrive/c'), or absolute paths with repeated directory
+   separators or relative elements within the mount name
+   (e.g. '/usr/./bin').
+   
+   It does NOT allow backslash \ directory separators within the actual mount
+   path (e.g. '/usr\bin').  Cygwin does not always allow them there either.  */
+char *
+cygpath (const char *path)
+{
+  char *result = NULL;
+
+  if (path == NULL)
+    return NULL;
+
+  /* If this is the first time this function has been called then read the
+     environment and registry.  */
+  if (mode == mode_unset)
+    {
+      char *env = getenv ("ST_CYGPATH_MODE");
+
+      if (env == NULL || strcmp (env, "normal") == 0)
+    	mode = mode_normal;
+      else if (strcmp (env, "full") == 0)
+	mode = mode_full;
+      else if (strcmp (env, "off") == 0)
+	mode = mode_off;
+
+      if (mode != mode_off)
+	read_registry();
+
+      if (mode == mode_unset)
+	{
+	  /* The variable was set, but not to any known value.
+	     Set up a default and print an informational message
+	     for the user.  */
+	  mode = mode_normal;
+	  fprintf (stderr, "ST_CYGPATH_MODE should be one of:\n");
+	  fprintf (stderr, " off    - Disable all path translation.\n");
+	  fprintf (stderr, " normal - Translate %s only.\n", cygdrive);
+	  fprintf (stderr, " full   - Translate all Cygwin mounts.\n");
+	}
+    }
+
+  /* First, test if this can only be a windows (non-cygwin) path.
+     This includes paths that start with a drive letter or UNC double slash.  */
+  if ((isalpha (path[0]) && path[1] == ':')
+      || ((path[0] == '\\' || path[0] == '/')
+	  && (path[1] == '\\' || path[1] == '/')))
+    result = xstrdup (path);
+
+  /* Second, handle /cygdrive/<letter>/ (or whatever) paths.  */
+  if (!result && cygdrive != NULL && (mode == mode_normal || mode == mode_full))
+    {
+      int length = strlen (cygdrive);
+      /* Note that cygwin does not allow '\\' instead of '/' in cygdrive.  */
+      if (strncmp (cygdrive, path, length) == 0
+	  && (path[length] == '/' || path[length] == '\\'
+	      || path[length] == '\0')
+	  && isalpha (path[length+1]))
+        {
+	  result = xmalloc (strlen (path) - length+1 + 1);
+	  result[0] = path[length+1];
+	  result[1] = ':';
+	  strcpy (result + 2, path + length + 2);
+	}
+    }
+
+  /* Third, handle other types of cygwin path.  */
+  if (!result && mounts != NULL && mode == mode_full)
+    {
+      int matched = 0;
+      struct mount *foundat = NULL;
+      struct mount *mount = mounts;
+      /* Find the longest matching mount point.
+	 This is important. If we just used the first matching mount point
+	 it would probably always match '/' when '/usr/bin' is right.
+	 Use the first of equal length matches - this allows current-user
+	 mounts to override 'local machine' mounts (can this happen?).
+         It is a match only if the matching part is followed by a directory
+         separator or the end of the path, except for the root mount point.  */
+      while (mount != NULL)
+	{
+	  int length = strlen (mount->mount);
+	  if (strncmp (mount->mount, path, length) == 0
+	      && matched < length
+	      && (length == 1 /* Special case for root mount point '/'.  */
+		  || path[length] == '/' || path[length] == '\\'
+		  || path[length] == '\0'))
+	    {
+	      matched = length;
+	      foundat = mount;
+	    }
+	  mount = mount->next;
+	}
+      if (matched)
+	{
+	  /* There was a match so do the substitution.
+	     If matched is 1 then it can only be the root mount point, in
+	     which case we do not want to remove the matched part as it is the 
+	     directory separator.  */
+	  if (matched == 1)
+	    matched = 0;
+	  result = xmalloc (strlen (foundat->actual) + strlen (path) + 1
+			    - matched);
+	  strcpy (result, foundat->actual);
+	  strcat (result, path + matched);
+	}
+    }
+
+  if (result)
+    {
+      /* Ensure that the return is never just a drive letter.
+	 This is not a valid directory on Windows, but code often
+	 trims trailing slashes.  */
+      int length = strlen(result);
+      if (result[length-1] == ':')
+	{
+	  result = xrealloc (result, length+2);
+	  result[length] = '/';
+	  result[length+1] = '\0';
+	}
+      return result;
+    }
+
+  /* If we get here then it must have been some other kind of path.  */
+  return xstrdup (path);
+}
+
+
+/* This is just to make inserting the conversion more convenient.
+   The CYGPATH_REPLACE is conditionally compiled so it is harder to
+   add clean up code to go with it without this.  */
+void
+cygpath_replace (char **path)
+{
+  char *result = cygpath (*path);
+  free (*path);
+  *path = result;
+}
diff -ruNdp -F'(' gcc-4.1.1.orig/libiberty/Makefile.in gcc-4.1.1/libiberty/Makefile.in
--- gcc-4.1.1.orig/libiberty/Makefile.in	2005-09-26 21:55:10.000000000 +0100
+++ gcc-4.1.1/libiberty/Makefile.in	2006-08-10 09:56:05.000000000 +0100
@@ -2,6 +2,7 @@
 # Makefile
 #   Copyright (C) 1990, 91-99, 2000, 2001, 2002, 2003, 2004, 2005
 #   Free Software Foundation
+#   Copyright (C) 2006 STMicroelectronics
 #
 # This file is part of the libiberty library.
 # Libiberty is free software; you can redistribute it and/or
@@ -129,7 +130,7 @@ # (alphabetical), and add them to REQUIR
 CFILES = alloca.c argv.c asprintf.c atexit.c				\
 	basename.c bcmp.c bcopy.c bsearch.c bzero.c			\
 	calloc.c choose-temp.c clock.c concat.c cp-demangle.c		\
-	 cp-demint.c cplus-dem.c					\
+	 cp-demint.c cplus-dem.c cygpath.c				\
 	dyn-string.c							\
 	fdmatch.c ffs.c fibheap.c floatformat.c fnmatch.c		\
 	 fopen_unlocked.c						\
@@ -186,7 +187,7 @@ REQUIRED_OFILES = ./regex.o ./cplus-dem.
 # maint-missing" and "make check".
 CONFIGURED_OFILES = ./asprintf.o ./atexit.o				\
 	./basename.o ./bcmp.o ./bcopy.o ./bsearch.o ./bzero.o		\
-	./calloc.o ./clock.o ./copysign.o				\
+	./calloc.o ./clock.o ./copysign.o cygpath.o			\
 	./_doprnt.o							\
 	./ffs.o								\
 	./getcwd.o ./getpagesize.o ./gettimeofday.o			\
@@ -548,6 +549,12 @@ 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/cpl
 	else true; fi
 	$(COMPILE.c) $(srcdir)/cplus-dem.c $(OUTPUT_OPTION)
 
+./cygpath.o: $(srcdir)/cygpath.c $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h
+	if [ x"$(PICFLAG)" != x ]; then \
+	  $(COMPILE.c) $(PICFLAG) $(srcdir)/cygpath.c -o pic/$@; \
+	else true; fi
+	$(COMPILE.c) $(srcdir)/cygpath.c $(OUTPUT_OPTION)
+
 ./dyn-string.o: $(srcdir)/dyn-string.c config.h $(INCDIR)/ansidecl.h \
 	$(INCDIR)/dyn-string.h $(INCDIR)/libiberty.h
 	if [ x"$(PICFLAG)" != x ]; then \
diff -ruNdp -F'(' gcc-4.1.1.orig/libiberty/make-relative-prefix.c gcc-4.1.1/libiberty/make-relative-prefix.c
--- gcc-4.1.1.orig/libiberty/make-relative-prefix.c	2005-05-24 21:48:25.000000000 +0100
+++ gcc-4.1.1/libiberty/make-relative-prefix.c	2006-08-10 09:56:05.000000000 +0100
@@ -1,6 +1,7 @@
 /* Relative (relocatable) prefix support.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (c) 2006  STMicroelectronics.
 
 This file is part of libiberty.
 
@@ -217,9 +218,9 @@   free ((char *) dirs);
 
    If no relative prefix can be found, return NULL.  */
 
-char *
-make_relative_prefix (const char *progname,
-                      const char *bin_prefix, const char *prefix)
+static char *
+make_relative_prefix_1 (const char *progname, const char *bin_prefix,
+			const char *prefix, const int resolve_links)
 {
   char **prog_dirs, **bin_dirs, **prefix_dirs;
   int prog_num, bin_num, prefix_num;
@@ -289,9 +290,14 @@ 		  if (*endp == 0)
 	}
     }
 
-  full_progname = lrealpath (progname);
-  if (full_progname == NULL)
-    return NULL;
+  if ( resolve_links )
+    {
+      full_progname = lrealpath (progname);
+      if (full_progname == NULL)
+	return NULL;
+    }
+  else
+    full_progname = strdup(progname);
 
   prog_dirs = split_directories (full_progname, &prog_num);
   bin_dirs = split_directories (bin_prefix, &bin_num);
@@ -387,3 +393,33 @@   free_split_directories (prefix_dirs);
 
   return ret;
 }
+
+
+/* Do the full job, including symlink resolution.
+   This path will find files installed in the same place as the
+   program even when a soft link has been made to the program
+   from somwhere else. */
+
+char *
+make_relative_prefix (progname, bin_prefix, prefix)
+     const char *progname;
+     const char *bin_prefix;
+     const char *prefix;
+{
+  return make_relative_prefix_1 (progname, bin_prefix, prefix, 1);
+}
+
+/* Make the relative pathname without attempting to resolve any links.
+   '..' etc may also be left in the pathname.
+   This will find the files the user meant the program to find if the
+   installation is patched together with soft links. */
+
+char *
+make_relative_prefix_ignore_links (progname, bin_prefix, prefix)
+     const char *progname;
+     const char *bin_prefix;
+     const char *prefix;
+{
+  return make_relative_prefix_1 (progname, bin_prefix, prefix, 0);
+}
+
diff -ruNdp -F'(' gcc-4.1.1.orig/libstdc++-v3/ChangeLog.STM gcc-4.1.1/libstdc++-v3/ChangeLog.STM
--- gcc-4.1.1.orig/libstdc++-v3/ChangeLog.STM	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.1.1/libstdc++-v3/ChangeLog.STM	2006-08-10 09:56:05.000000000 +0100
@@ -0,0 +1,5 @@
+2006-05-12  Antony King <anthony.king@st.com>
+            J"orn Rennecke <joern.rennecke@st.com>
+
+	* include/Makefile.am (stamp-host): Remove CCODECVT_H line.
+	* include/Makefile.in: Regenerate.
diff -ruNdp -F'(' gcc-4.1.1.orig/libstdc++-v3/include/Makefile.am gcc-4.1.1/libstdc++-v3/include/Makefile.am
--- gcc-4.1.1.orig/libstdc++-v3/include/Makefile.am	2005-11-05 09:42:01.000000000 +0000
+++ gcc-4.1.1/libstdc++-v3/include/Makefile.am	2006-08-10 09:56:05.000000000 +0100
@@ -804,6 +804,7 @@ 	$(STAMP) stamp-${host_alias}
 
 # Host includes static.
 # XXX Missing dependency info for {host_headers_extra}
+# CCODECVT_H is no longer defined; we don't want to symlink / copy the netire directory!
 stamp-host: ${host_headers} ${host_headers_noinst} stamp-${host_alias}
 	@if [ ! -f stamp-host ]; then \
 	  (cd ${host_builddir} ;\
@@ -815,8 +816,7 @@ 	  $(LN_S) ${glibcxx_srcdir}/$(CLOCALE_H
 	  $(LN_S) ${glibcxx_srcdir}/$(CLOCALE_INTERNAL_H) . || true ;\
 	  $(LN_S) ${glibcxx_srcdir}/$(COMPATIBILITY_H) . || true ;\
 	  $(LN_S) ${glibcxx_srcdir}/$(CMESSAGES_H) messages_members.h || true ;\
-	  $(LN_S) ${glibcxx_srcdir}/$(CTIME_H) time_members.h || true ;\
-	  $(LN_S) ${glibcxx_srcdir}/$(CCODECVT_H) codecvt_specializations.h || true);\
+	  $(LN_S) ${glibcxx_srcdir}/$(CTIME_H) time_members.h || true);\
 	fi ;\
 	$(STAMP) stamp-host
 
diff -ruNdp -F'(' gcc-4.1.1.orig/libstdc++-v3/include/Makefile.in gcc-4.1.1/libstdc++-v3/include/Makefile.in
--- gcc-4.1.1.orig/libstdc++-v3/include/Makefile.in	2006-01-10 17:14:00.000000000 +0000
+++ gcc-4.1.1/libstdc++-v3/include/Makefile.in	2006-08-10 09:56:05.000000000 +0100
@@ -1182,6 +1182,7 @@ 	$(STAMP) stamp-${host_alias}
 
 # Host includes static.
 # XXX Missing dependency info for {host_headers_extra}
+# CCODECVT_H is no longer defined; we don't want to symlink / copy the netire directory!
 stamp-host: ${host_headers} ${host_headers_noinst} stamp-${host_alias}
 	@if [ ! -f stamp-host ]; then \
 	  (cd ${host_builddir} ;\
@@ -1193,8 +1194,7 @@ 	  $(LN_S) ${glibcxx_srcdir}/$(CLOCALE_H
 	  $(LN_S) ${glibcxx_srcdir}/$(CLOCALE_INTERNAL_H) . || true ;\
 	  $(LN_S) ${glibcxx_srcdir}/$(COMPATIBILITY_H) . || true ;\
 	  $(LN_S) ${glibcxx_srcdir}/$(CMESSAGES_H) messages_members.h || true ;\
-	  $(LN_S) ${glibcxx_srcdir}/$(CTIME_H) time_members.h || true ;\
-	  $(LN_S) ${glibcxx_srcdir}/$(CCODECVT_H) codecvt_specializations.h || true);\
+	  $(LN_S) ${glibcxx_srcdir}/$(CTIME_H) time_members.h || true);\
 	fi ;\
 	$(STAMP) stamp-host
 
