64 to (nearly) 32 bit cross fix

Richard Henderson rth@cygnus.com
Thu Jul 22 18:20:00 GMT 1999


Consider a target with 64-bit words but a 32-bit Pmode.
Begin with a tree like

	minus
	  plus
	    symbol foo
	    const 8
	  const 8

we'll fold this to

	plus
	  plus
	    symbol foo
	    const 8
	  const 0xfffffff8

During expansion, we'll try plus_constant on

	(const:SI (symbol_ref:SI foo)
		  (const_int 8))

	(const_int 0xfffffff8)

resulting in

	(const:SI (symbol_ref:SI foo)
		  (const_int 0x100000000))

which is clearly wrong.

A solution Wilson suggested is, since we have a mode available on
the const, make plus_constant truncate the value as appropriate.

I've checked in the following.


r~


	* explow.c (trunc_int_for_mode): New function.
	(plus_constant_wide): Use it.
	* combine.c (simplify_and_const_int): Likewise.
	(merge_outer_ops): Likewise.
	(simplify_shift_const): Likewise.
	* cse.c (simplify_unary_operation): Likewise.
	(simplify_binary_operation): Likewise.
	* emit-rtl.c (operand_subword): Likewise.
	* rtl.h: Declare it.


Index: combine.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/combine.c,v
retrieving revision 1.63
diff -c -p -d -r1.63 combine.c
*** combine.c	1999/06/14 13:10:29	1.63
--- combine.c	1999/07/23 01:10:51
*************** simplify_and_const_int (x, mode, varop, 
*** 7336,7354 ****
       MODE.  */
  
    nonzero = nonzero_bits (varop, mode) & GET_MODE_MASK (mode);
! 
!   /* If this would be an entire word for the target, but is not for
!      the host, then sign-extend on the host so that the number will look
!      the same way on the host that it would on the target.
! 
!      For example, when building a 64 bit alpha hosted 32 bit sparc
!      targeted compiler, then we want the 32 bit unsigned value -1 to be
!      represented as a 64 bit value -1, and not as 0x00000000ffffffff.
!      The later confuses the sparc backend.  */
! 
!   if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
!       && (nonzero & ((HOST_WIDE_INT) 1 << (width - 1))))
!     nonzero |= ((HOST_WIDE_INT) (-1) << width);
  
    /* Turn off all bits in the constant that are known to already be zero.
       Thus, if the AND isn't needed at all, we will have CONSTOP == NONZERO_BITS
--- 7336,7342 ----
       MODE.  */
  
    nonzero = nonzero_bits (varop, mode) & GET_MODE_MASK (mode);
!   nonzero = trunc_int_for_mode (nonzero, mode);
  
    /* Turn off all bits in the constant that are known to already be zero.
       Thus, if the AND isn't needed at all, we will have CONSTOP == NONZERO_BITS
*************** merge_outer_ops (pop0, pconst0, op1, con
*** 8326,8344 ****
    else if ((unsigned HOST_WIDE_INT) const0 == GET_MODE_MASK (mode)
  	   && op0 == AND)
      op0 = NIL;
- 
-   /* If this would be an entire word for the target, but is not for
-      the host, then sign-extend on the host so that the number will look
-      the same way on the host that it would on the target.
- 
-      For example, when building a 64 bit alpha hosted 32 bit sparc
-      targeted compiler, then we want the 32 bit unsigned value -1 to be
-      represented as a 64 bit value -1, and not as 0x00000000ffffffff.
-      The later confuses the sparc backend.  */
  
!   if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
!       && (const0 & ((HOST_WIDE_INT) 1 << (width - 1))))
!     const0 |= ((HOST_WIDE_INT) (-1) << width);
  
    *pop0 = op0;
    *pconst0 = const0;
--- 8314,8324 ----
    else if ((unsigned HOST_WIDE_INT) const0 == GET_MODE_MASK (mode)
  	   && op0 == AND)
      op0 = NIL;
  
!   /* ??? Slightly redundant with the above mask, but not entirely.
!      Moving this above means we'd have to sign-extend the mode mask
!      for the final test.  */
!   const0 = trunc_int_for_mode (const0, mode);
  
    *pop0 = op0;
    *pconst0 = const0;
