diff options
author | Richard Henderson <rth@redhat.com> | 2005-01-26 12:29:25 -0800 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2005-01-26 12:29:25 -0800 |
commit | 55e79aef81371abf4c07885fbbd748078d695209 (patch) | |
tree | dd7963208fe0488ccef8028ff03580720a645475 /gcc/combine.c | |
parent | d951ae1e66fabf7dc1eedc2b3bb5c047fa968fb0 (diff) | |
download | gcc-55e79aef81371abf4c07885fbbd748078d695209.zip gcc-55e79aef81371abf4c07885fbbd748078d695209.tar.gz gcc-55e79aef81371abf4c07885fbbd748078d695209.tar.bz2 |
re PR middle-end/18008 (Duplicate mask on bitfield insertion)
PR middle-end/18008
* combine.c (make_field_assignment): Simplify store to zero_extract
from a source with an overlapping mask.
From-SVN: r94282
Diffstat (limited to 'gcc/combine.c')
-rw-r--r-- | gcc/combine.c | 53 |
1 files changed, 42 insertions, 11 deletions
diff --git a/gcc/combine.c b/gcc/combine.c index 0baeb98..7fe0a5f 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -7815,14 +7815,14 @@ make_field_assignment (rtx x) return x; } - else if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG - && subreg_lowpart_p (XEXP (src, 0)) - && (GET_MODE_SIZE (GET_MODE (XEXP (src, 0))) - < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0))))) - && GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE - && GET_CODE (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == CONST_INT - && INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2 - && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1))) + if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG + && subreg_lowpart_p (XEXP (src, 0)) + && (GET_MODE_SIZE (GET_MODE (XEXP (src, 0))) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0))))) + && GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE + && GET_CODE (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == CONST_INT + && INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2 + && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1))) { assign = make_extraction (VOIDmode, dest, 0, XEXP (SUBREG_REG (XEXP (src, 0)), 1), @@ -7834,9 +7834,9 @@ make_field_assignment (rtx x) /* If SRC is (ior (ashift (const_int 1) POS) DEST), this is a set of a one-bit field. */ - else if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == ASHIFT - && XEXP (XEXP (src, 0), 0) == const1_rtx - && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1))) + if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == ASHIFT + && XEXP (XEXP (src, 0), 0) == const1_rtx + && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1))) { assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1), 1, 1, 1, 0); @@ -7845,6 +7845,37 @@ make_field_assignment (rtx x) return x; } + /* If DEST is already a field assignment, i.e. ZERO_EXTRACT, and the + SRC is an AND with all bits of that field set, then we can discard + the AND. */ + if (GET_CODE (dest) == ZERO_EXTRACT + && GET_CODE (XEXP (dest, 1)) == CONST_INT + && GET_CODE (src) == AND + && GET_CODE (XEXP (src, 1)) == CONST_INT) + { + HOST_WIDE_INT width = INTVAL (XEXP (dest, 1)); + unsigned HOST_WIDE_INT and_mask = INTVAL (XEXP (src, 1)); + unsigned HOST_WIDE_INT ze_mask; + + if (width >= HOST_BITS_PER_WIDE_INT) + ze_mask = -1; + else + ze_mask = ((unsigned HOST_WIDE_INT)1 << width) - 1; + + /* Complete overlap. We can remove the source AND. */ + if ((and_mask & ze_mask) == ze_mask) + return gen_rtx_SET (VOIDmode, dest, XEXP (src, 0)); + + /* Partial overlap. We can reduce the source AND. */ + if ((and_mask & ze_mask) != and_mask) + { + mode = GET_MODE (src); + src = gen_rtx_AND (mode, XEXP (src, 0), + gen_int_mode (mode, and_mask & ze_mask)); + return gen_rtx_SET (VOIDmode, dest, src); + } + } + /* The other case we handle is assignments into a constant-position field. They look like (ior/xor (and DEST C1) OTHER). If C1 represents a mask that has all one bits except for a group of zero bits and |