diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index e37ef9f..a33b9d3 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -1108,6 +1108,8 @@ static tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *);
 static tree rs6000_handle_struct_attribute (tree *, tree, tree, int, bool *);
 static tree rs6000_builtin_vectorized_libmass (tree, tree, tree);
 static void rs6000_emit_set_long_const (rtx, HOST_WIDE_INT);
+static bool rs6000_is_valid_and_mask_wide (unsigned HOST_WIDE_INT val,
+					   machine_mode mode);
 static int rs6000_memory_move_cost (machine_mode, reg_class_t, bool);
 static bool rs6000_debug_rtx_costs (rtx, machine_mode, int, int, int *, bool);
 static int rs6000_debug_address_cost (rtx, machine_mode, addr_space_t,
@@ -16378,18 +16380,13 @@ validate_condition_mode (enum rtx_code code, machine_mode mode)
    the single stretch of 1 bits begins; and similarly for B, the bit
    offset where it ends.  */
 
-bool
-rs6000_is_valid_mask (rtx mask, int *b, int *e, machine_mode mode)
+static bool
+rs6000_is_valid_mask_wide (unsigned HOST_WIDE_INT val, int *b, int *e, int n)
 {
-  unsigned HOST_WIDE_INT val = INTVAL (mask);
   unsigned HOST_WIDE_INT bit;
   int nb, ne;
-  int n = GET_MODE_PRECISION (mode);
 
-  if (mode != DImode && mode != SImode)
-    return false;
-
-  if (INTVAL (mask) >= 0)
+  if ((HOST_WIDE_INT)val >= 0)
     {
       bit = val & -val;
       ne = exact_log2 (bit);
@@ -16430,27 +16427,54 @@ rs6000_is_valid_mask (rtx mask, int *b, int *e, machine_mode mode)
   return true;
 }
 
+bool
+rs6000_is_valid_mask (rtx mask, int *b, int *e, machine_mode mode)
+{
+  int n;
+
+  if (mode == DImode)
+    n = 64;
+  else if (mode == SImode)
+    n = 32;
+  else
+    return false;
+
+  unsigned HOST_WIDE_INT val = INTVAL (mask);
+  return rs6000_is_valid_mask_wide (val, b, e, n);
+}
+
 /* Return whether MASK (a CONST_INT) is a valid mask for any rlwinm, rldicl,
    or rldicr instruction, to implement an AND with it in mode MODE.  */
 
-bool
-rs6000_is_valid_and_mask (rtx mask, machine_mode mode)
+static bool
+rs6000_is_valid_and_mask_wide (unsigned HOST_WIDE_INT val, machine_mode mode)
 {
   int nb, ne;
 
-  if (!rs6000_is_valid_mask (mask, &nb, &ne, mode))
-    return false;
+  switch (mode)
+    {
+    case DImode:
+      if (!rs6000_is_valid_mask_wide (val, &nb, &ne, 64))
+	return false;
+      /* For DImode, we need a rldicl, rldicr, or a rlwinm with
+	 mask that does not wrap.  */
+      return (ne == 0 || nb == 63 || (nb < 32 && ne <= nb));
 
-  /* For DImode, we need a rldicl, rldicr, or a rlwinm with mask that
-     does not wrap.  */
-  if (mode == DImode)
-    return (ne == 0 || nb == 63 || (nb < 32 && ne <= nb));
+    case SImode:
+      if (!rs6000_is_valid_mask_wide (val, &nb, &ne, 32))
+	return false;
+      /* For SImode, rlwinm can do everything.  */
+      return (nb < 32 && ne < 32);
 
-  /* For SImode, rlwinm can do everything.  */
-  if (mode == SImode)
-    return (nb < 32 && ne < 32);
+    default:
+      return false;
+    }
+}
 
-  return false;
+bool
+rs6000_is_valid_and_mask (rtx mask, machine_mode mode)
+{
+  return rs6000_is_valid_and_mask_wide (UINTVAL (mask), mode);
 }
 
 /* Return the instruction template for an AND with mask in mode MODE, with
@@ -16739,12 +16763,12 @@ rs6000_is_valid_2insn_and (rtx c, machine_mode mode)
 
   /* Otherwise, fill in the lowest "hole"; if we can do the result with
      one insn, we can do the whole thing with two.  */
-  unsigned HOST_WIDE_INT val = INTVAL (c);
+  unsigned HOST_WIDE_INT val = UINTVAL (c);
   unsigned HOST_WIDE_INT bit1 = val & -val;
   unsigned HOST_WIDE_INT bit2 = (val + bit1) & ~val;
   unsigned HOST_WIDE_INT val1 = (val + bit1) & val;
   unsigned HOST_WIDE_INT bit3 = val1 & -val1;
-  return rs6000_is_valid_and_mask (GEN_INT (val + bit3 - bit2), mode);
+  return rs6000_is_valid_and_mask_wide (val + bit3 - bit2, mode);
 }
 
 /* Emit a potentially record-form instruction, setting DST from SRC.
@@ -16835,10 +16859,10 @@ rs6000_emit_2insn_and (machine_mode mode, rtx *operands, bool expand, int dot)
   unsigned HOST_WIDE_INT mask1 = -bit3 + bit2 - 1;
   unsigned HOST_WIDE_INT mask2 = val + bit3 - bit2;
 
-  gcc_assert (rs6000_is_valid_and_mask (GEN_INT (mask2), mode));
+  gcc_assert (rs6000_is_valid_and_mask_wide (mask2, mode));
 
   /* Two "no-rotate"-and-mask instructions, for SImode.  */
-  if (rs6000_is_valid_and_mask (GEN_INT (mask1), mode))
+  if (rs6000_is_valid_and_mask_wide (mask1, mode))
     {
       gcc_assert (mode == SImode);
 
@@ -16855,7 +16879,7 @@ rs6000_emit_2insn_and (machine_mode mode, rtx *operands, bool expand, int dot)
   /* Two "no-rotate"-and-mask instructions, for DImode: both are rlwinm
      insns; we have to do the first in SImode, because it wraps.  */
   if (mask2 <= 0xffffffff
-      && rs6000_is_valid_and_mask (GEN_INT (mask1), SImode))
+      && rs6000_is_valid_and_mask_wide (mask1, SImode))
     {
       rtx reg = expand ? gen_reg_rtx (mode) : operands[0];
       rtx tmp = gen_rtx_AND (SImode, gen_lowpart (SImode, operands[1]),
@@ -31070,7 +31094,7 @@ rs6000_rtx_costs (rtx x, machine_mode mode, int outer_code,
 
 	  /* rotate-and-mask (no rotate), andi., andis.: 1 insn.  */
 	  HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
-	  if (rs6000_is_valid_and_mask (XEXP (x, 1), mode)
+	  if (rs6000_is_valid_and_mask_wide (val, mode)
 	      || (val & 0xffff) == val
 	      || (val & 0xffff0000) == val
 	      || ((val & 0xffff) == 0 && mode == SImode))