*************** simplify_shift_const (x, code, result_mo
*** 9053,9076 ****
    if (outer_op != NIL)
      {
        if (GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT)
! 	{
! 	  int width = GET_MODE_BITSIZE (result_mode);
! 
! 	  outer_const &= GET_MODE_MASK (result_mode);
! 
! 	  /* If this would be an entire word for the target, but is not for
! 	     the host, then sign-extend on the host so that the number will
! 	     look the same way on the host that it would on the target.
! 
! 	     For example, when building a 64 bit alpha hosted 32 bit sparc
! 	     targeted compiler, then we want the 32 bit unsigned value -1 to be
! 	     represented as a 64 bit value -1, and not as 0x00000000ffffffff.
! 	     The later confuses the sparc backend.  */
! 
! 	  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
! 	      && (outer_const & ((HOST_WIDE_INT) 1 << (width - 1))))
! 	    outer_const |= ((HOST_WIDE_INT) (-1) << width);
! 	}
  
        if (outer_op == AND)
  	x = simplify_and_const_int (NULL_RTX, result_mode, x, outer_const);
--- 9033,9039 ----
    if (outer_op != NIL)
      {
        if (GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT)
! 	outer_const = trunc_int_for_mode (outer_const, result_mode);
  
        if (outer_op == AND)
  	x = simplify_and_const_int (NULL_RTX, result_mode, x, outer_const);
Index: cse.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cse.c,v
retrieving revision 1.73
diff -c -p -d -r1.73 cse.c
*** cse.c	1999/06/16 13:32:14	1.73
--- cse.c	1999/07/23 01:10:51
*************** simplify_unary_operation (code, mode, op
*** 3364,3390 ****
  	  abort ();
  	}
  
!       /* Clear the bits that don't belong in our mode,
! 	 unless they and our sign bit are all one.
! 	 So we get either a reasonable negative value or a reasonable
! 	 unsigned value for this mode.  */
!       if (width < HOST_BITS_PER_WIDE_INT
! 	  && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
! 	      != ((HOST_WIDE_INT) (-1) << (width - 1))))
! 	val &= ((HOST_WIDE_INT) 1 << width) - 1;
! 
!       /* If this would be an entire word for the target, but is not for
! 	 the host, then sign-extend on the host so that the number will look
! 	 the same way on the host that it would on the target.
! 
! 	 For example, when building a 64 bit alpha hosted 32 bit sparc
! 	 targeted compiler, then we want the 32 bit unsigned value -1 to be
! 	 represented as a 64 bit value -1, and not as 0x00000000ffffffff.
! 	 The later confuses the sparc backend.  */
! 
!       if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
! 	  && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
! 	val |= ((HOST_WIDE_INT) (-1) << width);
  
        return GEN_INT (val);
      }
--- 3364,3370 ----
  	  abort ();
  	}
  
!       val = trunc_int_for_mode (val, mode);
  
        return GEN_INT (val);
      }
*************** simplify_unary_operation (code, mode, op
*** 3555,3582 ****
  	}
  
        set_float_handler (NULL_PTR);
- 
-       /* Clear the bits that don't belong in our mode,
- 	 unless they and our sign bit are all one.
- 	 So we get either a reasonable negative value or a reasonable
- 	 unsigned value for this mode.  */
-       if (width < HOST_BITS_PER_WIDE_INT
- 	  && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
- 	      != ((HOST_WIDE_INT) (-1) << (width - 1))))
- 	val &= ((HOST_WIDE_INT) 1 << width) - 1;
  
!       /* If this would be an entire word for the target, but is not for
! 	 the host, then sign-extend on the host so that the number will look
! 	 the same way on the host that it would on the target.
! 
! 	 For example, when building a 64 bit alpha hosted 32 bit sparc
! 	 targeted compiler, then we want the 32 bit unsigned value -1 to be
! 	 represented as a 64 bit value -1, and not as 0x00000000ffffffff.
! 	 The later confuses the sparc backend.  */
! 
!       if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
! 	  && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
! 	val |= ((HOST_WIDE_INT) (-1) << width);
  
        return GEN_INT (val);
      }
--- 3535,3542 ----
  	}
  
        set_float_handler (NULL_PTR);
  
!       val = trunc_int_for_mode (val, mode);
  
        return GEN_INT (val);
      }
*************** simplify_binary_operation (code, mode, o
*** 4457,4483 ****
      default:
        abort ();
      }
- 
-   /* Clear the bits that don't belong in our mode, unless they and our sign
-      bit are all one.  So we get either a reasonable negative value or a
-      reasonable unsigned value for this mode.  */
-   if (width < HOST_BITS_PER_WIDE_INT
-       && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
- 	  != ((HOST_WIDE_INT) (-1) << (width - 1))))
-     val &= ((HOST_WIDE_INT) 1 << width) - 1;
- 
-   /* If this would be an entire word for the target, but is not for
-      the host, then sign-extend on the host so that the number will look
-      the same way on the host that it would on the target.
- 
-      For example, when building a 64 bit alpha hosted 32 bit sparc
-      targeted compiler, then we want the 32 bit unsigned value -1 to be
-      represented as a 64 bit value -1, and not as 0x00000000ffffffff.
-      The later confuses the sparc backend.  */
  
!   if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
!       && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
!     val |= ((HOST_WIDE_INT) (-1) << width);
  
    return GEN_INT (val);
  }
--- 4417,4424 ----
      default:
        abort ();
      }
  
!   val = trunc_int_for_mode (val, mode);
  
    return GEN_INT (val);
  }
Index: emit-rtl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/emit-rtl.c,v
retrieving revision 1.62
diff -c -p -d -r1.62 emit-rtl.c
*** emit-rtl.c	1999/07/14 23:04:45	1.62
--- emit-rtl.c	1999/07/23 01:10:51
*************** operand_subword (op, i, validate_address
*** 1489,1514 ****
    if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT)
      val = ((val >> ((i % size_ratio) * BITS_PER_WORD)));
  
