Index: gcc/config/sh/predicates.md
===================================================================
--- gcc/config/sh/predicates.md	(revision 186233)
+++ gcc/config/sh/predicates.md	(working copy)
@@ -404,7 +404,7 @@
       if (GET_CODE (x) == PLUS
 	  && REG_P (XEXP (x, 0))
 	  && CONST_INT_P (XEXP (x, 1)))
-	return sh_legitimate_index_p (mode, XEXP (x, 1));
+	return sh_legitimate_index_p (mode, XEXP (x, 1), TARGET_SH2A, false);
     }
 
   if (TARGET_SHMEDIA
@@ -466,7 +466,7 @@
       if (GET_CODE (x) == PLUS
 	  && REG_P (XEXP (x, 0))
 	  && CONST_INT_P (XEXP (x, 1)))
-	return sh_legitimate_index_p (mode, XEXP (x, 1));
+	return sh_legitimate_index_p (mode, XEXP (x, 1), TARGET_SH2A, false);
     }
 
   return general_operand (op, mode);
Index: gcc/config/sh/sh-protos.h
===================================================================
--- gcc/config/sh/sh-protos.h	(revision 186233)
+++ gcc/config/sh/sh-protos.h	(working copy)
@@ -56,7 +56,7 @@
 extern bool fp_zero_operand (rtx);
 extern bool fp_one_operand (rtx);
 extern rtx get_fpscr_rtx (void);
-extern bool sh_legitimate_index_p (enum machine_mode, rtx);
+extern bool sh_legitimate_index_p (enum machine_mode, rtx, bool, bool);
 extern bool sh_legitimize_reload_address (rtx *, enum machine_mode, int, int);
 extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
 extern bool nonpic_symbol_mentioned_p (rtx);
Index: gcc/config/sh/sh.c
===================================================================
--- gcc/config/sh/sh.c	(revision 186233)
+++ gcc/config/sh/sh.c	(working copy)
@@ -304,6 +304,7 @@
 static int mov_insn_size (enum machine_mode, bool);
 static int max_mov_insn_displacement (enum machine_mode, bool);
 static int mov_insn_alignment_mask (enum machine_mode, bool);
+static HOST_WIDE_INT disp_addr_displacement (rtx);
 
 static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED;
 
@@ -3160,11 +3161,6 @@
      scale the max. displacement value accordingly.  */
   const int disp_scale = consider_sh2a ? (4095 / 15) : 1;
 
-  /* FIXME: HImode with displacement addressing is not supported yet.
-     Make it purposefully fail for now.  */
-  if (mode == HImode)
-    return 0;
-
   /* SH2A supports FPU move insns with 12 bit displacements.
      Other variants to do not support any kind of displacements for
      FPU move insns.  */
@@ -3194,15 +3190,24 @@
   return mov_insn_sz > 0 ? (mov_insn_sz - 1) : 0;
 }
 
