Patchwork Fix undefined behavior in the combiner

login
register
mail settings
Submitter Jakub Jelinek
Date March 25, 2014, 7:12 a.m.
Message ID <20140325071248.GJ1817@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/333298/
State New
Headers show

Comments

Jakub Jelinek - March 25, 2014, 7:12 a.m.
Hi!

simplify_compare_const is sometimes called with two CONST_INTs,
which means mode is VOIDmode and mode_width is 0, but then it
happily verifies that mode_width is <= HOST_BITS_PER_WIDE_INT
and shits stuff by mode_width - 1 (i.e. -1).
From what I can understand, some optimizations can be still
performed even when we don't know the mode width, and sometimes
the caller knows the mode of op0, so it makes sense to pass it down
to let the function take it into account.

Bootstrapped/regtested on x86_64-linux and i686-linux, tested also
with --with-build-config=bootstrap-ubsan bootstrap.
Ok for trunk?

2014-03-25  Jakub Jelinek  <jakub@redhat.com>

	* combine.c (simplify_compare_const): Add MODE argument.
	Handle mode_width 0 as very large mode_width.
	(try_combine, simplify_comparison): Adjust callers.


	Jakub
Richard Guenther - March 25, 2014, 9:06 a.m.
On Tue, 25 Mar 2014, Jakub Jelinek wrote:

> Hi!
> 
> simplify_compare_const is sometimes called with two CONST_INTs,
> which means mode is VOIDmode and mode_width is 0, but then it
> happily verifies that mode_width is <= HOST_BITS_PER_WIDE_INT
> and shits stuff by mode_width - 1 (i.e. -1).
> From what I can understand, some optimizations can be still
> performed even when we don't know the mode width, and sometimes
> the caller knows the mode of op0, so it makes sense to pass it down
> to let the function take it into account.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, tested also
> with --with-build-config=bootstrap-ubsan bootstrap.
> Ok for trunk?

Ok.

Thanks,
Richard.

