aboutsummaryrefslogtreecommitdiff
path: root/gcc/explow.c
diff options
context:
space:
mode:
authorMike Stump <mikestump@comcast.net>2012-04-04 20:27:17 +0000
committerMike Stump <mrs@gcc.gnu.org>2012-04-04 20:27:17 +0000
commit929e10f4cf1e7f683d36b505e3a1aabc6e85dd57 (patch)
treedbe6160ad6febabb7998df1b736a4d686b578623 /gcc/explow.c
parentb059fba46902f67bf76c5e80da28b423778ced1f (diff)
downloadgcc-929e10f4cf1e7f683d36b505e3a1aabc6e85dd57.zip
gcc-929e10f4cf1e7f683d36b505e3a1aabc6e85dd57.tar.gz
gcc-929e10f4cf1e7f683d36b505e3a1aabc6e85dd57.tar.bz2
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
Diffstat (limited to 'gcc/explow.c')
-rw-r--r--gcc/explow.c77
1 files changed, 46 insertions, 31 deletions
diff --git a/gcc/explow.c b/gcc/explow.c
index 11dffed..ff26dbf 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 (&copy);
- *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.