!   /* Clear the bits that don't belong in our mode, unless they and our sign
!      bit are all one.  So we get either a reasonable negative value or a
!      reasonable unsigned value for this mode.  */
!   if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
!       && ((val & ((HOST_WIDE_INT) (-1) << (bits_per_word - 1)))
!           != ((HOST_WIDE_INT) (-1) << (bits_per_word - 1))))
!     val &= ((HOST_WIDE_INT) 1 << bits_per_word) - 1;
! 
!   /* If this would be an entire word for the target, but is not for
!      the host, then sign-extend on the host so that the number will look
!      the same way on the host that it would on the target.
! 
!      For example, when building a 64 bit alpha hosted 32 bit sparc
!      targeted compiler, then we want the 32 bit unsigned value -1 to be
!      represented as a 64 bit value -1, and not as 0x00000000ffffffff.
!      The later confuses the sparc backend.  */
! 
!   if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
!       && (val & ((HOST_WIDE_INT) 1 << (bits_per_word - 1))))
!     val |= ((HOST_WIDE_INT) (-1) << bits_per_word);
  
    return GEN_INT (val);
  }
--- 1489,1495 ----
    if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT)
      val = ((val >> ((i % size_ratio) * BITS_PER_WORD)));
  
!   val = trunc_int_for_mode (val, word_mode);
  
    return GEN_INT (val);
  }
Index: explow.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/explow.c,v
retrieving revision 1.28
diff -c -p -d -r1.28 explow.c
*** explow.c	1999/04/17 17:14:48	1.28
--- explow.c	1999/07/23 01:10:51
*************** Boston, MA 02111-1307, USA.  */
*** 38,43 ****
--- 38,80 ----
  
  static rtx break_out_memory_refs	PROTO((rtx));
  static void emit_stack_probe		PROTO((rtx));
+ 
+ 
+ /* Truncate and perhaps sign-extend C as appropriate for MODE.  */
+ 
+ HOST_WIDE_INT
+ trunc_int_for_mode (c, mode)
+      HOST_WIDE_INT c;
+      enum machine_mode mode;
+ {
+   int width = GET_MODE_BITSIZE (mode);
+ 
+   /* We clear out all bits that don't belong in MODE, unless they and our
+      sign bit are all one.  So we get either a reasonable negative
+      value or a reasonable unsigned value.  */
+ 
+   if (width < HOST_BITS_PER_WIDE_INT
+       && ((c & ((HOST_WIDE_INT) (-1) << (width - 1)))
+            != ((HOST_WIDE_INT) (-1) << (width - 1))))
+     c &= ((HOST_WIDE_INT) 1 << width) - 1;
+ 
+   /* If this would be an entire word for the target, but is not for
+      the host, then sign-extend on the host so that the number will look
+      the same way on the host that it would on the target.
+ 
+      For example, when building a 64 bit alpha hosted 32 bit sparc
+      targeted compiler, then we want the 32 bit unsigned value -1 to be
+      represented as a 64 bit value -1, and not as 0x00000000ffffffff.
+      The later confuses the sparc backend.  */
+ 
+   if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
+       && BITS_PER_WORD == width
+       && (c & ((HOST_WIDE_INT) 1 << (width - 1))))
+     c |= ((HOST_WIDE_INT) (-1) << width);
+ 
+   return c;
+ }
+ 
  /* Return an rtx for the sum of X and the integer C.
  
     This function should be used via the `plus_constant' macro.  */
*************** plus_constant_wide (x, c)
*** 126,131 ****
--- 163,172 ----
        if (GET_CODE (XEXP (x, 1)) == CONST_INT)
  	{
  	  c += INTVAL (XEXP (x, 1));
+ 
+ 	  if (GET_MODE (x) != VOIDmode)
+ 	    c = trunc_int_for_mode (c, GET_MODE (x));
+ 
  	  x = XEXP (x, 0);
  	  goto restart;
  	}
Index: rtl.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/rtl.h,v
retrieving revision 1.105
diff -c -p -d -r1.105 rtl.h
*** rtl.h	1999/04/27 17:08:34	1.105
--- rtl.h	1999/07/23 01:10:51
*************** extern int ceil_log2			PROTO((unsigned H
*** 909,914 ****
--- 909,916 ----
    plus_constant_for_output_wide (X, (HOST_WIDE_INT) (C))
  
  /* In explow.c */
+ extern HOST_WIDE_INT trunc_int_for_mode	PROTO((HOST_WIDE_INT,
+ 					       enum machine_mode));
  extern rtx plus_constant_wide		 PROTO((rtx, HOST_WIDE_INT));
  extern rtx plus_constant_for_output_wide PROTO((rtx, HOST_WIDE_INT));
  extern void optimize_save_area_alloca	PROTO((rtx));


More information about the Gcc-patches mailing list