diff options
author | mrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-04-04 20:27:17 +0000 |
---|---|---|
committer | mrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-04-04 20:27:17 +0000 |
commit | db20fb4785ee648ca9ff51a2530bf5d1e9d06427 (patch) | |
tree | dbe6160ad6febabb7998df1b736a4d686b578623 | |
parent | f450da21479a2fae2c1acab5409a603541fca144 (diff) | |
download | gcc-db20fb4785ee648ca9ff51a2530bf5d1e9d06427.tar.gz |
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@186147 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/doc/rtl.texi | 17 | ||||
-rw-r--r-- | gcc/emit-rtl.c | 16 | ||||
-rw-r--r-- | gcc/explow.c | 77 | ||||
-rw-r--r-- | gcc/expmed.c | 6 | ||||
-rw-r--r-- | gcc/rtl.h | 1 | ||||
-rw-r--r-- | gcc/simplify-rtx.c | 32 |
7 files changed, 108 insertions, 60 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 70f59a49150..23c9435ba68 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index 7e9e535abb5..82eb2162927 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -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 diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 4f809820b78..8d7d4417d59 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -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. */ diff --git a/gcc/explow.c b/gcc/explow.c index 11dffedd4b0..ff26dbf605c 100644 --- a/gcc/explow.c +++ b/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. diff --git a/gcc/expmed.c b/gcc/expmed.c index 5eea2ab8b51..aa24fbf630b 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -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); } } diff --git a/gcc/rtl.h b/gcc/rtl.h index 30931b74df7..915ef136538 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -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); diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 35b7f2cdd29..1d82a375673 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -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 { |