diff options
author | Alexandre Oliva <aoliva@redhat.com> | 2002-02-20 23:15:00 +0000 |
---|---|---|
committer | Alexandre Oliva <aoliva@gcc.gnu.org> | 2002-02-20 23:15:00 +0000 |
commit | 4161da12190d52eb1d622354e6ea67f67195c73c (patch) | |
tree | 55c3d095668c86b8d785d6a6b95f142a8823cd52 /gcc/combine.c | |
parent | 8e8d61f5c1ddd2e55ae3c32347af851eaeb83e0a (diff) | |
download | gcc-4161da12190d52eb1d622354e6ea67f67195c73c.zip gcc-4161da12190d52eb1d622354e6ea67f67195c73c.tar.gz gcc-4161da12190d52eb1d622354e6ea67f67195c73c.tar.bz2 |
combine.c (do_SUBST): Sanity check substitutions of CONST_INTs...
* 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.
From-SVN: r49920
Diffstat (limited to 'gcc/combine.c')
-rw-r--r-- | gcc/combine.c | 71 |
1 files changed, 70 insertions, 1 deletions
diff --git a/gcc/combine.c b/gcc/combine.c index eb82531..dba7997 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -424,6 +424,33 @@ do_SUBST (into, newval) 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 @@ -3505,7 +3532,24 @@ subst (x, from, to, in_dest, unique_copy) 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); } } } @@ -7449,6 +7493,31 @@ known_cond (x, cond, reg, val) 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--) |