diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9fcf3ca1dbe4decafa619ac89f7b2eda40be8602..f161d63f41dd69980181fd3aca95e64be9d3eeba 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2012-07-03  Oleg Endo  <olegendo@gcc.gnu.org>
+
+	* config/sh/predicates.md (logical_and_operand): New predicate.
+	* config/sh/constraints.md (Jmb, Jmw): New constraints.
+	* config/sh/sh.md (andsi3): Move expander above insns.  Add handling
+	of 0xFFFF constant.  Use logical_and_operand predicate and
+	satisfies_constraint_Jmb, satisfies_constraint_Jmw.
+	(*andsi3_compact): Make it an insn_and_split.  Use
+	logical_and_operand predicate.  Add Jmb,Jmw alternatives.
+
 2012-07-03  Jason Merrill  <jason@redhat.com>
 
 	PR c++/53826
diff --git a/gcc/config/sh/constraints.md b/gcc/config/sh/constraints.md
index 6c9bc5ecc95df71630fe722507076289356beb21..8642ea808a73b4334f48f3ad878a4c5f6a4ec9e7 100644
--- a/gcc/config/sh/constraints.md
+++ b/gcc/config/sh/constraints.md
@@ -31,6 +31,8 @@
 ;; IJKLMNOP: CONT_INT constants
 ;;  Ixx: signed xx bit
 ;;  J16: 0xffffffff00000000 | 0x00000000ffffffff
+;;  Jmb: 0x000000FF
+;;  Jmw: 0x0000FFFF
 ;;  Kxx: unsigned xx bit
 ;;  M: 1
 ;;  N: 0
@@ -135,6 +137,16 @@
   (and (match_code "const_int")
        (match_test "CONST_OK_FOR_J16 (ival)")))
 
+(define_constraint "Jmb"
+  "Low byte mask constant 0x000000FF"
+  (and (match_code "const_int")
+       (match_test "ival == 0xFF")))
+
+(define_constraint "Jmw"
+  "Low word mask constant 0x0000FFFF"
+  (and (match_code "const_int")
+       (match_test "ival == 0xFFFF")))
+
 (define_constraint "K03"
   "An unsigned 3-bit constant, as used in SH2A bclr, bset, etc."
   (and (match_code "const_int")
diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md
index d58f657c857de9fc979df3ad22a65f675ec6f103..3e7efd3504483d7a156a2b93c71f8087564fe72d 100644
--- a/gcc/config/sh/predicates.md
+++ b/gcc/config/sh/predicates.md
@@ -574,6 +574,21 @@
   return 0;
 })
 
+;; Like logical_operand but allows additional constant values which can be
+;; done with zero extensions.  Used for the second operand of and insns.
+(define_predicate "logical_and_operand"
+  (match_code "subreg,reg,const_int")
+{
+  if (logical_operand (op, mode))
+    return 1;
+
+  if (! TARGET_SHMEDIA
+      && (satisfies_constraint_Jmb (op) || satisfies_constraint_Jmw (op)))
+    return 1;
+
+  return 0;
+})
+
 ;; TODO: Add a comment here.
 
 (define_predicate "logical_operator"
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 4e2425f4888e0d706ea11fae490ac2a3d34542f9..1dda1943cba7065f3193e2c1397cec57e694f232 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -3113,12 +3113,55 @@ label:
 ;; Logical operations
 ;; -------------------------------------------------------------------------
 
-(define_insn "*andsi3_compact"
-  [(set (match_operand:SI 0 "arith_reg_dest" "=z,r")
-	(and:SI (match_operand:SI 1 "arith_reg_operand" "%0,0")
-		(match_operand:SI 2 "logical_operand" "K08,r")))]
+(define_expand "andsi3"
+  [(set (match_operand:SI 0 "arith_reg_operand" "")
+	(and:SI (match_operand:SI 1 "logical_reg_operand" "")
+		(match_operand:SI 2 "logical_and_operand" "")))]
+  ""
+{
+  /* If it is possible to turn the and insn into a zero extension
+     already, redundant zero extensions will be folded, which results
+     in better code.  
+     Ideally the splitter of *andsi_compact would be enough, if reundant
+     zero extensions were detected after the combine pass, which does not
+     happen at the moment.  */
+  if (TARGET_SH1)
+    {
+      if (satisfies_constraint_Jmb (operands[2]))
+	{
+	  emit_insn (gen_zero_extendqisi2 (operands[0],
+					   gen_lowpart (QImode, operands[1])));
+	  DONE;
+	}
+      else if (satisfies_constraint_Jmw (operands[2]))
+	{
+	  emit_insn (gen_zero_extendhisi2 (operands[0],
+					   gen_lowpart (HImode, operands[1])));
+	  DONE;
+	}
+    }
+})
+
+(define_insn_and_split "*andsi_compact"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=r,r,z,r")
+	(and:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,0,0")
+		(match_operand:SI 2 "logical_and_operand" "Jmb,Jmw,K08,r")))]
   "TARGET_SH1"
-  "and	%2,%0"
+  "@
+	extu.b	%1,%0
+	extu.w	%1,%0
+	and	%2,%0
+	and	%2,%0"
+  "&& 1"
+ [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+{
+  if (satisfies_constraint_Jmb (operands[2]))
+    operands[1] = gen_lowpart (QImode, operands[1]);
+  else if (satisfies_constraint_Jmw (operands[2]))
+    operands[1] = gen_lowpart (HImode, operands[1]);
+  else
+    FAIL;
+}
   [(set_attr "type" "arith")])
 
 (define_insn "*andsi3_media"
@@ -3139,24 +3182,6 @@ label:
   "bclr\\t%W2,%0"
   [(set_attr "type" "arith")])
 
-;; If the constant is 255, then emit an extu.b instruction instead of an
-;; and, since that will give better code.
-
-(define_expand "andsi3"
-  [(set (match_operand:SI 0 "arith_reg_operand" "")
-	(and:SI (match_operand:SI 1 "logical_reg_operand" "")
-		(match_operand:SI 2 "logical_operand" "")))]
-  ""
-{
-  if (TARGET_SH1
-      && CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 255)
-    {
-      emit_insn (gen_zero_extendqisi2 (operands[0],
-				       gen_lowpart (QImode, operands[1])));
-      DONE;
-    }
-})
-
 (define_insn_and_split "anddi3"
   [(set (match_operand:DI 0 "arith_reg_dest" "=r,r,r")
 	(and:DI (match_operand:DI 1 "arith_reg_operand" "%r,r,r")