--- gcc/config/sh/sh.c.orig	Wed Feb 24 10:44:34 1999
+++ gcc/config/sh/sh.c	Mon Jan 22 21:09:51 2001
@@ -22,6 +22,8 @@
    Improved by Jim Wilson (wilson@cygnus.com).  */
 
 #include "config.h"
+#include "system.h"
+#include "insn-config.h"
 
 #include <stdio.h>
 
@@ -29,11 +31,15 @@
 #include "tree.h"
 #include "flags.h"
 #include "insn-flags.h"
+#include "except.h"
 #include "expr.h"
+#include "function.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "output.h"
 #include "insn-attr.h"
+#include "toplev.h"
+#include "recog.h"
 
 int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch;
 
@@ -131,7 +137,8 @@
   switch (GET_CODE (x))
     {
     case REG:
-      fprintf (stream, "@%s", reg_names[REGNO (x)]);
+    case SUBREG:
+      fprintf (stream, "@%s", reg_names[true_regnum (x)]);
       break;
 
     case PLUS:
@@ -143,13 +150,19 @@
 	  {
 	  case CONST_INT:
 	    fprintf (stream, "@(%d,%s)", INTVAL (index),
-		     reg_names[REGNO (base)]);
+		     reg_names[true_regnum (base)]);
 	    break;
 
 	  case REG:
-	    fprintf (stream, "@(r0,%s)",
-		     reg_names[MAX (REGNO (base), REGNO (index))]);
+	  case SUBREG:
+	  {
+		  int base_num = true_regnum (base);
+		  int index_num = true_regnum (index);
+
+		  fprintf (stream, "@(r0,%s)",
+		     reg_names[MAX (base_num,index_num)]);
 	    break;
+	  }
 
 	  default:
 	    debug_rtx (x);
@@ -159,11 +172,11 @@
       break;
 
     case PRE_DEC:
-      fprintf (stream, "@-%s", reg_names[REGNO (XEXP (x, 0))]);
+      fprintf (stream, "@-%s", reg_names[true_regnum (XEXP (x, 0))]);
       break;
 
     case POST_INC:
-      fprintf (stream, "@%s+", reg_names[REGNO (XEXP (x, 0))]);
+      fprintf (stream, "@%s+", reg_names[true_regnum (XEXP (x, 0))]);
       break;
 
     default:
@@ -230,16 +243,31 @@
 	  fputs (reg_names[REGNO (x) + 1], (stream));
 	  break;
 	case MEM:
-	  print_operand_address (stream,
-				 XEXP (adj_offsettable_operand (x, 4), 0));
+	  if (GET_CODE (XEXP (x, 0)) != PRE_DEC
+	      && GET_CODE (XEXP (x, 0)) != POST_INC)
+	    x = adj_offsettable_operand (x, 4);
+	  print_operand_address (stream, XEXP (x, 0));
 	  break;
 	}
       break;
