Commit 929e10f4 by Mike Stump Committed by Mike Stump

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
parent b059fba4
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> 2012-04-04 Richard Guenther <rguenther@suse.de>
PR tree-optimization/52808 PR tree-optimization/52808
......
...@@ -1479,8 +1479,13 @@ This type of expression represents the integer value @var{i}. @var{i} ...@@ -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 is customarily accessed with the macro @code{INTVAL} as in
@code{INTVAL (@var{exp})}, which is equivalent to @code{XWINT (@var{exp}, 0)}. @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} Constants generated for modes with fewer bits than in
must be sign extended to full width (e.g., with @code{gen_int_mode}). @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 const0_rtx
@findex const1_rtx @findex const1_rtx
...@@ -1510,7 +1515,13 @@ Represents either a floating-point constant of mode @var{m} or an ...@@ -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} 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 bits but small enough to fit within twice that number of bits (GCC
does not provide a mechanism to represent even larger constants). In 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 @findex CONST_DOUBLE_LOW
If @var{m} is @code{VOIDmode}, the bits of the value are stored in 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) ...@@ -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 /* 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. 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 For values that are larger than 2*HOST_BITS_PER_WIDE_INT, the
REAL_VALUE_TYPE and use CONST_DOUBLE_FROM_REAL_VALUE. */ 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 rtx
immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode) 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) ...@@ -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 1) If GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT, then we use
gen_int_mode. gen_int_mode.
2) GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT, but the value of 2) If the value of the integer fits into HOST_WIDE_INT anyway
the integer fits into HOST_WIDE_INT anyway (i.e., i1 consists only (i.e., i1 consists only from copies of the sign bit, and sign
from copies of the sign bit, and sign of i0 and i1 are the same), then of i0 and i1 are the same), then we return a CONST_INT for i0.
we return a CONST_INT for i0.
3) Otherwise, we create a CONST_DOUBLE for i0 and i1. */ 3) Otherwise, we create a CONST_DOUBLE for i0 and i1. */
if (mode != VOIDmode) if (mode != VOIDmode)
{ {
...@@ -546,8 +548,6 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode) ...@@ -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) if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
return gen_int_mode (i0, mode); 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. */ /* If this integer fits in one word, return a CONST_INT. */
......
...@@ -74,14 +74,20 @@ trunc_int_for_mode (HOST_WIDE_INT c, enum machine_mode mode) ...@@ -74,14 +74,20 @@ trunc_int_for_mode (HOST_WIDE_INT c, enum machine_mode mode)
return c; 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 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_CODE code;
rtx y; rtx y;
enum machine_mode mode;
rtx tem; rtx tem;
int all_constant = 0; int all_constant = 0;
...@@ -91,12 +97,26 @@ plus_constant (rtx x, HOST_WIDE_INT c) ...@@ -91,12 +97,26 @@ plus_constant (rtx x, HOST_WIDE_INT c)
restart: restart:
code = GET_CODE (x); code = GET_CODE (x);
mode = GET_MODE (x);
y = x; y = x;
switch (code) switch (code)
{ {
case CONST_INT: 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); return GEN_INT (INTVAL (x) + c);
case CONST_DOUBLE: case CONST_DOUBLE:
...@@ -104,11 +124,14 @@ plus_constant (rtx x, HOST_WIDE_INT c) ...@@ -104,11 +124,14 @@ plus_constant (rtx x, HOST_WIDE_INT c)
unsigned HOST_WIDE_INT l1 = CONST_DOUBLE_LOW (x); unsigned HOST_WIDE_INT l1 = CONST_DOUBLE_LOW (x);
HOST_WIDE_INT h1 = CONST_DOUBLE_HIGH (x); HOST_WIDE_INT h1 = CONST_DOUBLE_HIGH (x);
unsigned HOST_WIDE_INT l2 = c; 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; unsigned HOST_WIDE_INT lv;
HOST_WIDE_INT hv; 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); return immed_double_const (lv, hv, VOIDmode);
} }
...@@ -120,10 +143,8 @@ plus_constant (rtx x, HOST_WIDE_INT c) ...@@ -120,10 +143,8 @@ plus_constant (rtx x, HOST_WIDE_INT c)
if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
{ {
tem tem = plus_constant_mode (mode, get_pool_constant (XEXP (x, 0)), c);
= force_const_mem (GET_MODE (x), tem = force_const_mem (GET_MODE (x), tem);
plus_constant (get_pool_constant (XEXP (x, 0)),
c));
if (memory_address_p (GET_MODE (tem), XEXP (tem, 0))) if (memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
return tem; return tem;
} }
...@@ -142,31 +163,17 @@ plus_constant (rtx x, HOST_WIDE_INT c) ...@@ -142,31 +163,17 @@ plus_constant (rtx x, HOST_WIDE_INT c)
break; break;
case PLUS: case PLUS:
/* The interesting case is adding the integer to a sum. /* The interesting case is adding the integer to a sum. Look
Look for constant term in the sum and combine for constant term in the sum and combine with C. For an
with C. For an integer constant term, we make a combined integer constant term or a constant term that is not an
integer. For a constant term that is not an explicit integer, explicit integer, we combine or group them together anyway.
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.
We may not immediately return from the recursive call here, lest We may not immediately return from the recursive call here, lest
all_constant gets lost. */ all_constant gets lost. */
if (CONST_INT_P (XEXP (x, 1))) if (CONSTANT_P (XEXP (x, 1)))
{ {
c += INTVAL (XEXP (x, 1)); x = gen_rtx_PLUS (mode, XEXP (x, 0), plus_constant_mode (mode, XEXP (x, 1), c));
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));
c = 0; c = 0;
} }
else if (find_constant_term_loc (&y)) else if (find_constant_term_loc (&y))
...@@ -176,7 +183,7 @@ plus_constant (rtx x, HOST_WIDE_INT c) ...@@ -176,7 +183,7 @@ plus_constant (rtx x, HOST_WIDE_INT c)
rtx copy = copy_rtx (x); rtx copy = copy_rtx (x);
rtx *const_loc = find_constant_term_loc (&copy); rtx *const_loc = find_constant_term_loc (&copy);
*const_loc = plus_constant (*const_loc, c); *const_loc = plus_constant_mode (mode, *const_loc, c);
x = copy; x = copy;
c = 0; c = 0;
} }
...@@ -196,6 +203,14 @@ plus_constant (rtx x, HOST_WIDE_INT c) ...@@ -196,6 +203,14 @@ plus_constant (rtx x, HOST_WIDE_INT c)
else else
return x; 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. /* If X is a sum, return a new sum like X but lacking any constant terms.
Add all the removed constant terms into *CONSTPTR. Add all the removed constant terms into *CONSTPTR.
......
...@@ -3139,8 +3139,10 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target, ...@@ -3139,8 +3139,10 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
{ {
int shift = floor_log2 (CONST_DOUBLE_HIGH (op1)) int shift = floor_log2 (CONST_DOUBLE_HIGH (op1))
+ HOST_BITS_PER_WIDE_INT; + HOST_BITS_PER_WIDE_INT;
return expand_shift (LSHIFT_EXPR, mode, op0, if (shift < 2 * HOST_BITS_PER_WIDE_INT - 1
shift, target, unsignedp); || 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); ...@@ -1644,6 +1644,7 @@ extern int ceil_log2 (unsigned HOST_WIDE_INT);
/* In explow.c */ /* In explow.c */
extern HOST_WIDE_INT trunc_int_for_mode (HOST_WIDE_INT, enum machine_mode); 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 (rtx, HOST_WIDE_INT);
extern rtx plus_constant_mode (enum machine_mode, rtx, HOST_WIDE_INT);
/* In rtl.c */ /* In rtl.c */
extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL); extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL);
......
...@@ -97,6 +97,7 @@ mode_signbit_p (enum machine_mode mode, const_rtx x) ...@@ -97,6 +97,7 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
width -= HOST_BITS_PER_WIDE_INT; width -= HOST_BITS_PER_WIDE_INT;
} }
else else
/* FIXME: We don't yet have a representation for wider modes. */
return false; return false;
if (width < HOST_BITS_PER_WIDE_INT) if (width < HOST_BITS_PER_WIDE_INT)
...@@ -1355,16 +1356,11 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode, ...@@ -1355,16 +1356,11 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
else else
lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op); lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op);
if (op_mode == VOIDmode) if (op_mode == VOIDmode
{ || GET_MODE_PRECISION (op_mode) > 2 * HOST_BITS_PER_WIDE_INT)
/* We don't know how to interpret negative-looking numbers in /* We should never get a negative number. */
this case, so don't try to fold those. */ gcc_assert (hv >= 0);
if (hv < 0) else if (GET_MODE_PRECISION (op_mode) <= HOST_BITS_PER_WIDE_INT)
return 0;
}
else if (GET_MODE_PRECISION (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
;
else
hv = 0, lv &= GET_MODE_MASK (op_mode); hv = 0, lv &= GET_MODE_MASK (op_mode);
REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, 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, ...@@ -1718,7 +1714,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
else if (GET_CODE (op) == CONST_DOUBLE else if (GET_CODE (op) == CONST_DOUBLE
&& SCALAR_FLOAT_MODE_P (GET_MODE (op)) && SCALAR_FLOAT_MODE_P (GET_MODE (op))
&& GET_MODE_CLASS (mode) == MODE_INT && 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 /* Although the overflow semantics of RTL's FIX and UNSIGNED_FIX
operators are intentionally left unspecified (to ease implementation operators are intentionally left unspecified (to ease implementation
...@@ -1783,7 +1779,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode, ...@@ -1783,7 +1779,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
return const0_rtx; return const0_rtx;
/* Test against the unsigned upper bound. */ /* Test against the unsigned upper bound. */
if (width == 2*HOST_BITS_PER_WIDE_INT) if (width == 2 * HOST_BITS_PER_WIDE_INT)
{ {
th = -1; th = -1;
tl = -1; tl = -1;
...@@ -2380,7 +2376,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, ...@@ -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_CLASS (GET_MODE (trueop1)) == MODE_INT)
&& GET_MODE (op0) == mode && GET_MODE (op0) == mode
&& CONST_DOUBLE_LOW (trueop1) == 0 && 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, return simplify_gen_binary (ASHIFT, mode, op0,
GEN_INT (val + HOST_BITS_PER_WIDE_INT)); GEN_INT (val + HOST_BITS_PER_WIDE_INT));
...@@ -5189,6 +5187,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op, ...@@ -5189,6 +5187,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
case CONST_DOUBLE: case CONST_DOUBLE:
if (GET_MODE (el) == VOIDmode) if (GET_MODE (el) == VOIDmode)
{ {
unsigned char extend = 0;
/* If this triggers, someone should have generated a /* If this triggers, someone should have generated a
CONST_INT instead. */ CONST_INT instead. */
gcc_assert (elem_bitsize > HOST_BITS_PER_WIDE_INT); gcc_assert (elem_bitsize > HOST_BITS_PER_WIDE_INT);
...@@ -5201,10 +5200,11 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op, ...@@ -5201,10 +5200,11 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
= CONST_DOUBLE_HIGH (el) >> (i - HOST_BITS_PER_WIDE_INT); = CONST_DOUBLE_HIGH (el) >> (i - HOST_BITS_PER_WIDE_INT);
i += value_bit; 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) for (; i < elem_bitsize; i += value_bit)
*vp++ = 0; *vp++ = extend;
} }
else else
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment