+2002-02-20 Alexandre Oliva <aoliva@redhat.com>
+
+ * combine.c (do_SUBST): Sanity check substitutions of
+ CONST_INTs, and reject them in SUBREGs and ZERO_EXTENDs.
+ (subst): Simplify SUBREG or ZERO_EXTEND instead of SUBSTing a
+ CONST_INT into its operand.
+ (known_cond): Likewise, for ZERO_EXTEND.
+ * simplify-rtx.c (simplify_unary_operation): Fix condition to
+ allow for simplification of wide modes. Reject CONST_INTs in
+ ZERO_EXTEND when their actual mode is not given.
+
2002-02-20 Alexandre Oliva <aoliva@redhat.com>
* c-decl.c (pushdecl): If no global declaration is found for an
if (oldval == newval)
return;
+ /* We'd like to catch as many invalid transformations here as
+ possible. Unfortunately, there are way too many mode changes
+ that are perfectly valid, so we'd waste too much effort for
+ little gain doing the checks here. Focus on catching invalid
+ transformations involving integer constants. */
+ if (GET_MODE_CLASS (GET_MODE (oldval)) == MODE_INT
+ && GET_CODE (newval) == CONST_INT)
+ {
+ /* Sanity check that we're replacing oldval with a CONST_INT
+ that is a valid sign-extension for the original mode. */
+ if (INTVAL (newval) != trunc_int_for_mode (INTVAL (newval),
+ GET_MODE (oldval)))
+ abort ();
+
+ /* Replacing the operand of a SUBREG or a ZERO_EXTEND with a
+ CONST_INT is not valid, because after the replacement, the
+ original mode would be gone. Unfortunately, we can't tell
+ when do_SUBST is called to replace the operand thereof, so we
+ perform this test on oldval instead, checking whether an
+ invalid replacement took place before we got here. */
+ if ((GET_CODE (oldval) == SUBREG
+ && GET_CODE (SUBREG_REG (oldval)) == CONST_INT)
+ || (GET_CODE (oldval) == ZERO_EXTEND
+ && GET_CODE (XEXP (oldval, 0)) == CONST_INT))
+ abort ();
+ }
+
if (undobuf.frees)
buf = undobuf.frees, undobuf.frees = buf->next;
else
if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
return new;
- SUBST (XEXP (x, i), new);
+ if (GET_CODE (new) == CONST_INT && GET_CODE (x) == SUBREG)
+ {
+ x = simplify_subreg (GET_MODE (x), new,
+ GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x));
+ if (! x)
+ abort ();
+ }
+ else if (GET_CODE (new) == CONST_INT
+ && GET_CODE (x) == ZERO_EXTEND)
+ {
+ x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
+ new, GET_MODE (XEXP (x, 0)));
+ if (! x)
+ abort ();
+ }
+ else
+ SUBST (XEXP (x, i), new);
}
}
}
return x;
}
+ /* We don't have to handle SIGN_EXTEND here, because even in the
+ case of replacing something with a modeless CONST_INT, a
+ CONST_INT is already (supposed to be) a valid sign extension for
+ its narrower mode, which implies it's already properly
+ sign-extended for the wider mode. Now, for ZERO_EXTEND, the
+ story is different. */
+ else if (code == ZERO_EXTEND)
+ {
+ enum machine_mode inner_mode = GET_MODE (XEXP (x, 0));
+ rtx new, r = known_cond (XEXP (x, 0), cond, reg, val);
+
+ if (XEXP (x, 0) != r)
+ {
+ /* We must simplify the zero_extend here, before we lose
+ track of the original inner_mode. */
+ new = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
+ r, inner_mode);
+ if (new)
+ return new;
+ else
+ SUBST (XEXP (x, 0), r);
+ }
+
+ return x;
+ }
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
break;
case ZERO_EXTEND:
+ /* When zero-extending a CONST_INT, we need to know its
+ original mode. */
if (op_mode == VOIDmode)
- op_mode = mode;
+ abort ();
if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
{
/* If we were really extending the mode,
/* We can do some operations on integer CONST_DOUBLEs. Also allow
for a DImode operation on a CONST_INT. */
- else if (GET_MODE (trueop) == VOIDmode && width <= HOST_BITS_PER_INT * 2
+ else if (GET_MODE (trueop) == VOIDmode
+ && width <= HOST_BITS_PER_WIDE_INT * 2
&& (GET_CODE (trueop) == CONST_DOUBLE
|| GET_CODE (trueop) == CONST_INT))
{
break;
case ZERO_EXTEND:
- if (op_mode == VOIDmode
- || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
+ if (op_mode == VOIDmode)
+ abort ();
+
+ if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
return 0;
hv = 0;