+    case 'o':
+      switch (GET_CODE (x))
+	{
+	case PLUS:  fputs ("add", stream); break;
+	case MINUS: fputs ("sub", stream); break;
+	case MULT:  fputs ("mul", stream); break;
+	case DIV:   fputs ("div", stream); break;
+	}
+      break;
     default:
       switch (GET_CODE (x))
 	{
 	case REG:
-	  fputs (reg_names[REGNO (x)], (stream));
+	  if (REGNO (x) >= FIRST_FP_REG && REGNO (x) <= LAST_FP_REG
+	      && GET_MODE_SIZE (GET_MODE (x)) > 4)
+	    fprintf ((stream), "d%s", reg_names[REGNO (x)]+1);
+	  else
+	    fputs (reg_names[REGNO (x)], (stream));
 	  break;
 	case MEM:
 	  output_address (XEXP (x, 0));
@@ -402,6 +430,7 @@
   if ((code != EQ && code != NE
        && (sh_compare_op1 != const0_rtx
 	   || code == GTU  || code == GEU || code == LTU || code == LEU))
+      || (mode == DImode && sh_compare_op1 != const0_rtx)
       || TARGET_SH3E && GET_MODE_CLASS (mode) == MODE_FLOAT)
     sh_compare_op1 = force_reg (mode, sh_compare_op1);
 
@@ -694,9 +723,9 @@
 
 char *
 output_ieee_ccmpeq (insn, operands)
-     rtx insn, operands;
+     rtx insn, *operands;
 {
-  output_branchy_insn (NE, "bt\t%l9\\;fcmp/eq\t%1,%0", insn, operands);
+  return output_branchy_insn (NE, "bt\t%l9\\;fcmp/eq\t%1,%0", insn, operands);
 }
 
 /* Output to FILE the start of the assembler file.  */
@@ -1602,8 +1631,16 @@
     case 5:
       {
 	int i = 16 - size;
-	emit_insn (gen_shl_sext_ext (dest, source, GEN_INT (16 - insize),
-				     GEN_INT (16)));
+	if (! rtx_equal_function_value_matters
+	    && ! reload_in_progress && ! reload_completed)
+	  emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx));
+	else
+	  {
+	    operands[0] = dest;
+	    operands[2] = GEN_INT (16 - insize);
+	    gen_shifty_hi_op (ASHIFT, operands);
+	    emit_insn (gen_extendhisi2 (dest, gen_lowpart (HImode, dest)));
+	  }
 	/* Don't use gen_ashrsi3 because it generates new pseudos.  */
 	while (--i >= 0)
 	  gen_ashift (ASHIFTRT, 1, dest);
@@ -2124,7 +2161,7 @@
   for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
     {
       part = XVECEXP (pattern, 0, i);
-      if (part == reg_part)
+      if (part == reg_part || GET_CODE (part) == CLOBBER)
 	continue;
       if (reg_mentioned_p (reg, ((GET_CODE (part) == SET
 				  && GET_CODE (SET_DEST (part)) == REG)
@@ -2464,6 +2501,13 @@
     }
   else
     jump = emit_jump_insn_after (gen_return (), insn);
+  /* Emit a barrier so that reorg knows that any following instructions
+     are not reachable via a fall-through path.
+     But don't do this when not optimizing, since we wouldn't supress the
+     alignment for the barrier then, and could end up with out-of-range
+     pc-relative loads.  */
+  if (optimize)
+    emit_barrier_after (jump);
   emit_label_after (bp->near_label, insn);
   JUMP_LABEL (jump) = bp->far_label;
   if (! invert_jump (insn, label))
@@ -2481,7 +2525,7 @@
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
-      rtx vec_lab, pat, prev, prevpat, x;
+      rtx vec_lab, pat, prev, prevpat, x, braf_label;
 
       if (GET_CODE (insn) != JUMP_INSN
 	  || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
@@ -2504,10 +2548,15 @@
 	  if (GET_CODE (x) == LABEL_REF && XEXP (x, 0) == vec_lab)
 	    break;
 	}
+
+      /* Emit the reference label of the braf where it belongs, right after
+	 the casesi_jump_2 (i.e. braf).  */
+      braf_label = XEXP (XEXP (SET_SRC (XVECEXP (prevpat, 0, 0)), 1), 0);
+      emit_label_after (braf_label, prev);
+
       /* Fix up the ADDR_DIF_VEC to be relative
 	 to the reference address of the braf.  */
-      XEXP (XEXP (pat, 0), 0)
-	= XEXP (XEXP (SET_SRC (XVECEXP (prevpat, 0, 0)), 1), 0);
+      XEXP (XEXP (pat, 0), 0) = braf_label;
     }
 }
 
--- gcc/config/sh/sh.h.orig	Mon Jun  1 23:25:44 1998
+++ gcc/config/sh/sh.h	Mon Jan 22 21:09:51 2001
@@ -1143,7 +1143,8 @@
   else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC)	\
 	   && BASE_REGISTER_RTX_P (XEXP ((X), 0)))			\
     goto LABEL;								\
