rtl.texi (const_double): Document as sign-extending.
* doc/rtl.texi (const_double): Document as sign-extending. * expmed.c (expand_mult): Ensure we don't use shift incorrectly. * emit-rtl.c (immed_double_int_const): Refine to state the value is signed. * simplify-rtx.c (mode_signbit_p): Add a fixme for wider than CONST_DOUBLE integers. (simplify_const_unary_operation, UNSIGNED_FLOAT): Ensure no negative values are converted. Fix conversions bigger than HOST_BITS_PER_WIDE_INT. (simplify_binary_operation_1): Ensure we don't use shift incorrectly. (simplify_immed_subreg): Sign-extend CONST_DOUBLEs. * explow.c (plus_constant_mode): Add. (plus_constant): Implement with plus_constant_mode. * rtl.h (plus_constant_mode): Add. From-SVN: r186147
This commit is contained in:
parent
b059fba469
commit
929e10f4cf
|
@ -1,3 +1,22 @@
|
|||
2012-04-04 Mike Stump <mikestump@comcast.net>
|
||||
|
||||
* doc/rtl.texi (const_double): Document as sign-extending.
|
||||
* expmed.c (expand_mult): Ensure we don't use shift
|
||||
incorrectly.
|
||||
* emit-rtl.c (immed_double_int_const): Refine to state the
|
||||
value is signed.
|
||||
* simplify-rtx.c (mode_signbit_p): Add a fixme for wider than
|
||||
CONST_DOUBLE integers.
|
||||
(simplify_const_unary_operation, UNSIGNED_FLOAT): Ensure no
|
||||
negative values are converted. Fix conversions bigger than
|
||||
HOST_BITS_PER_WIDE_INT.
|
||||
(simplify_binary_operation_1): Ensure we don't use shift
|
||||
incorrectly.
|
||||
(simplify_immed_subreg): Sign-extend CONST_DOUBLEs.
|
||||
* explow.c (plus_constant_mode): Add.
|
||||
(plus_constant): Implement with plus_constant_mode.
|
||||
* rtl.h (plus_constant_mode): Add.
|
||||
|
||||
2012-04-04 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/52808
|
||||
|
|
|
@ -1479,8 +1479,13 @@ This type of expression represents the integer value @var{i}. @var{i}
|
|||
is customarily accessed with the macro @code{INTVAL} as in
|
||||
@code{INTVAL (@var{exp})}, which is equivalent to @code{XWINT (@var{exp}, 0)}.
|
||||
|
||||
Constants generated for modes with fewer bits than @code{HOST_WIDE_INT}
|
||||
must be sign extended to full width (e.g., with @code{gen_int_mode}).
|
||||
Constants generated for modes with fewer bits than in
|
||||
@code{HOST_WIDE_INT} must be sign extended to full width (e.g., with
|
||||
@code{gen_int_mode}). For constants for modes with more bits than in
|
||||
@code{HOST_WIDE_INT} the implied high order bits of that constant are
|
||||
copies of the top bit. Note however that values are neither
|
||||
inherently signed nor inherently unsigned; where necessary, signedness
|
||||
is determined by the rtl operation instead.
|
||||
|
||||
@findex const0_rtx
|
||||
@findex const1_rtx
|
||||
|
@ -1510,7 +1515,13 @@ Represents either a floating-point constant of mode @var{m} or an
|
|||
integer constant too large to fit into @code{HOST_BITS_PER_WIDE_INT}
|
||||
bits but small enough to fit within twice that number of bits (GCC
|
||||
does not provide a mechanism to represent even larger constants). In
|
||||
the latter case, @var{m} will be @code{VOIDmode}.
|
||||
the latter case, @var{m} will be @code{VOIDmode}. For integral values
|
||||
constants for modes with more bits than twice the number in
|
||||
@code{HOST_WIDE_INT} the implied high order bits of that constant are
|
||||
copies of the top bit of @code{CONST_DOUBLE_HIGH}. Note however that
|
||||
integral values are neither inherently signed nor inherently unsigned;
|
||||
where necessary, signedness is determined by the rtl operation
|
||||
instead.
|
||||
|
||||
@findex CONST_DOUBLE_LOW
|
||||
If @var{m} is @code{VOIDmode}, the bits of the value are stored in
|
||||
|
|
|
@ -517,8 +517,11 @@ immed_double_int_const (double_int i, enum machine_mode mode)
|
|||
|
||||
/* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair
|
||||
of ints: I0 is the low-order word and I1 is the high-order word.
|
||||
Do not use this routine for non-integer modes; convert to
|
||||
REAL_VALUE_TYPE and use CONST_DOUBLE_FROM_REAL_VALUE. */
|
||||
For values that are larger than 2*HOST_BITS_PER_WIDE_INT, the
|
||||
implied upper bits are copies of the high bit of i1. The value
|
||||
itself is neither signed nor unsigned. Do not use this routine for
|
||||
non-integer modes; convert to REAL_VALUE_TYPE and use
|
||||
CONST_DOUBLE_FROM_REAL_VALUE. */
|
||||
|
||||
rtx
|
||||
immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode)
|
||||
|
@ -531,10 +534,9 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode)
|
|||
|
||||
1) If GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT, then we use
|
||||
gen_int_mode.
|
||||
2) GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT, but the value of
|
||||
the integer fits into HOST_WIDE_INT anyway (i.e., i1 consists only
|
||||
from copies of the sign bit, and sign of i0 and i1 are the same), then
|
||||
we return a CONST_INT for i0.
|
||||
2) If the value of the integer fits into HOST_WIDE_INT anyway
|
||||
(i.e., i1 consists only from copies of the sign bit, and sign
|
||||
of i0 and i1 are the same), then we return a CONST_INT for i0.
|
||||
3) Otherwise, we create a CONST_DOUBLE for i0 and i1. */
|
||||
if (mode != VOIDmode)
|
||||
{
|
||||
|
@ -546,8 +548,6 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode)
|
|||
|
||||
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
|
||||
return gen_int_mode (i0, mode);
|
||||
|
||||
gcc_assert (GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT);
|
||||
}
|
||||
|
||||
/* If this integer fits in one word, return a CONST_INT. */
|
||||
|
|
77
gcc/explow.c
77
gcc/explow.c
|
@ -74,14 +74,20 @@ trunc_int_for_mode (HOST_WIDE_INT c, enum machine_mode mode)
|
|||
return c;
|
||||
}
|
||||
|
||||
/* Return an rtx for the sum of X and the integer C. */
|
||||
/* Return an rtx for the sum of X and the integer C, given that X has
|
||||
mode MODE. This routine should be used instead of plus_constant
|
||||
when they want to ensure that addition happens in a particular
|
||||
mode, which is necessary when X can be a VOIDmode CONST_INT or
|
||||
CONST_DOUBLE and the width of the constant is different from the
|
||||
width of the expression. */
|
||||
/* TODO: All callers of plus_constant should migrate to this routine,
|
||||
and once they do, we can assert that mode is not VOIDmode. */
|
||||
|
||||
rtx
|
||||
plus_constant (rtx x, HOST_WIDE_INT c)
|
||||
plus_constant_mode (enum machine_mode mode, rtx x, HOST_WIDE_INT c)
|
||||
{
|
||||
RTX_CODE code;
|
||||
rtx y;
|
||||
enum machine_mode mode;
|
||||
rtx tem;
|
||||
int all_constant = 0;
|
||||
|
||||
|
@ -91,12 +97,26 @@ plus_constant (rtx x, HOST_WIDE_INT c)
|
|||
restart:
|
||||
|
||||
code = GET_CODE (x);
|
||||
mode = GET_MODE (x);
|
||||
y = x;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case CONST_INT:
|
||||
if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
|
||||
{
|
||||
unsigned HOST_WIDE_INT l1 = INTVAL (x);
|
||||
HOST_WIDE_INT h1 = (l1 >> (HOST_BITS_PER_WIDE_INT - 1)) ? -1 : 0;
|
||||
unsigned HOST_WIDE_INT l2 = c;
|
||||
HOST_WIDE_INT h2 = c < 0 ? -1 : 0;
|
||||
unsigned HOST_WIDE_INT lv;
|
||||
HOST_WIDE_INT hv;
|
||||
|
||||
if (add_double_with_sign (l1, h1, l2, h2, &lv, &hv, false))
|
||||
gcc_unreachable ();
|
||||
|
||||
return immed_double_const (lv, hv, VOIDmode);
|
||||
}
|
||||
|
||||
return GEN_INT (INTVAL (x) + c);
|
||||
|
||||
case CONST_DOUBLE:
|
||||
|
@ -104,11 +124,14 @@ plus_constant (rtx x, HOST_WIDE_INT c)
|
|||
unsigned HOST_WIDE_INT l1 = CONST_DOUBLE_LOW (x);
|
||||
HOST_WIDE_INT h1 = CONST_DOUBLE_HIGH (x);
|
||||
unsigned HOST_WIDE_INT l2 = c;
|
||||
HOST_WIDE_INT h2 = c < 0 ? ~0 : 0;
|
||||
HOST_WIDE_INT h2 = c < 0 ? -1 : 0;
|
||||
unsigned HOST_WIDE_INT lv;
|
||||
HOST_WIDE_INT hv;
|
||||
|
||||
add_double (l1, h1, l2, h2, &lv, &hv);
|
||||
if (add_double_with_sign (l1, h1, l2, h2, &lv, &hv, false))
|
||||
/* Sorry, we have no way to represent overflows this wide.
|
||||
To fix, add constant support wider than CONST_DOUBLE. */
|
||||
gcc_assert (GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT);
|
||||
|
||||
return immed_double_const (lv, hv, VOIDmode);
|
||||
}
|
||||
|
@ -120,10 +143,8 @@ plus_constant (rtx x, HOST_WIDE_INT c)
|
|||
if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
|
||||
&& CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
|
||||
{
|
||||
tem
|
||||
= force_const_mem (GET_MODE (x),
|
||||
plus_constant (get_pool_constant (XEXP (x, 0)),
|
||||
c));
|
||||
tem = plus_constant_mode (mode, get_pool_constant (XEXP (x, 0)), c);
|
||||
tem = force_const_mem (GET_MODE (x), tem);
|
||||
if (memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
|
||||
return tem;
|
||||
}
|
||||
|
@ -142,31 +163,17 @@ plus_constant (rtx x, HOST_WIDE_INT c)
|
|||
break;
|
||||
|
||||
case PLUS:
|
||||
/* The interesting case is adding the integer to a sum.
|
||||
Look for constant term in the sum and combine
|
||||
with C. For an integer constant term, we make a combined
|
||||
integer. For a constant term that is not an explicit integer,
|
||||
we cannot really combine, but group them together anyway.
|
||||
|
||||
Restart or use a recursive call in case the remaining operand is
|
||||
something that we handle specially, such as a SYMBOL_REF.
|
||||
/* The interesting case is adding the integer to a sum. Look
|
||||
for constant term in the sum and combine with C. For an
|
||||
integer constant term or a constant term that is not an
|
||||
explicit integer, we combine or group them together anyway.
|
||||
|
||||
We may not immediately return from the recursive call here, lest
|
||||
all_constant gets lost. */
|
||||
|
||||
if (CONST_INT_P (XEXP (x, 1)))
|
||||
if (CONSTANT_P (XEXP (x, 1)))
|
||||
{
|
||||
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;
|
||||
}
|
||||
else if (CONSTANT_P (XEXP (x, 1)))
|
||||
{
|
||||
x = gen_rtx_PLUS (mode, XEXP (x, 0), plus_constant (XEXP (x, 1), c));
|
||||
x = gen_rtx_PLUS (mode, XEXP (x, 0), plus_constant_mode (mode, XEXP (x, 1), c));
|
||||
c = 0;
|
||||
}
|
||||
else if (find_constant_term_loc (&y))
|
||||
|
@ -176,7 +183,7 @@ plus_constant (rtx x, HOST_WIDE_INT c)
|
|||
rtx copy = copy_rtx (x);
|
||||
rtx *const_loc = find_constant_term_loc (©);
|
||||
|
||||
*const_loc = plus_constant (*const_loc, c);
|
||||
*const_loc = plus_constant_mode (mode, *const_loc, c);
|
||||
x = copy;
|
||||
c = 0;
|
||||
}
|
||||
|
@ -196,6 +203,14 @@ plus_constant (rtx x, HOST_WIDE_INT c)
|
|||
else
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Return an rtx for the sum of X and the integer C. */
|
||||
|
||||
rtx
|
||||
plus_constant (rtx x, HOST_WIDE_INT c)
|
||||
{
|
||||
return plus_constant_mode (GET_MODE (x), x, c);
|
||||
}
|
||||
|
||||
/* If X is a sum, return a new sum like X but lacking any constant terms.
|
||||
Add all the removed constant terms into *CONSTPTR.
|
||||
|
|
|
@ -3139,8 +3139,10 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
|
|||
{
|
||||
int shift = floor_log2 (CONST_DOUBLE_HIGH (op1))
|
||||
+ HOST_BITS_PER_WIDE_INT;
|
||||
return expand_shift (LSHIFT_EXPR, mode, op0,
|
||||
shift, target, unsignedp);
|
||||
if (shift < 2 * HOST_BITS_PER_WIDE_INT - 1
|
||||
|| GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT)
|
||||
return expand_shift (LSHIFT_EXPR, mode, op0,
|
||||
shift, target, unsignedp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1644,6 +1644,7 @@ extern int ceil_log2 (unsigned HOST_WIDE_INT);
|
|||
/* In explow.c */
|
||||
extern HOST_WIDE_INT trunc_int_for_mode (HOST_WIDE_INT, enum machine_mode);
|
||||
extern rtx plus_constant (rtx, HOST_WIDE_INT);
|
||||
extern rtx plus_constant_mode (enum machine_mode, rtx, HOST_WIDE_INT);
|
||||
|
||||
/* In rtl.c */
|
||||
extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL);
|
||||
|
|
|
@ -97,6 +97,7 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
|
|||
width -= HOST_BITS_PER_WIDE_INT;
|
||||
}
|
||||
else
|
||||
/* FIXME: We don't yet have a representation for wider modes. */
|
||||
return false;
|
||||
|
||||
if (width < HOST_BITS_PER_WIDE_INT)
|
||||
|
@ -1355,16 +1356,11 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
|
|||
else
|
||||
lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op);
|
||||
|
||||
if (op_mode == VOIDmode)
|
||||
{
|
||||
/* We don't know how to interpret negative-looking numbers in
|
||||
this case, so don't try to fold those. */
|
||||
if (hv < 0)
|
||||
return 0;
|
||||
}
|
||||
else if (GET_MODE_PRECISION (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
|
||||
;
|
||||
else
|
||||
if (op_mode == VOIDmode
|
||||
|| GET_MODE_PRECISION (op_mode) > 2 * HOST_BITS_PER_WIDE_INT)
|
||||
/* We should never get a negative number. */
|
||||
gcc_assert (hv >= 0);
|
||||
else if (GET_MODE_PRECISION (op_mode) <= HOST_BITS_PER_WIDE_INT)
|
||||
hv = 0, lv &= GET_MODE_MASK (op_mode);
|
||||
|
||||
REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode);
|
||||
|
@ -1718,7 +1714,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
|
|||
else if (GET_CODE (op) == CONST_DOUBLE
|
||||
&& SCALAR_FLOAT_MODE_P (GET_MODE (op))
|
||||
&& GET_MODE_CLASS (mode) == MODE_INT
|
||||
&& width <= 2*HOST_BITS_PER_WIDE_INT && width > 0)
|
||||
&& width <= 2 * HOST_BITS_PER_WIDE_INT && width > 0)
|
||||
{
|
||||
/* Although the overflow semantics of RTL's FIX and UNSIGNED_FIX
|
||||
operators are intentionally left unspecified (to ease implementation
|
||||
|
@ -1783,7 +1779,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
|
|||
return const0_rtx;
|
||||
|
||||
/* Test against the unsigned upper bound. */
|
||||
if (width == 2*HOST_BITS_PER_WIDE_INT)
|
||||
if (width == 2 * HOST_BITS_PER_WIDE_INT)
|
||||
{
|
||||
th = -1;
|
||||
tl = -1;
|
||||
|
@ -2380,7 +2376,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
|
|||
|| GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_INT)
|
||||
&& GET_MODE (op0) == mode
|
||||
&& CONST_DOUBLE_LOW (trueop1) == 0
|
||||
&& (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0)
|
||||
&& (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0
|
||||
&& (val < 2 * HOST_BITS_PER_WIDE_INT - 1
|
||||
|| GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT))
|
||||
return simplify_gen_binary (ASHIFT, mode, op0,
|
||||
GEN_INT (val + HOST_BITS_PER_WIDE_INT));
|
||||
|
||||
|
@ -5189,6 +5187,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
|
|||
case CONST_DOUBLE:
|
||||
if (GET_MODE (el) == VOIDmode)
|
||||
{
|
||||
unsigned char extend = 0;
|
||||
/* If this triggers, someone should have generated a
|
||||
CONST_INT instead. */
|
||||
gcc_assert (elem_bitsize > HOST_BITS_PER_WIDE_INT);
|
||||
|
@ -5201,10 +5200,11 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
|
|||
= CONST_DOUBLE_HIGH (el) >> (i - HOST_BITS_PER_WIDE_INT);
|
||||
i += value_bit;
|
||||
}
|
||||
/* It shouldn't matter what's done here, so fill it with
|
||||
zero. */
|
||||
|
||||
if (CONST_DOUBLE_HIGH (el) >> (HOST_BITS_PER_WIDE_INT - 1))
|
||||
extend = -1;
|
||||
for (; i < elem_bitsize; i += value_bit)
|
||||
*vp++ = 0;
|
||||
*vp++ = extend;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue