Index: gcc/combine.c
===================================================================
--- gcc/combine.c	2017-07-13 09:18:43.037447143 +0100
+++ gcc/combine.c	2017-07-13 09:18:43.379419324 +0100
@@ -11662,7 +11662,7 @@ gen_lowpart_for_combine (machine_mode om
 simplify_compare_const (enum rtx_code code, machine_mode mode,
 			rtx op0, rtx *pop1)
 {
-  unsigned int mode_width = GET_MODE_PRECISION (mode);
+  scalar_int_mode int_mode;
   HOST_WIDE_INT const_op = INTVAL (*pop1);
 
   /* Get the constant we are comparing against and turn off all bits
@@ -11677,10 +11677,11 @@ simplify_compare_const (enum rtx_code co
   if (const_op
       && (code == EQ || code == NE || code == GE || code == GEU
 	  || code == LT || code == LTU)
-      && mode_width - 1 < HOST_BITS_PER_WIDE_INT
-      && pow2p_hwi (const_op & GET_MODE_MASK (mode))
-      && (nonzero_bits (op0, mode)
-	  == (unsigned HOST_WIDE_INT) (const_op & GET_MODE_MASK (mode))))
+      && is_a <scalar_int_mode> (mode, &int_mode)
+      && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+      && pow2p_hwi (const_op & GET_MODE_MASK (int_mode))
+      && (nonzero_bits (op0, int_mode)
+	  == (unsigned HOST_WIDE_INT) (const_op & GET_MODE_MASK (int_mode))))
     {
       code = (code == EQ || code == GE || code == GEU ? NE : EQ);
       const_op = 0;
@@ -11691,7 +11692,8 @@ simplify_compare_const (enum rtx_code co
   if (const_op == -1
       && (code == EQ || code == NE || code == GT || code == LE
 	  || code == GEU || code == LTU)
-      && num_sign_bit_copies (op0, mode) == mode_width)
+      && is_a <scalar_int_mode> (mode, &int_mode)
+      && num_sign_bit_copies (op0, int_mode) == GET_MODE_PRECISION (int_mode))
     {
       code = (code == EQ || code == LE || code == GEU ? NE : EQ);
       const_op = 0;
@@ -11725,9 +11727,10 @@ simplify_compare_const (enum rtx_code co
       /* If we are doing a <= 0 comparison on a value known to have
 	 a zero sign bit, we can replace this with == 0.  */
       else if (const_op == 0
-	       && mode_width - 1 < HOST_BITS_PER_WIDE_INT
-	       && (nonzero_bits (op0, mode)
-		   & (HOST_WIDE_INT_1U << (mode_width - 1)))
+	       && is_a <scalar_int_mode> (mode, &int_mode)
+	       && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+	       && (nonzero_bits (op0, int_mode)
+		   & (HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
 	       == 0)
 	code = EQ;
       break;
@@ -11755,9 +11758,10 @@ simplify_compare_const (enum rtx_code co
       /* If we are doing a > 0 comparison on a value known to have
 	 a zero sign bit, we can replace this with != 0.  */
       else if (const_op == 0
-	       && mode_width - 1 < HOST_BITS_PER_WIDE_INT
-	       && (nonzero_bits (op0, mode)
-		   & (HOST_WIDE_INT_1U << (mode_width - 1)))
+	       && is_a <scalar_int_mode> (mode, &int_mode)
+	       && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+	       && (nonzero_bits (op0, int_mode)
+		   & (HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
 	       == 0)
 	code = NE;
       break;
@@ -11771,9 +11775,10 @@ simplify_compare_const (enum rtx_code co
 	  /* ... fall through ...  */
 	}
       /* (unsigned) < 0x80000000 is equivalent to >= 0.  */
-      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
-	       && (unsigned HOST_WIDE_INT) const_op
-	       == HOST_WIDE_INT_1U << (mode_width - 1))
+      else if (is_a <scalar_int_mode> (mode, &int_mode)
+	       && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+	       && ((unsigned HOST_WIDE_INT) const_op
+		   == HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
 	{
 	  const_op = 0;
 	  code = GE;
@@ -11787,9 +11792,11 @@ simplify_compare_const (enum rtx_code co
       if (const_op == 0)
 	code = EQ;
       /* (unsigned) <= 0x7fffffff is equivalent to >= 0.  */
-      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
-	       && (unsigned HOST_WIDE_INT) const_op
-	       == (HOST_WIDE_INT_1U << (mode_width - 1)) - 1)
+      else if (is_a <scalar_int_mode> (mode, &int_mode)
+	       && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+	       && ((unsigned HOST_WIDE_INT) const_op
+		   == ((HOST_WIDE_INT_1U
+			<< (GET_MODE_PRECISION (int_mode) - 1)) - 1)))
 	{
 	  const_op = 0;
 	  code = GE;
@@ -11806,9 +11813,10 @@ simplify_compare_const (enum rtx_code co
 	}
 
       /* (unsigned) >= 0x80000000 is equivalent to < 0.  */
-      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
-	       && (unsigned HOST_WIDE_INT) const_op
-	       == HOST_WIDE_INT_1U << (mode_width - 1))
+      else if (is_a <scalar_int_mode> (mode, &int_mode)
+	       && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+	       && ((unsigned HOST_WIDE_INT) const_op
+		   == HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
 	{
 	  const_op = 0;
 	  code = LT;
@@ -11822,9 +11830,11 @@ simplify_compare_const (enum rtx_code co
       if (const_op == 0)
 	code = NE;
       /* (unsigned) > 0x7fffffff is equivalent to < 0.  */
-      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
-	       && (unsigned HOST_WIDE_INT) const_op
-	       == (HOST_WIDE_INT_1U << (mode_width - 1)) - 1)
+      else if (is_a <scalar_int_mode> (mode, &int_mode)
+	       && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+	       && ((unsigned HOST_WIDE_INT) const_op
+		   == (HOST_WIDE_INT_1U
+		       << (GET_MODE_PRECISION (int_mode) - 1)) - 1))
 	{
 	  const_op = 0;
 	  code = LT;
@@ -12009,9 +12019,8 @@ simplify_comparison (enum rtx_code code,
 
   while (CONST_INT_P (op1))
     {
-      machine_mode mode = GET_MODE (op0);
-      unsigned int mode_width = GET_MODE_PRECISION (mode);
-      unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
+      machine_mode raw_mode = GET_MODE (op0);
+      scalar_int_mode int_mode;
       int equality_comparison_p;
       int sign_bit_comparison_p;
       int unsigned_comparison_p;
@@ -12022,14 +12031,14 @@ simplify_comparison (enum rtx_code code,
 	 can handle VOIDmode if OP0 is a COMPARE or a comparison
 	 operation.  */
 
-      if (GET_MODE_CLASS (mode) != MODE_INT
-	  && ! (mode == VOIDmode
+      if (GET_MODE_CLASS (raw_mode) != MODE_INT
+	  && ! (raw_mode == VOIDmode
 		&& (GET_CODE (op0) == COMPARE || COMPARISON_P (op0))))
 	break;
 
       /* Try to simplify the compare to constant, possibly changing the
 	 comparison op, and/or changing op1 to zero.  */
-      code = simplify_compare_const (code, mode, op0, &op1);
+      code = simplify_compare_const (code, raw_mode, op0, &op1);
       const_op = INTVAL (op1);
 
       /* Compute some predicates to simplify code below.  */
@@ -12041,16 +12050,62 @@ simplify_comparison (enum rtx_code code,
 
       /* If this is a sign bit comparison and we can do arithmetic in
 	 MODE, say that we will only be needing the sign bit of OP0.  */
-      if (sign_bit_comparison_p && HWI_COMPUTABLE_MODE_P (mode))
-	op0 = force_to_mode (op0, mode,
+      if (sign_bit_comparison_p
+	  && is_a <scalar_int_mode> (raw_mode, &int_mode)
+	  && HWI_COMPUTABLE_MODE_P (int_mode))
+	op0 = force_to_mode (op0, int_mode,
 			     HOST_WIDE_INT_1U
-			     << (GET_MODE_PRECISION (mode) - 1),
+			     << (GET_MODE_PRECISION (int_mode) - 1),
 			     0);
 
+      if (COMPARISON_P (op0))
+	{
+	  /* We can't do anything if OP0 is a condition code value, rather
+	     than an actual data value.  */
+	  if (const_op != 0
+	      || CC0_P (XEXP (op0, 0))
+	      || GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
+	    break;
+
+	  /* Get the two operands being compared.  */
+	  if (GET_CODE (XEXP (op0, 0)) == COMPARE)
+	    tem = XEXP (XEXP (op0, 0), 0), tem1 = XEXP (XEXP (op0, 0), 1);
+	  else
+	    tem = XEXP (op0, 0), tem1 = XEXP (op0, 1);
+
+	  /* Check for the cases where we simply want the result of the
+	     earlier test or the opposite of that result.  */
+	  if (code == NE || code == EQ
+	      || (val_signbit_known_set_p (raw_mode, STORE_FLAG_VALUE)
+		  && (code == LT || code == GE)))
+	    {
+	      enum rtx_code new_code;
+	      if (code == LT || code == NE)
+		new_code = GET_CODE (op0);
+	      else
+		new_code = reversed_comparison_code (op0, NULL);
+
+	      if (new_code != UNKNOWN)
+		{
+		  code = new_code;
+		  op0 = tem;
+		  op1 = tem1;
+		  continue;
+		}
+	    }
+	  break;
+	}
+
+      if (raw_mode == VOIDmode)
+	break;
+      scalar_int_mode mode = as_a <scalar_int_mode> (raw_mode);
+
       /* Now try cases based on the opcode of OP0.  If none of the cases
 	 does a "continue", we exit this loop immediately after the
 	 switch.  */
 
+      unsigned int mode_width = GET_MODE_PRECISION (mode);
+      unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
       switch (GET_CODE (op0))
 	{
 	case ZERO_EXTRACT:
@@ -12195,8 +12250,7 @@ simplify_comparison (enum rtx_code code,
 	     insn of the given mode, since we'd have to revert it
 	     later on, and then we wouldn't know whether to sign- or
 	     zero-extend.  */
-	  mode = GET_MODE (XEXP (op0, 0));
-	  if (GET_MODE_CLASS (mode) == MODE_INT
+	  if (is_int_mode (GET_MODE (XEXP (op0, 0)), &mode)
 	      && ! unsigned_comparison_p
 	      && HWI_COMPUTABLE_MODE_P (mode)
 	      && trunc_int_for_mode (const_op, mode) == const_op
@@ -12230,11 +12284,12 @@ simplify_comparison (enum rtx_code code,
 
 	  if (mode_width <= HOST_BITS_PER_WIDE_INT
 	      && subreg_lowpart_p (op0)
-	      && GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op0))) > mode_width
+	      && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (op0)),
+					 &inner_mode)
+	      && GET_MODE_PRECISION (inner_mode) > mode_width
 	      && GET_CODE (SUBREG_REG (op0)) == PLUS
 	      && CONST_INT_P (XEXP (SUBREG_REG (op0), 1)))
 	    {
-	      machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
 	      rtx a = XEXP (SUBREG_REG (op0), 0);
 	      HOST_WIDE_INT c1 = -INTVAL (XEXP (SUBREG_REG (op0), 1));
 
@@ -12271,19 +12326,19 @@ simplify_comparison (enum rtx_code code,
 	      && GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op0))) < mode_width)
 	    ;
 	  else if (subreg_lowpart_p (op0)
-		   && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+		   && GET_MODE_CLASS (mode) == MODE_INT
 		   && is_int_mode (GET_MODE (SUBREG_REG (op0)), &inner_mode)
 		   && (code == NE || code == EQ)
 		   && GET_MODE_PRECISION (inner_mode) <= HOST_BITS_PER_WIDE_INT
 		   && !paradoxical_subreg_p (op0)
 		   && (nonzero_bits (SUBREG_REG (op0), inner_mode)
-		       & ~GET_MODE_MASK (GET_MODE (op0))) == 0)
+		       & ~GET_MODE_MASK (mode)) == 0)
 	    {
 	      /* Remove outer subregs that don't do anything.  */
 	      tem = gen_lowpart (inner_mode, op1);
 
 	      if ((nonzero_bits (tem, inner_mode)
-		   & ~GET_MODE_MASK (GET_MODE (op0))) == 0)
+		   & ~GET_MODE_MASK (mode)) == 0)
 		{
 		  op0 = SUBREG_REG (op0);
 		  op1 = tem;
@@ -12297,8 +12352,7 @@ simplify_comparison (enum rtx_code code,
 	  /* FALLTHROUGH */
 
 	case ZERO_EXTEND:
-	  mode = GET_MODE (XEXP (op0, 0));
-	  if (GET_MODE_CLASS (mode) == MODE_INT
+	  if (is_int_mode (GET_MODE (XEXP (op0, 0)), &mode)
 	      && (unsigned_comparison_p || equality_comparison_p)
 	      && HWI_COMPUTABLE_MODE_P (mode)
 	      && (unsigned HOST_WIDE_INT) const_op <= GET_MODE_MASK (mode)
@@ -12387,45 +12441,6 @@ simplify_comparison (enum rtx_code code,
 	    }
 	  break;
 
-	case EQ:  case NE:
-	case UNEQ:  case LTGT:
-	case LT:  case LTU:  case UNLT:  case LE:  case LEU:  case UNLE:
-	case GT:  case GTU:  case UNGT:  case GE:  case GEU:  case UNGE:
-	case UNORDERED: case ORDERED:
-	  /* We can't do anything if OP0 is a condition code value, rather
-	     than an actual data value.  */
-	  if (const_op != 0
-	      || CC0_P (XEXP (op0, 0))
-	      || GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
-	    break;
-
-	  /* Get the two operands being compared.  */
-	  if (GET_CODE (XEXP (op0, 0)) == COMPARE)
-	    tem = XEXP (XEXP (op0, 0), 0), tem1 = XEXP (XEXP (op0, 0), 1);
-	  else
-	    tem = XEXP (op0, 0), tem1 = XEXP (op0, 1);
-
-	  /* Check for the cases where we simply want the result of the
-	     earlier test or the opposite of that result.  */
-	  if (code == NE || code == EQ
-	      || (val_signbit_known_set_p (GET_MODE (op0), STORE_FLAG_VALUE)
-		  && (code == LT || code == GE)))
-	    {
-	      enum rtx_code new_code;
-	      if (code == LT || code == NE)
-		new_code = GET_CODE (op0);
-	      else
-		new_code = reversed_comparison_code (op0, NULL);
-
-	      if (new_code != UNKNOWN)
-		{
-		  code = new_code;
-		  op0 = tem;
-		  op1 = tem1;
-		  continue;
-		}
-	    }
-	  break;
 
 	case IOR:
 	  /* The sign bit of (ior (plus X (const_int -1)) X) is nonzero
@@ -12697,7 +12712,7 @@ simplify_comparison (enum rtx_code code,
 	    {
 	      rtx inner = XEXP (XEXP (XEXP (op0, 0), 0), 0);
 	      rtx add_const = XEXP (XEXP (op0, 0), 1);
-	      rtx new_const = simplify_gen_binary (ASHIFTRT, GET_MODE (op0),
+	      rtx new_const = simplify_gen_binary (ASHIFTRT, mode,
 						   add_const, XEXP (op0, 1));
 
 	      op0 = simplify_gen_binary (PLUS, tmode,