-  else if (GET_CODE (X) == PLUS && MODE != PSImode)			\
+  else if (GET_CODE (X) == PLUS						\
+      && ((MODE) != PSImode || reload_completed))			\
     {									\
       rtx xop0 = XEXP ((X), 0);						\
       rtx xop1 = XEXP ((X), 1);						\
@@ -1465,7 +1466,7 @@
    and another.  */
 
 #define REGISTER_MOVE_COST(SRCCLASS, DSTCLASS) \
-  ((DSTCLASS) == PR_REG ? 10		\
+  ((DSTCLASS) == PR_REGS ? 10		\
    : (((DSTCLASS) == FP_REGS && (SRCCLASS) == GENERAL_REGS)		\
       || ((DSTCLASS) == GENERAL_REGS && (SRCCLASS) == FP_REGS)) ? 4	\
    : 1)
@@ -1566,10 +1567,10 @@
 }
 
 #define ASM_OUTPUT_REG_PUSH(file, v) \
-  fprintf ((file), "\tmov.l\tr%s,-@r15\n", (v));
+  fprintf ((file), "\tmov.l\tr%d,@-r15\n", (v));
 
 #define ASM_OUTPUT_REG_POP(file, v) \
-  fprintf ((file), "\tmov.l\t@r15+,r%s\n", (v));
+  fprintf ((file), "\tmov.l\t@r15+,r%d\n", (v));
 
 /* The assembler's names for the registers.  RFP need not always be used as
    the Real framepointer; it can also be used as a normal general register.
@@ -1957,3 +1958,5 @@
 #define HAVE_ATEXIT
 
 #define SH_DYNAMIC_SHIFT_COST (TARGET_SH3 ? (TARGET_SMALLCODE ? 1 : 2) : 20)
+
+#define DWARF_LINE_MIN_INSTR_LENGTH 2
--- gcc/config/sh/sh.md.orig	Thu Apr 23 22:37:16 1998
+++ gcc/config/sh/sh.md	Mon Jan 22 21:09:51 2001
@@ -661,7 +661,7 @@
 ;; This reload would clobber the value in r0 we are trying to store.
 ;; If we let reload allocate r0, then this problem can never happen.
 
-(define_insn ""
+(define_insn "udivsi3_i1"
   [(set (match_operand:SI 0 "register_operand" "=z")
 	(udiv:SI (reg:SI 4) (reg:SI 5)))
    (clobber (reg:SI 18))
@@ -674,9 +674,9 @@
    (set_attr "needs_delay_slot" "yes")])
 
 (define_expand "udivsi3"
-  [(set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
+  [(set (match_dup 3) (symbol_ref:SI "__udivsi3"))
+   (set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
    (set (reg:SI 5) (match_operand:SI 2 "general_operand" ""))
-   (set (match_dup 3) (symbol_ref:SI "__udivsi3"))
    (parallel [(set (match_operand:SI 0 "register_operand" "")
 		   (udiv:SI (reg:SI 4)
 			    (reg:SI 5)))
@@ -685,9 +685,26 @@
 	      (clobber (reg:SI 4))
 	      (use (match_dup 3))])]
   ""
-  "operands[3] = gen_reg_rtx(SImode);")
+  "
+{
+  rtx first, last;
 
-(define_insn ""
+  operands[3] = gen_reg_rtx(SImode);
+  /* Emit the move of the address to a pseudo outside of the libcall.  */
+  emit_move_insn (operands[3],
+		  gen_rtx_SYMBOL_REF (SImode, \"__udivsi3\"));
+  last = gen_udivsi3_i1 (operands[0], operands[3]);
+  first = emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]);
+  emit_move_insn (gen_rtx_REG (SImode, 5), operands[2]);
+  last = emit_insn (last);
+  /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
+     invariant code motion can move it.  */
+  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
+  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
+  DONE;
+}")
+
+(define_insn "divsi3_i1"
   [(set (match_operand:SI 0 "register_operand" "=z")
 	(div:SI (reg:SI 4) (reg:SI 5)))
    (clobber (reg:SI 18))
@@ -702,9 +719,9 @@
    (set_attr "needs_delay_slot" "yes")])
 
 (define_expand "divsi3"
-  [(set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
+  [(set (match_dup 3) (symbol_ref:SI "__sdivsi3"))
+   (set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
    (set (reg:SI 5) (match_operand:SI 2 "general_operand" ""))
-   (set (match_dup 3) (symbol_ref:SI "__sdivsi3"))
    (parallel [(set (match_operand:SI 0 "register_operand" "")
 		   (div:SI (reg:SI 4)
 			   (reg:SI 5)))
@@ -715,13 +732,29 @@
 	      (clobber (reg:SI 3))
 	      (use (match_dup 3))])]
   ""
-  "operands[3] = gen_reg_rtx(SImode);")
+  "
+{
+  rtx first, last;
+
+  operands[3] = gen_reg_rtx(SImode);
+  /* Emit the move of the address to a pseudo outside of the libcall.  */
+  emit_move_insn (operands[3], gen_rtx_SYMBOL_REF (SImode, \"__sdivsi3\"));
+  last = gen_divsi3_i1 (operands[0], operands[3]);
+  first = emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]);
+  emit_move_insn (gen_rtx_REG (SImode, 5), operands[2]);
+  last = emit_insn (last);
+  /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
+     invariant code motion can move it.  */
+  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
+  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
+  DONE;
+}")
 
 ;; -------------------------------------------------------------------------
 ;; Multiplication instructions
 ;; -------------------------------------------------------------------------
 
-(define_insn ""
+(define_insn "umulhisi3_i"
   [(set (reg:SI 21)
 	(mult:SI (zero_extend:SI (match_operand:HI 0 "arith_reg_operand" "r"))
 		 (zero_extend:SI (match_operand:HI 1 "arith_reg_operand" "r"))))]
@@ -729,7 +762,7 @@
   "mulu	%1,%0"
   [(set_attr "type" "smpy")])
 
-(define_insn ""
+(define_insn "mulhisi3_i"
   [(set (reg:SI 21)
 	(mult:SI (sign_extend:SI
 		  (match_operand:HI 0 "arith_reg_operand" "r"))
@@ -748,7 +781,18 @@
    (set (match_operand:SI 0 "arith_reg_operand" "")
 	(reg:SI 21))]
   ""
-  "")
+  "
+{
+  rtx first, last;
+
+  first = emit_insn (gen_mulhisi3_i (operands[1], operands[2]));
+  last = emit_move_insn (operands[0], gen_rtx_REG (SImode, 21));
+  /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
+     invariant code motion can move it.  */
+  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
+  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
+  DONE;
+}")
 
 (define_expand "umulhisi3"
   [(set (reg:SI 21)
@@ -759,7 +803,18 @@
    (set (match_operand:SI 0 "arith_reg_operand" "")
 	(reg:SI 21))]
   ""
-  "")
+  "
+{
+  rtx first, last;
+
+  first = emit_insn (gen_umulhisi3_i (operands[1], operands[2]));
+  last = emit_move_insn (operands[0], gen_rtx_REG (SImode, 21));
+  /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
+     invariant code motion can move it.  */
+  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
+  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
+  DONE;
+}")
 
 ;; mulsi3 on the SH2 can be done in one instruction, on the SH1 we generate
 ;; a call to a routine which clobbers known registers.
@@ -782,7 +837,6 @@
 (define_expand "mulsi3_call"
   [(set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
    (set (reg:SI 5) (match_operand:SI 2 "general_operand" ""))
-   (set (match_dup 3) (symbol_ref:SI "__mulsi3"))
    (parallel[(set (match_operand:SI 0 "register_operand" "")
 		  (mult:SI (reg:SI 4)
 			   (reg:SI 5)))
@@ -792,9 +846,9 @@
 	     (clobber (reg:SI 3))
 	     (clobber (reg:SI 2))
 	     (clobber (reg:SI 1))
-	     (use (match_dup 3))])]
+	     (use (match_operand:SI 3 "register_operand" ""))])]
   ""
-  "operands[3] = gen_reg_rtx(SImode);")
+  "")
 
 (define_insn "mul_l"
   [(set (reg:SI 21)
@@ -813,82 +867,120 @@
   ""
   "
 {
+  rtx first, last;
+
   if (!TARGET_SH2)
     {
-      FAIL;
-      /* ??? Does this give worse or better code?  */
-      emit_insn (gen_mulsi3_call (operands[0], operands[1], operands[2]));
-      DONE;
+      /* The address must be set outside the libcall,
+	 since it goes into a pseudo.  */
+      rtx addr = force_reg (SImode, gen_rtx_SYMBOL_REF (SImode, \"__mulsi3\"));
+      rtx insns = gen_mulsi3_call (operands[0], operands[1], operands[2], addr);
+      first = XVECEXP (insns, 0, 0);
+      last = XVECEXP (insns, 0, XVECLEN (insns, 0) - 1);
+      emit_insn (insns);
     }
+  else
+    {
+      rtx macl = gen_rtx_REG (SImode, MACL_REG);
+
+      first = emit_insn (gen_mul_l (operands[1], operands[2]));
+      /* consec_sets_giv can only recognize the first insn that sets a
+	 giv as the giv insn.  So we must tag this also with a REG_EQUAL
+	 note.  */
+      last = emit_insn (gen_movsi_i ((operands[0]), macl));
+    }
+  /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
+     invariant code motion can move it.  */
+  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
+  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
+  DONE;
 }")
 
 (define_insn "mulsidi3_i"
-  [(set (reg:DI 20)
-	(mult:DI (sign_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
-		 (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))))]
+  [(set (reg:SI 20)
+	(truncate:SI
+	 (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
+			       (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "r")))
+		      (const_int 32))))
+   (set (reg:SI 21)
+	(mult:SI (match_dup 0)
+		 (match_dup 1)))]
   "TARGET_SH2"
   "dmuls.l	%1,%0"
   [(set_attr "type" "dmpy")])
 
-(define_expand "mulsidi3"
-  [(set (reg:DI 20)
+(define_insn "mulsidi3"
+  [(set (match_operand:DI 0 "arith_reg_operand" "=r")
+	(mult:DI (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
+		 (sign_extend:DI (match_operand:SI 2 "arith_reg_operand" "r"))))
+   (clobber (reg:DI 20))]
+  "TARGET_SH2"
+  "#")
+
+(define_split
+  [(set (match_operand:DI 0 "arith_reg_operand" "")
 	(mult:DI (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" ""))
 		 (sign_extend:DI (match_operand:SI 2 "arith_reg_operand" ""))))
-   (set (match_operand:DI 0 "arith_reg_operand" "")
-	(reg:DI 20))]
+   (clobber (reg:DI 20))]
   "TARGET_SH2"
+  [(const_int 0)]
   "
 {
-  /* We must swap the two words when copying them from MACH/MACL to the
-     output register.  */
-  if (TARGET_LITTLE_ENDIAN)
-    {
-      rtx low_dst = operand_subword (operands[0], 0, 1, DImode);
-      rtx high_dst = operand_subword (operands[0], 1, 1, DImode);
-
-      emit_insn (gen_mulsidi3_i (operands[1], operands[2]));
-
-      emit_insn (gen_rtx (CLOBBER, VOIDmode, operands[0]));
-      emit_move_insn (low_dst, gen_rtx (REG, SImode, 21));
-      emit_move_insn (high_dst, gen_rtx (REG, SImode, 20));
-      DONE;
-    }
+  rtx low_dst = gen_lowpart (SImode, operands[0]);
+  rtx high_dst = gen_highpart (SImode, operands[0]);
+
+  emit_insn (gen_mulsidi3_i (operands[1], operands[2]));
+
+  emit_move_insn (low_dst, gen_rtx_REG (SImode, 21));
+  emit_move_insn (high_dst, gen_rtx_REG (SImode, 20));
+  /* We need something to tag the possible REG_EQUAL notes on to.  */
+  emit_move_insn (operands[0], operands[0]);
+  DONE;
 }")
 
 (define_insn "umulsidi3_i"
-  [(set (reg:DI 20)
-	(mult:DI (zero_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
-		 (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))))]
+  [(set (reg:SI 20)
+	(truncate:SI
+	 (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
+			       (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" "r")))
+		      (const_int 32))))
+   (set (reg:SI 21)
+	(mult:SI (match_dup 0)
+		 (match_dup 1)))]
   "TARGET_SH2"
   "dmulu.l	%1,%0"
   [(set_attr "type" "dmpy")])
 
-(define_expand "umulsidi3"
-  [(set (reg:DI 20)
+(define_insn "umulsidi3"
+  [(set (match_operand:DI 0 "arith_reg_operand" "=r")
+	(mult:DI (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
+		 (zero_extend:DI (match_operand:SI 2 "arith_reg_operand" "r"))))
+   (clobber (reg:DI 20))]
+  "TARGET_SH2"
+  "#")
+
+(define_split
+  [(set (match_operand:DI 0 "arith_reg_operand" "")
 	(mult:DI (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" ""))
 		 (zero_extend:DI (match_operand:SI 2 "arith_reg_operand" ""))))
-   (set (match_operand:DI 0 "arith_reg_operand" "")
-	(reg:DI 20))]
+   (clobber (reg:DI 20))]
   "TARGET_SH2"
+  [(const_int 0)]
   "
 {
-  /* We must swap the two words when copying them from MACH/MACL to the
-     output register.  */
-  if (TARGET_LITTLE_ENDIAN)
-    {
-      rtx low_dst = operand_subword (operands[0], 0, 1, DImode);
-      rtx high_dst = operand_subword (operands[0], 1, 1, DImode);
-
-      emit_insn (gen_umulsidi3_i (operands[1], operands[2]));
-
-      emit_insn (gen_rtx (CLOBBER, VOIDmode, operands[0]));
-      emit_move_insn (low_dst, gen_rtx (REG, SImode, 21));
-      emit_move_insn (high_dst, gen_rtx (REG, SImode, 20));
-      DONE;
-    }
+  rtx low_dst = gen_lowpart (SImode, operands[0]);
+  rtx high_dst = gen_highpart (SImode, operands[0]);
+
+  emit_insn (gen_umulsidi3_i (operands[1], operands[2]));
+
+  emit_move_insn (low_dst, gen_rtx_REG (SImode, 21));
+  emit_move_insn (high_dst, gen_rtx_REG (SImode, 20));
+  /* We need something to tag the possible REG_EQUAL notes on to.  */
+  emit_move_insn (operands[0], operands[0]);
+  DONE;
 }")
 
-(define_insn ""
+(define_insn "smulsi3_highpart_i"
   [(set (reg:SI 20)
 	(truncate:SI
 	 (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
@@ -909,9 +1001,27 @@
    (set (match_operand:SI 0 "arith_reg_operand" "")
 	(reg:SI 20))]
   "TARGET_SH2"
-  "")
+  "
+{
+  rtx first, last;
 
-(define_insn ""
+  first = emit_insn (gen_smulsi3_highpart_i (operands[1], operands[2]));
+  last = emit_move_insn (operands[0], gen_rtx_REG (SImode, 20));
+  /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
+     invariant code motion can move it.  */
+  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
+  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
+  /* expand_binop can't find a suitable code in mul_highpart_optab to
+     make a REG_EQUAL note from, so make one here.
+     ??? Alternatively, we could put this at the calling site of expand_binop,
+     i.e. expand_mult_highpart.  */
+  REG_NOTES (last)
+    = gen_rtx_EXPR_LIST (REG_EQUAL, copy_rtx (SET_SRC (single_set (first))),
+			 REG_NOTES (last));
+  DONE;
+}")
+
+(define_insn "umulsi3_highpart_i"
   [(set (reg:SI 20)
 	(truncate:SI
 	 (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 0 "arith_reg_operand" "r"))
@@ -932,7 +1042,18 @@
    (set (match_operand:SI 0 "arith_reg_operand" "")
 	(reg:SI 20))]
   "TARGET_SH2"
-  "")
+  "
+{
+  rtx first, last;
+
+  first = emit_insn (gen_umulsi3_highpart_i (operands[1], operands[2]));
+  last = emit_move_insn (operands[0], gen_rtx_REG (SImode, 20));
+  /* Wrap the sequence in REG_LIBCALL / REG_RETVAL notes so that loop
+     invariant code motion can move it.  */
+  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last, REG_NOTES (first));
+  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
+  DONE;
+}")
 
 ;; -------------------------------------------------------------------------
 ;; Logical operations
@@ -1825,19 +1946,20 @@
   ""
   "sett")
 
-;; t/r is first, so that it will be preferred over r/r when reloading a move
-;; of a pseudo-reg into the T reg
+;; t/r must come after r/r, lest reload will try to reload stuff like
+;; (set (subreg:SI (mem:QI (plus:SI (reg:SI 15 r15) (const_int 12)) 0) 0)
+;; (made from (set (subreg:SI (reg:QI 73) 0) ) into T.
 (define_insn "movsi_i"
-  [(set (match_operand:SI 0 "general_movdst_operand" "=t,r,r,r,r,r,m,<,<,xl,x,l,r")
-	(match_operand:SI 1 "general_movsrc_operand" "r,Q,rI,m,xl,t,r,x,l,r,>,>,i"))]
+  [(set (match_operand:SI 0 "general_movdst_operand" "=r,r,t,r,r,r,m,<,<,xl,x,l,r")
+	(match_operand:SI 1 "general_movsrc_operand" "Q,rI,r,mr,xl,t,r,x,l,r,>,>,i"))]
   "
    ! TARGET_SH3E
    && (register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode))"
   "@
-	cmp/pl	%1
 	mov.l	%1,%0
 	mov	%1,%0
+	cmp/pl	%1
 	mov.l	%1,%0
 	sts	%1,%0
 	movt	%0
@@ -1848,7 +1970,7 @@
 	lds.l	%1,%0
 	lds.l	%1,%0
 	fake	%1,%0"
-  [(set_attr "type" "*,pcload_si,move,load_si,move,move,store,store,pstore,move,load,pload,pcload_si")
+  [(set_attr "type" "pcload_si,move,*,load_si,move,move,store,store,pstore,move,load,pload,pcload_si")
    (set_attr "length" "*,*,*,*,*,*,*,*,*,*,*,*,*")])
 
 ;; t/r must come after r/r, lest reload will try to reload stuff like
@@ -1856,8 +1978,8 @@
 ;; ??? This allows moves from macl to fpul to be recognized, but these moves
 ;; will require a reload.
 (define_insn "movsi_ie"
-  [(set (match_operand:SI 0 "general_movdst_operand" "=r,r,t,r,r,r,m,<,<,xl,x,l,r,y,r,y")
-	(match_operand:SI 1 "general_movsrc_operand" "Q,rI,r,m,xl,t,r,x,l,r,>,>,i,r,y,y"))]
+  [(set (match_operand:SI 0 "general_movdst_operand" "=r,r,t,r,r,r,m,<,<,xl,x,l,y,r,y,r,y")
+	(match_operand:SI 1 "general_movsrc_operand" "Q,rI,r,mr,xl,t,r,x,l,r,>,>,>,i,r,y,y"))]
   "TARGET_SH3E
    && (register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode))"
@@ -1874,16 +1996,17 @@
 	lds	%1,%0
 	lds.l	%1,%0
 	lds.l	%1,%0
+	lds.l	%1,%0
 	fake	%1,%0
 	lds	%1,%0
 	sts	%1,%0
 	! move optimized away"
-  [(set_attr "type" "pcload_si,move,*,load_si,move,move,store,store,pstore,move,load,pload,pcload_si,gp_fpul,gp_fpul,nil")
-   (set_attr "length" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,0")])
+  [(set_attr "type" "pcload_si,move,*,load_si,move,move,store,store,pstore,move,load,pload,load,pcload_si,gp_fpul,gp_fpul,nil")
+   (set_attr "length" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,0")])
 
 (define_insn "movsi_i_lowpart"
   [(set (strict_low_part (match_operand:SI 0 "general_movdst_operand" "=r,r,r,r,r,m,r"))
-	(match_operand:SI 1 "general_movsrc_operand" "Q,rI,m,xl,t,r,i"))]
+	(match_operand:SI 1 "general_movsrc_operand" "Q,rI,mr,xl,t,r,i"))]
    "register_operand (operands[0], SImode)
     || register_operand (operands[1], SImode)"
   "@
@@ -2087,7 +2210,8 @@
     FAIL;
   reg = XEXP (addr, 0);
   const_int = XEXP (addr, 1);
-  if (GET_CODE (reg) != REG || GET_CODE (const_int) != CONST_INT)
+  if (! (BASE_REGISTER_RTX_P (reg) && INDEX_REGISTER_RTX_P (operands[2])
+	 && GET_CODE (const_int) == CONST_INT))
     FAIL;
   emit_move_insn (operands[2], const_int);
   emit_move_insn (operands[0],
@@ -2113,7 +2237,8 @@
     FAIL;
   reg = XEXP (addr, 0);
   const_int = XEXP (addr, 1);
-  if (GET_CODE (reg) != REG || GET_CODE (const_int) != CONST_INT)
+  if (! (BASE_REGISTER_RTX_P (reg) && INDEX_REGISTER_RTX_P (operands[2])
+	 && GET_CODE (const_int) == CONST_INT))
     FAIL;
   emit_move_insn (operands[2], const_int);
   emit_move_insn (change_address (operands[1], VOIDmode,
@@ -2249,7 +2374,7 @@
 ;; This one has the additional purpose to record a possible scratch register
 ;; for the following branch.
 (define_insn "indirect_jump_scratch"
-  [(set (match_operand 0 "register_operand" "r")
+  [(set (match_operand 0 "register_operand" "=r")
 	(unspec [(match_operand 1 "const_int_operand" "")] 4))]
   ""
   ""
@@ -2478,7 +2603,7 @@
 {
   int i;
 
-  emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx, const0_rtx));
+  emit_call_insn (gen_call (operands[0], const0_rtx));
 
   for (i = 0; i < XVECLEN (operands[2], 0); i++)
     {
@@ -2974,6 +3099,7 @@
 	      (use (match_operand:SI 0 "arith_reg_operand" "r"))
 	      (use (reg:SI 6))
 	      (clobber (reg:SI 17))
+	      (clobber (reg:SI 18))
 	      (clobber (reg:SI 4))
 	      (clobber (reg:SI 5))
 	      (clobber (reg:SI 6))
@@ -3144,10 +3270,9 @@
 
   size /= 8;
   orig_address = XEXP (operands[0], 0);
-  addr_target = gen_reg_rtx (SImode);
   shift_reg = gen_reg_rtx (SImode);
   emit_insn (gen_movsi (shift_reg, operands[3]));
-  emit_insn (gen_addsi3 (addr_target, orig_address, GEN_INT (size - 1)));
+  addr_target = copy_addr_to_reg (plus_constant (orig_address, size - 1));
 
   operands[0] = change_address (operands[0], QImode, addr_target);
   emit_insn (gen_movqi (operands[0], gen_rtx (SUBREG, QImode, shift_reg, 0)));