+/* Return the displacement value of a displacement address.  */
+
+static inline HOST_WIDE_INT
+disp_addr_displacement (rtx x)
+{
+  gcc_assert (satisfies_constraint_Sdd (x));
+  return INTVAL (XEXP (XEXP (x, 0), 1));
+}
+
 /* Compute the cost of an address.  */
 
 static int
 sh_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
 {
   /* 'reg + disp' addressing.  */
-  if (DISP_ADDR_P (x))
+  if (satisfies_constraint_Sdd (x))
     {
-      const HOST_WIDE_INT offset = DISP_ADDR_OFFSET (x);
+      const HOST_WIDE_INT offset = disp_addr_displacement (x);
       const enum machine_mode mode = GET_MODE (x);
 
       /* The displacement would fit into a 2 byte move insn.  */
@@ -9665,7 +9670,8 @@
    with MODE.  */
 
 bool
-sh_legitimate_index_p (enum machine_mode mode, rtx op)
+sh_legitimate_index_p (enum machine_mode mode, rtx op, bool consider_sh2a,
+		       bool allow_zero)
 {
   if (! CONST_INT_P (op))
     return false;
@@ -9686,15 +9692,15 @@
   else
     {
       const HOST_WIDE_INT offset = INTVAL (op);
-      const int max_disp = max_mov_insn_displacement (mode, TARGET_SH2A);
-      const int align_mask = mov_insn_alignment_mask (mode, TARGET_SH2A);
+      const int max_disp = max_mov_insn_displacement (mode, consider_sh2a);
+      const int align_mask = mov_insn_alignment_mask (mode, consider_sh2a);
 
       /* If the mode does not support any displacement always return false.
 	 Even though an index of '0' is actually always valid, it will cause
 	 troubles when e.g. a DFmode move is split into two SFmode moves,
 	 where one SFmode move will have index '0' and the other move will
 	 have index '4'.  */
-       if (max_disp < 1)
+       if (!allow_zero && max_disp < 1)
 	return false;
 
       return offset >= 0 && offset <= max_disp && (offset & align_mask) == 0;
@@ -9728,7 +9734,7 @@
 
       if (GET_MODE_SIZE (mode) <= 8
 	  && MAYBE_BASE_REGISTER_RTX_P (xop0, strict)
-	  && sh_legitimate_index_p (mode, xop1))
+	  && sh_legitimate_index_p (mode, xop1, TARGET_SH2A, false))
 	return true;
 
       if ((ALLOW_INDEXED_ADDRESS || GET_MODE (x) == DImode
@@ -9875,11 +9881,6 @@
   if (mode_sz < 1 || mode_sz > 8 || max_disp < 1)
     return res;
 
-  /* FIXME: HImode with displacement addressing is not supported yet.
-     Make it purposefully fail for now.  */
-  if (mov_insn_sz == 2)
-    return res;
-
   /* Keeps the previous behavior for QImode displacement addressing.
      This just decides how the offset is re-based.  Removing this special
      case will result in slightly bigger code on average, but it's not that
@@ -12566,12 +12567,14 @@
   if (rclass == FPUL_REGS && true_regnum (x) == -1)
     return GENERAL_REGS;
 
-  /* Force mov.b displacement addressing insn to use R0 as the other operand.
+  /* Force mov.b / mov.w displacement addressing insn to use R0 as
+     the other operand.
      On SH2A could also just leave it alone here, which would result in a
      4 byte move insn being generated instead.  However, for this to work
      the insns must have the appropriate alternatives.  */
-  if (mode == QImode && rclass != R0_REGS
-      && DISP_ADDR_P (x) && DISP_ADDR_OFFSET (x) < 16)
+  if ((mode == QImode || mode == HImode) && rclass != R0_REGS
+      && satisfies_constraint_Sdd (x)
+      && disp_addr_displacement (x) <= max_mov_insn_displacement (mode, false))
     return R0_REGS;
 
   /* When reload is trying to address a QImode or HImode subreg on the stack, 
Index: gcc/config/sh/sh.h
===================================================================
--- gcc/config/sh/sh.h	(revision 186233)
+++ gcc/config/sh/sh.h	(working copy)
@@ -1210,24 +1210,12 @@
   ((HOST_BITS_PER_WIDE_INT >= 64 && (VALUE) == (HOST_WIDE_INT) 0xffffffff) \
    || (HOST_BITS_PER_WIDE_INT >= 64 && (VALUE) == (HOST_WIDE_INT) -1 << 32))
 
-#define CONST_OK_FOR_K04(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \
-				 && ((HOST_WIDE_INT)(VALUE)) <= 15)
-
 #define CONST_OK_FOR_K08(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \
 				 && ((HOST_WIDE_INT)(VALUE)) <= 255)
 
-#define CONST_OK_FOR_K12(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \
-				 && ((HOST_WIDE_INT)(VALUE)) <= 4095)
-
 #define ZERO_EXTRACT_ANDMASK(EXTRACT_SZ_RTX, EXTRACT_POS_RTX)\
   (((1 << INTVAL (EXTRACT_SZ_RTX)) - 1) << INTVAL (EXTRACT_POS_RTX))
 
-#define DISP_ADDR_P(X) (MEM_P (X) && GET_CODE (XEXP (X, 0)) == PLUS \
-			 && REG_P (XEXP (XEXP (X, 0), 0)) \
-			 && CONST_INT_P (XEXP (XEXP (X, 0), 1)))
-
-#define DISP_ADDR_OFFSET(X) (INTVAL (XEXP (XEXP (X, 0), 1)))
-
 #if 0
 #define SECONDARY_INOUT_RELOAD_CLASS(CLASS,MODE,X,ELSE) \
   ((((REGCLASS_HAS_FP_REG (CLASS) 					\
Index: gcc/config/sh/constraints.md
===================================================================
--- gcc/config/sh/constraints.md	(revision 186234)
+++ gcc/config/sh/constraints.md	(working copy)
@@ -145,16 +145,28 @@
   (and (match_code "const_int")
        (match_test "ival >= 0 && ival <= 15")))
 
+(define_constraint "K05"
+  "An unsigned 5-bit constant, as used in mov.w displacement addressing."
+  (and (match_code "const_int")
+       (match_test "ival >= 0 && ival <= 31")))
+
 (define_constraint "K08"
   "An unsigned 8-bit constant, as used in and, or, etc."
   (and (match_code "const_int")
        (match_test "ival >= 0 && ival <= 255")))
  
 (define_constraint "K12"
-  "An unsigned 12-bit constant, as used in SH2A 12-bit displacement addressing."
+  "An unsigned 12-bit constant, as used in SH2A 12-bit mov.b displacement
+   addressing."
   (and (match_code "const_int")
        (match_test "ival >= 0 && ival <= 4095")))
 
+(define_constraint "K13"
+  "An unsigned 13-bit constant, as used in SH2A 12-bit mov.w displacement
+   addressing."
+  (and (match_code "const_int")
+       (match_test "ival >= 0 && ival <= 8191")))
+
 (define_constraint "K16"
   "An unsigned 16-bit constant, as used in SHmedia shori."
   (and (match_code "const_int")
@@ -262,6 +274,16 @@
   (and (match_test "memory_operand (op, GET_MODE (op))")
        (match_test "GET_CODE (XEXP (op, 0)) != PLUS")))
 
+(define_memory_constraint "Sdd"
+  "A memory reference that uses displacement addressing."
+  (and (match_test "MEM_P (op) && GET_CODE (XEXP (op, 0)) == PLUS")
+       (match_test "REG_P (XEXP (XEXP (op, 0), 0))")
+       (match_test "CONST_INT_P (XEXP (XEXP (op, 0), 1))")))
+
+(define_memory_constraint "Snd"
+  "A memory reference that excludes displacement addressing."
+  (match_test "! satisfies_constraint_Sdd (op)"))
+
 (define_memory_constraint "Sbv"
   "A memory reference, as used in SH2A bclr.b, bset.b, etc."
   (and (match_test "MEM_P (op) && GET_MODE (op) == QImode")
@@ -269,15 +291,7 @@
 
 (define_memory_constraint "Sbw"
   "A memory reference, as used in SH2A bclr.b, bset.b, etc."
-  (and (match_test "MEM_P (op) && GET_MODE (op) == QImode")
-       (match_test "GET_CODE (XEXP (op, 0)) == PLUS")
-       (match_test "REG_P (XEXP (XEXP (op, 0), 0))")
+  (and (match_test "satisfies_constraint_Sdd (op)")
+       (match_test "GET_MODE (op) == QImode")
        (match_test "satisfies_constraint_K12 (XEXP (XEXP (op, 0), 1))")))
 
-(define_memory_constraint "Snd"
-  "A memory reference that excludes displacement addressing."
-  (match_test "! DISP_ADDR_P (op)"))
-
-(define_memory_constraint "Sdd"
-  "A memory reference that uses displacement addressing."
-  (match_test "DISP_ADDR_P (op)"))
Index: gcc/config/sh/sh.md
===================================================================
--- gcc/config/sh/sh.md	(revision 186233)
+++ gcc/config/sh/sh.md	(working copy)
@@ -4768,20 +4768,18 @@
     operands[1] = XEXP (operands[1], 0);
 })
 
+;; FIXME: Maybe fold HImode and QImode stuff with mode iterator?
 (define_expand "extendhisi2"
-  [(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
-	(sign_extend:SI (match_operand:HI 1 "general_extend_operand" "r,m")))]
+  [(set (match_operand:SI 0 "arith_reg_dest" "")
+	(sign_extend:SI (match_operand:HI 1 "general_extend_operand" "")))]
   ""
   "")
 
-(define_insn "*extendhisi2_compact"
-  [(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
-	(sign_extend:SI (match_operand:HI 1 "general_movsrc_operand" "r,m")))]
-  "TARGET_SH1"
-  "@
-	exts.w	%1,%0
-	mov.w	%1,%0"
-  [(set_attr "type" "arith,load")])
+(define_expand "extendqisi2"
+  [(set (match_operand:SI 0 "arith_reg_dest" "")
+	(sign_extend:SI (match_operand:QI 1 "general_extend_operand" "")))]
+  ""
+  "")
 
 (define_insn "*extendhisi2_media"
   [(set (match_operand:SI 0 "register_operand" "=r,r")
@@ -4811,12 +4809,6 @@
 			   subreg_lowpart_offset (SImode, GET_MODE (op1)));
 })
 
-(define_expand "extendqisi2"
-  [(set (match_operand:SI 0 "arith_reg_dest" "")
-	(sign_extend:SI (match_operand:QI 1 "general_extend_operand" "")))]
-  ""
-  "")
-
 (define_insn "*extendqisi2_compact_reg"
   [(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
 	(sign_extend:SI (match_operand:QI 1 "register_operand" "r,t")))]
@@ -4826,6 +4818,15 @@
 	movt	%0"
   [(set_attr "type" "arith,arith")])
 
+(define_insn "*extendhisi2_compact_reg"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
+	(sign_extend:SI (match_operand:HI 1 "register_operand" "r,t")))]
+  "TARGET_SH1"
+  "@
+	exts.w	%1,%0
+	movt	%0"
+  [(set_attr "type" "arith,arith")])
+
 ;; FIXME: Fold non-SH2A and SH2A alternatives with "enabled" attribute.
 ;; See movqi insns.
 (define_insn "*extendqisi2_compact_mem_disp"
@@ -4833,20 +4834,31 @@
 	(sign_extend:SI
 	 (mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r")
 			  (match_operand:SI 2 "const_int_operand" "K04,N")))))]
-  "TARGET_SH1 && ! TARGET_SH2A && CONST_OK_FOR_K04 (INTVAL (operands[2]))"
+  "TARGET_SH1 && ! TARGET_SH2A
+   && sh_legitimate_index_p (QImode, operands[2], false, true)"
   "@
 	mov.b	@(%O2,%1),%0
 	mov.b	@%1,%0"
   [(set_attr "type" "load")])
 
+(define_insn "*extendhisi2_compact_mem_disp"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=z,r")
+	(sign_extend:SI
+	 (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r")
+			  (match_operand:SI 2 "const_int_operand" "K05,N")))))]
+  "TARGET_SH1 && ! TARGET_SH2A
+   && sh_legitimate_index_p (HImode, operands[2], false, true)"
+  "@
+	mov.w	@(%O2,%1),%0
+	mov.w	@%1,%0"
+  [(set_attr "type" "load")])
+
 (define_insn "*extendqisi2_compact_mem_disp"
   [(set (match_operand:SI 0 "arith_reg_dest" "=z,r,r")
 	(sign_extend:SI
 	 (mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r")
 			  (match_operand:SI 2 "const_int_operand" "K04,N,K12")))))]
-  "TARGET_SH2A
-   && (CONST_OK_FOR_K04 (INTVAL (operands[2]))
-       || (CONST_OK_FOR_K12 (INTVAL (operands[2]))))"
+  "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[2], true, true)"
   "@
 	mov.b	@(%O2,%1),%0
 	mov.b	@%1,%0
@@ -4854,8 +4866,23 @@
   [(set_attr "type" "load")
    (set_attr "length" "2,2,4")])
 
-;; This will take care of other QImode addressing modes than displacement
-;; addressing.
+(define_insn "*extendhisi2_compact_mem_disp"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=z,r,r")
+	(sign_extend:SI
+	 (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r")
+			  (match_operand:SI 2 "const_int_operand" "K05,N,K13")))))]
+  "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[2], true, true)"
+  "@
+	mov.w	@(%O2,%1),%0
+	mov.w	@%1,%0
+	mov.w	@(%O2,%1),%0"
+  [(set_attr "type" "load")
+   (set_attr "length" "2,2,4")])
+
+;; The *_snd patterns will take care of other QImode/HImode addressing
+;; modes than displacement addressing.  They must be defined _after_ the
+;; displacement addressing patterns.  Otherwise the displacement addressing
+;; patterns will not be picked.
 (define_insn "*extendqisi2_compact_snd"
   [(set (match_operand:SI 0 "arith_reg_dest" "=r")
 	(sign_extend:SI (match_operand:QI 1 "movsrc_no_disp_mem_operand" "Snd")))]
@@ -4863,6 +4890,13 @@
   "mov.b	%1,%0"
   [(set_attr "type" "load")])
 
+(define_insn "*extendhisi2_compact_snd"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+	(sign_extend:SI (match_operand:HI 1 "movsrc_no_disp_mem_operand" "Snd")))]
+  "TARGET_SH1"
+  "mov.w	%1,%0"
+  [(set_attr "type" "load")])
+
 (define_insn "*extendqisi2_media"
   [(set (match_operand:SI 0 "register_operand" "=r,r")
 	(sign_extend:SI (match_operand:QI 1 "general_extend_operand" "r,m")))]
@@ -5441,6 +5475,14 @@
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
 
+(define_expand "movhi"
+  [(set (match_operand:HI 0 "general_movdst_operand" "")
+	(match_operand:HI 1 "general_movsrc_operand" ""))]
+  ""
+{
+  prepare_move_operands (operands, HImode);
+})
+
 (define_expand "movqi"
   [(set (match_operand:QI 0 "general_operand" "")
 	(match_operand:QI 1 "general_operand" ""))]
@@ -5456,6 +5498,7 @@
 ;; With the movqi_reg_reg being specified before movqi it will be intially 
 ;; picked to load/store regs.  If the regs regs are on the stack reload will
 ;; try other insns and not stick to movqi_reg_reg.
+;; The same applies to the movhi variants.
 (define_insn "*movqi_reg_reg"
   [(set (match_operand:QI 0 "arith_reg_dest"   "=r,r")
 	(match_operand:QI 1 "register_operand" "r,t"))]
@@ -5465,44 +5508,82 @@
 	movt	%0"
   [(set_attr "type" "move,arith")])
 
+(define_insn "*movhi_reg_reg"
+  [(set (match_operand:HI 0 "arith_reg_dest"   "=r,r")
+	(match_operand:HI 1 "register_operand" "r,t"))]
+  "TARGET_SH1"
+  "@
+	mov	%1,%0
+	movt	%0"
+  [(set_attr "type" "move,arith")])
+
 ;; FIXME: The non-SH2A and SH2A variants should be combined by adding
 ;; "enabled" attribute as it is done in other targets.
 (define_insn "*movqi_store_mem_disp04"
   [(set (mem:QI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r,r")
 			 (match_operand:SI 1 "const_int_operand" "K04,N")))
 	(match_operand:QI 2 "arith_reg_operand" "z,r"))]
-  "TARGET_SH1 && CONST_OK_FOR_K04 (INTVAL (operands[1]))"
+  "TARGET_SH1 && sh_legitimate_index_p (QImode, operands[1], false, true)"
   "@
 	mov.b	%2,@(%O1,%0)
 	mov.b	%2,@%0"
   [(set_attr "type" "store")])
 
+(define_insn "*movhi_store_mem_disp05"
+  [(set (mem:HI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r,r")
+			 (match_operand:SI 1 "const_int_operand" "K05,N")))
+	(match_operand:HI 2 "arith_reg_operand" "z,r"))]
+  "TARGET_SH1 && sh_legitimate_index_p (HImode, operands[1], false, true)"
+  "@
+	mov.w	%2,@(%O1,%0)
+	mov.w	%2,@%0"
+  [(set_attr "type" "store")])
+
 (define_insn "*movqi_store_mem_disp12"
   [(set (mem:QI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r")
 			 (match_operand:SI 1 "const_int_operand" "K12")))
 	(match_operand:QI 2 "arith_reg_operand" "r"))]
-  "TARGET_SH2A && CONST_OK_FOR_K12 (INTVAL (operands[1]))"
+  "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[1], true, true)"
   "mov.b	%2,@(%O1,%0)"
   [(set_attr "type" "store")
    (set_attr "length" "4")])
 
+(define_insn "*movhi_store_mem_disp13"
+  [(set (mem:HI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r")
+			 (match_operand:SI 1 "const_int_operand" "K13")))
+	(match_operand:HI 2 "arith_reg_operand" "r"))]
+  "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[1], true, true)"
+  "mov.w	%2,@(%O1,%0)"
+  [(set_attr "type" "store")
+   (set_attr "length" "4")])
+
 (define_insn "*movqi_load_mem_disp"
   [(set (match_operand:QI 0 "arith_reg_dest" "=z,r")
 	(mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r")
 			 (match_operand:SI 2 "const_int_operand" "K04,N"))))]
-  "TARGET_SH1 && ! TARGET_SH2A && CONST_OK_FOR_K04 (INTVAL (operands[2]))"
+  "TARGET_SH1 && ! TARGET_SH2A
+   && sh_legitimate_index_p (QImode, operands[2], false, true)"
   "@
 	mov.b	@(%O2,%1),%0
 	mov.b	@%1,%0"
   [(set_attr "type" "load")])
 
+(define_insn "*movhi_load_mem_disp"
+  [(set (match_operand:HI 0 "arith_reg_dest" "=z,r")
+	(mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r")
+			 (match_operand:SI 2 "const_int_operand" "K05,N"))))]
+  "TARGET_SH1 && ! TARGET_SH2A
+   && sh_legitimate_index_p (HImode, operands[2], false, true)"
+  "@
+	mov.w	@(%O2,%1),%0
+	mov.w	@%1,%0"
+  [(set_attr "type" "load")])
+
 (define_insn "*movqi_load_mem_disp"
   [(set (match_operand:QI 0 "arith_reg_dest" "=z,r,r")
 	(mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r")
 			 (match_operand:SI 2 "const_int_operand" "K04,N,K12"))))]
-  "TARGET_SH2A
-   && (CONST_OK_FOR_K04 (INTVAL (operands[2]))
-       || CONST_OK_FOR_K12 (INTVAL (operands[2])))"
+  "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[2], true, true)"
   "@
 	mov.b	@(%O2,%1),%0
 	mov.b	@%1,%0
@@ -5510,6 +5591,18 @@
   [(set_attr "type" "load")
    (set_attr "length" "2,2,4")])
 
+(define_insn "*movhi_load_mem_disp"
+  [(set (match_operand:HI 0 "arith_reg_dest" "=z,r,r")
+	(mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r")
+			 (match_operand:SI 2 "const_int_operand" "K05,N,K13"))))]
+  "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[2], true, true)"
+  "@
+	mov.w	@(%O2,%1),%0
+	mov.w	@%1,%0
+	mov.w	@(%O2,%1),%0"
+  [(set_attr "type" "load")
+   (set_attr "length" "2,2,4")])
+
 ;; The m constraints basically allow any kind of addresses to be used with any
 ;; source/target register as the other operand.  This is not true for 
 ;; displacement addressing modes on anything but SH2A.  That's why the
@@ -5528,6 +5621,21 @@
 	lds	%1,%0"
  [(set_attr "type" "movi8,load,store,prget,prset")])
 
+(define_insn "*movhi"
+  [(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,m,r,l")
+	(match_operand:HI 1 "general_movsrc_operand"  "Q,i,m,r,l,r"))]
+  "TARGET_SH1
+   && (arith_reg_operand (operands[0], HImode)
+       || arith_reg_operand (operands[1], HImode))"
+  "@
+	mov.w	%1,%0
+	mov	%1,%0
+	mov.w	%1,%0
+	mov.w	%1,%0
+	sts	%1,%0
+	lds	%1,%0"
+ [(set_attr "type" "pcload,movi8,load,store,prget,prset")])
+
 (define_insn "*movqi_media"
   [(set (match_operand:QI 0 "general_movdst_operand" "=r,r,r,m")
 	(match_operand:QI 1 "general_movsrc_operand" "r,I16Css,m,rZ"))]
@@ -5560,28 +5668,6 @@
   operands[3] = gen_rtx_REG (DImode, REGNO (operands[2]));
 })
 
-;; When storing r0, we have to avoid reg+reg addressing.
-(define_insn "movhi_i"
-  [(set (match_operand:HI 0 "general_movdst_operand"   "=r,r,r,r,m,r,l,r")
-	(match_operand:HI 1 "general_movsrc_operand" "Q,rI08,m,t,r,l,r,i"))]
-  "TARGET_SH1
-   && (arith_reg_operand (operands[0], HImode)
-       || arith_reg_operand (operands[1], HImode))
-   && (!MEM_P (operands[0])
-       || GET_CODE (XEXP (operands[0], 0)) != PLUS
-       || !REG_P (XEXP (XEXP (operands[0], 0), 1))
-       || ! refers_to_regno_p (R0_REG, R0_REG + 1, operands[1], (rtx *)0))"
-  "@
-	mov.w	%1,%0
-	mov	%1,%0
-	mov.w	%1,%0
-	movt	%0
-	mov.w	%1,%0
-	sts	%1,%0
-	lds	%1,%0
-	fake	%1,%0"
-  [(set_attr "type" "pcload,move,load,move,store,move,move,pcload")])
-
 (define_insn "*movhi_media"
   [(set (match_operand:HI 0 "general_movdst_operand"     "=r,r,r,r,m")
 	(match_operand:HI 1 "general_movsrc_operand" "r,I16Css,n,m,rZ"))]
@@ -5607,14 +5693,6 @@
    && ! satisfies_constraint_I16 (operands[1])"
   [(set (subreg:DI (match_dup 0) 0) (match_dup 1))])
 
-(define_expand "movhi"
-  [(set (match_operand:HI 0 "general_movdst_operand" "")
-	(match_operand:HI 1 "general_movsrc_operand"  ""))]
-  ""
-{
-  prepare_move_operands (operands, HImode);
-})
-
 (define_expand "reload_inhi"
   [(set (match_operand:SI 2 "" "=&r")
 	(match_operand:HI 1 "inqhi_operand" ""))
@@ -11563,10 +11641,10 @@
 
 ;; Fold sequence:
 ;;	mov #54,r0
-;;	mov.b @(r0,r15),r0
+;;	mov.{b,w} @(r0,r15),r0
 ;;	mov r0,r3
 ;; into:
-;;	mov.b @(54,r15),r3
+;;	mov.{b,w} @(54,r15),r3
 ;;
 (define_peephole2
   [(set (match_operand:SI 0 "arith_reg_dest" "")
@@ -11578,17 +11656,33 @@
    (set (match_operand:QI 4 "arith_reg_dest" "")
 	(match_operand:QI 5 "arith_reg_operand" ""))]
   "TARGET_SH2A
-   && CONST_OK_FOR_K12 (INTVAL (operands[1]))
+   && sh_legitimate_index_p (QImode, operands[1], true, true)
    && REGNO (operands[2]) == REGNO (operands[5])
    && peep2_reg_dead_p (3, operands[5])"
   [(set (match_dup 4) (mem:QI (plus:SI (match_dup 3) (match_dup 1))))]
   "")
 
+(define_peephole2
+  [(set (match_operand:SI 0 "arith_reg_dest" "")
+	(match_operand:SI 1 "const_int_operand" ""))
+   (set (match_operand:SI 2 "arith_reg_dest" "")
+	(sign_extend:SI
+	 (mem:HI (plus:SI (match_dup 0)
+			  (match_operand:SI 3 "arith_reg_operand" "")))))
+   (set (match_operand:HI 4 "arith_reg_dest" "")
+	(match_operand:HI 5 "arith_reg_operand" ""))]
+  "TARGET_SH2A
+   && sh_legitimate_index_p (HImode, operands[1], true, true)
+   && REGNO (operands[2]) == REGNO (operands[5])
+   && peep2_reg_dead_p (3, operands[5])"
+  [(set (match_dup 4) (mem:HI (plus:SI (match_dup 3) (match_dup 1))))]
+  "")
+
 ;; Fold sequence:
 ;;	mov #54,r0
-;;	mov.b @(r0,r15),r1
+;;	mov.{b,w} @(r0,r15),r1
 ;; into:
-;;	mov.b @(54,r15),r1
+;;	mov.{b,w} @(54,r15),r1
 ;;
 (define_peephole2
   [(set (match_operand:SI 0 "arith_reg_dest" "")
@@ -11598,19 +11692,37 @@
 	 (mem:QI (plus:SI (match_dup 0)
 			  (match_operand:SI 3 "arith_reg_operand" "")))))]
   "TARGET_SH2A
-   && CONST_OK_FOR_K12 (INTVAL (operands[1]))
+   && sh_legitimate_index_p (QImode, operands[1], true, true)
    && (peep2_reg_dead_p (2, operands[0])
        || REGNO (operands[0]) == REGNO (operands[2]))"
   [(set (match_dup 2)
 	(sign_extend:SI (mem:QI (plus:SI (match_dup 3) (match_dup 1)))))]
   "")
 
+(define_peephole2
+  [(set (match_operand:SI 0 "arith_reg_dest" "")
+	(match_operand:SI 1 "const_int_operand" ""))
+   (set (match_operand:SI 2 "arith_reg_dest" "")
+	 (sign_extend:SI
+	 (mem:HI (plus:SI (match_dup 0)
+			  (match_operand:SI 3 "arith_reg_operand" "")))))]
+  "TARGET_SH2A
+   && sh_legitimate_index_p (HImode, operands[1], true, true)
+   && (peep2_reg_dead_p (2, operands[0])
+       || REGNO (operands[0]) == REGNO (operands[2]))"
+  [(set (match_dup 2)
+	(sign_extend:SI (mem:HI (plus:SI (match_dup 3) (match_dup 1)))))]
+  "")
+
 ;; Fold sequence:
-;;	mov.b @(r0,r15),r0
+;;	mov.{b,w} @(r0,r15),r0
 ;;	mov r0,r3
 ;; into:
-;;	mov.b @(r0,r15),r3
+;;	mov.{b,w} @(r0,r15),r3
 ;;
+;; This can happen when initially a displacement address is picked, where
+;; the destination reg is fixed to r0, and then the address is transformed
+;; into 'r0 + reg'.
 (define_peephole2
   [(set (match_operand:SI 0 "arith_reg_dest" "")
 	(sign_extend:SI
@@ -11625,6 +11737,20 @@
 	(mem:QI (plus:SI (match_dup 1) (match_dup 2))))]
   "")
 
+(define_peephole2
+  [(set (match_operand:SI 0 "arith_reg_dest" "")
+	(sign_extend:SI
+	 (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "")
+			  (match_operand:SI 2 "arith_reg_operand" "")))))
+   (set (match_operand:HI 3 "arith_reg_dest" "")
+	(match_operand:HI 4 "arith_reg_operand" ""))]
+  "TARGET_SH1
+   && REGNO (operands[0]) == REGNO (operands[4])
+   && peep2_reg_dead_p (2, operands[0])"
+  [(set (match_dup 3)
+	(mem:HI (plus:SI (match_dup 1) (match_dup 2))))]
+  "")
+
 ;; These convert sequences such as `mov #k,r0; add r15,r0; mov.l @r0,rn'
 ;; to `mov #k,r0; mov.l @(r0,r15),rn'.  These sequences are generated by
 ;; reload when the constant is too large for a reg+offset address.
