This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the EGCS project.
64 to (nearly) 32 bit cross fix
- To: gcc-patches@gcc.gnu.org
- Subject: 64 to (nearly) 32 bit cross fix
- From: Richard Henderson <rth@cygnus.com>
- Date: Thu, 22 Jul 1999 18:20:45 -0700
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));