> 2014-03-25  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* combine.c (simplify_compare_const): Add MODE argument.
> 	Handle mode_width 0 as very large mode_width.
> 	(try_combine, simplify_comparison): Adjust callers.
> 
> --- gcc/combine.c.jj	2014-03-03 08:24:33.000000000 +0100
> +++ gcc/combine.c	2014-03-24 11:31:13.390695208 +0100
> @@ -446,7 +446,8 @@ static rtx simplify_shift_const (rtx, en
>  				 int);
>  static int recog_for_combine (rtx *, rtx, rtx *);
>  static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
> -static enum rtx_code simplify_compare_const (enum rtx_code, rtx, rtx *);
> +static enum rtx_code simplify_compare_const (enum rtx_code, enum machine_mode,
> +					     rtx, rtx *);
>  static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
>  static void update_table_tick (rtx);
>  static void record_value_for_reg (rtx, rtx, rtx);
> @@ -2949,7 +2950,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx
>  	{
>  	  compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
>  	  compare_code = simplify_compare_const (compare_code,
> -						 op0, &op1);
> +						 GET_MODE (i2dest), op0, &op1);
>  	  target_canonicalize_comparison (&compare_code, &op0, &op1, 1);
>  	}
>  
> @@ -10817,9 +10818,9 @@ gen_lowpart_for_combine (enum machine_mo
>     *POP1 may be updated.  */
>  
>  static enum rtx_code
> -simplify_compare_const (enum rtx_code code, rtx op0, rtx *pop1)
> +simplify_compare_const (enum rtx_code code, enum machine_mode mode,
> +			rtx op0, rtx *pop1)
>  {
> -  enum machine_mode mode = GET_MODE (op0);
>    unsigned int mode_width = GET_MODE_PRECISION (mode);
>    HOST_WIDE_INT const_op = INTVAL (*pop1);
>  
> @@ -10835,7 +10836,7 @@ simplify_compare_const (enum rtx_code co
>    if (const_op
>        && (code == EQ || code == NE || code == GE || code == GEU
>  	  || code == LT || code == LTU)
> -      && mode_width <= HOST_BITS_PER_WIDE_INT
> +      && mode_width - 1 < HOST_BITS_PER_WIDE_INT
>        && exact_log2 (const_op & GET_MODE_MASK (mode)) >= 0
>        && (nonzero_bits (op0, mode)
>  	  == (unsigned HOST_WIDE_INT) (const_op & GET_MODE_MASK (mode))))
> @@ -10882,7 +10883,7 @@ 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 <= HOST_BITS_PER_WIDE_INT
> +	       && mode_width - 1 < HOST_BITS_PER_WIDE_INT
>  	       && (nonzero_bits (op0, mode)
>  		   & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
>  	       == 0)
> @@ -10911,7 +10912,7 @@ 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 <= HOST_BITS_PER_WIDE_INT
> +	       && mode_width - 1 < HOST_BITS_PER_WIDE_INT
>  	       && (nonzero_bits (op0, mode)
>  		   & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
>  	       == 0)
> @@ -10927,7 +10928,7 @@ simplify_compare_const (enum rtx_code co
>  	  /* ... fall through ...  */
>  	}
>        /* (unsigned) < 0x80000000 is equivalent to >= 0.  */
> -      else if (mode_width <= HOST_BITS_PER_WIDE_INT
> +      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
>  	       && (unsigned HOST_WIDE_INT) const_op
>  	       == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1))
>  	{
> @@ -10943,7 +10944,7 @@ simplify_compare_const (enum rtx_code co
>        if (const_op == 0)
>  	code = EQ;
>        /* (unsigned) <= 0x7fffffff is equivalent to >= 0.  */
> -      else if (mode_width <= HOST_BITS_PER_WIDE_INT
> +      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
>  	       && (unsigned HOST_WIDE_INT) const_op
>  	       == ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
>  	{
> @@ -10962,7 +10963,7 @@ simplify_compare_const (enum rtx_code co
>  	}
>  
>        /* (unsigned) >= 0x80000000 is equivalent to < 0.  */
> -      else if (mode_width <= HOST_BITS_PER_WIDE_INT
> +      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
>  	       && (unsigned HOST_WIDE_INT) const_op
>  	       == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1))
>  	{
> @@ -10978,7 +10979,7 @@ simplify_compare_const (enum rtx_code co
>        if (const_op == 0)
>  	code = NE;
>        /* (unsigned) > 0x7fffffff is equivalent to < 0.  */
> -      else if (mode_width <= HOST_BITS_PER_WIDE_INT
> +      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
>  	       && (unsigned HOST_WIDE_INT) const_op
>  	       == ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
>  	{
> @@ -11185,7 +11186,7 @@ simplify_comparison (enum rtx_code code,
>  
>        /* Try to simplify the compare to constant, possibly changing the
>  	 comparison op, and/or changing op1 to zero.  */
> -      code = simplify_compare_const (code, op0, &op1);
> +      code = simplify_compare_const (code, mode, op0, &op1);
>        const_op = INTVAL (op1);
>  
>        /* Compute some predicates to simplify code below.  */
> 
> 	Jakub
> 
>

Patch

--- gcc/combine.c.jj	2014-03-03 08:24:33.000000000 +0100
+++ gcc/combine.c	2014-03-24 11:31:13.390695208 +0100
@@ -446,7 +446,8 @@  static rtx simplify_shift_const (rtx, en
 				 int);
 static int recog_for_combine (rtx *, rtx, rtx *);
 static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
-static enum rtx_code simplify_compare_const (enum rtx_code, rtx, rtx *);
+static enum rtx_code simplify_compare_const (enum rtx_code, enum machine_mode,
+					     rtx, rtx *);
 static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
 static void update_table_tick (rtx);
 static void record_value_for_reg (rtx, rtx, rtx);
@@ -2949,7 +2950,7 @@  try_combine (rtx i3, rtx i2, rtx i1, rtx
 	{
 	  compare_code = orig_compare_code = GET_CODE (*cc_use_loc);
 	  compare_code = simplify_compare_const (compare_code,
-						 op0, &op1);
+						 GET_MODE (i2dest), op0, &op1);
 	  target_canonicalize_comparison (&compare_code, &op0, &op1, 1);
 	}
 
@@ -10817,9 +10818,9 @@  gen_lowpart_for_combine (enum machine_mo
    *POP1 may be updated.  */
 
 static enum rtx_code
-simplify_compare_const (enum rtx_code code, rtx op0, rtx *pop1)
+simplify_compare_const (enum rtx_code code, enum machine_mode mode,
+			rtx op0, rtx *pop1)
 {
-  enum machine_mode mode = GET_MODE (op0);
   unsigned int mode_width = GET_MODE_PRECISION (mode);
   HOST_WIDE_INT const_op = INTVAL (*pop1);
 
@@ -10835,7 +10836,7 @@  simplify_compare_const (enum rtx_code co
   if (const_op
       && (code == EQ || code == NE || code == GE || code == GEU
 	  || code == LT || code == LTU)
-      && mode_width <= HOST_BITS_PER_WIDE_INT
+      && mode_width - 1 < HOST_BITS_PER_WIDE_INT
       && exact_log2 (const_op & GET_MODE_MASK (mode)) >= 0
       && (nonzero_bits (op0, mode)
 	  == (unsigned HOST_WIDE_INT) (const_op & GET_MODE_MASK (mode))))
@@ -10882,7 +10883,7 @@  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 <= HOST_BITS_PER_WIDE_INT
+	       && mode_width - 1 < HOST_BITS_PER_WIDE_INT
 	       && (nonzero_bits (op0, mode)
 		   & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
 	       == 0)
@@ -10911,7 +10912,7 @@  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 <= HOST_BITS_PER_WIDE_INT
+	       && mode_width - 1 < HOST_BITS_PER_WIDE_INT
 	       && (nonzero_bits (op0, mode)
 		   & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
 	       == 0)
@@ -10927,7 +10928,7 @@  simplify_compare_const (enum rtx_code co
 	  /* ... fall through ...  */
 	}
       /* (unsigned) < 0x80000000 is equivalent to >= 0.  */
-      else if (mode_width <= HOST_BITS_PER_WIDE_INT
+      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
 	       && (unsigned HOST_WIDE_INT) const_op
 	       == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1))
 	{
@@ -10943,7 +10944,7 @@  simplify_compare_const (enum rtx_code co
       if (const_op == 0)
 	code = EQ;
       /* (unsigned) <= 0x7fffffff is equivalent to >= 0.  */
-      else if (mode_width <= HOST_BITS_PER_WIDE_INT
+      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
 	       && (unsigned HOST_WIDE_INT) const_op
 	       == ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
 	{
@@ -10962,7 +10963,7 @@  simplify_compare_const (enum rtx_code co
 	}
 
       /* (unsigned) >= 0x80000000 is equivalent to < 0.  */
-      else if (mode_width <= HOST_BITS_PER_WIDE_INT
+      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
 	       && (unsigned HOST_WIDE_INT) const_op
 	       == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1))
 	{
@@ -10978,7 +10979,7 @@  simplify_compare_const (enum rtx_code co
       if (const_op == 0)
 	code = NE;
       /* (unsigned) > 0x7fffffff is equivalent to < 0.  */
-      else if (mode_width <= HOST_BITS_PER_WIDE_INT
+      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
 	       && (unsigned HOST_WIDE_INT) const_op
 	       == ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
 	{
@@ -11185,7 +11186,7 @@  simplify_comparison (enum rtx_code code,
 
       /* Try to simplify the compare to constant, possibly changing the
 	 comparison op, and/or changing op1 to zero.  */
-      code = simplify_compare_const (code, op0, &op1);
+      code = simplify_compare_const (code, mode, op0, &op1);
       const_op = INTVAL (op1);
 
       /* Compute some predicates to simplify code below.  */