diff options
author | Jakub Jelinek <jakub@redhat.com> | 2015-03-14 09:54:08 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2015-03-14 09:54:08 +0100 |
commit | a4b55f2a303636e3491250e1499e88454cb4ed2f (patch) | |
tree | bc114b2b6eba0116cb808d58d4045446b9a73fd8 /gcc | |
parent | efdea4d54b2af7ad3ef5dd3f1a0ca5284e60a33c (diff) | |
download | gcc-a4b55f2a303636e3491250e1499e88454cb4ed2f.zip gcc-a4b55f2a303636e3491250e1499e88454cb4ed2f.tar.gz gcc-a4b55f2a303636e3491250e1499e88454cb4ed2f.tar.bz2 |
re PR rtl-optimization/65401 (make_field_assignment broken for big-endian)
PR rtl-optimization/65401
* combine.c (rtx_equal_for_field_assignment_p): Add widen_x
argument. If true, adjust_address_nv of x with big-endian
correction for the mode widening to GET_MODE (y).
(make_field_assignment): Don't do MEM mode widening here.
Use MEM_P instead of GET_CODE == MEM.
* gcc.c-torture/execute/pr65401.c: New test.
From-SVN: r221433
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/combine.c | 37 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/pr65401.c | 59 |
4 files changed, 98 insertions, 12 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5bcfdb9..e62f67b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2015-03-14 Jakub Jelinek <jakub@redhat.com> + + PR rtl-optimization/65401 + * combine.c (rtx_equal_for_field_assignment_p): Add widen_x + argument. If true, adjust_address_nv of x with big-endian + correction for the mode widening to GET_MODE (y). + (make_field_assignment): Don't do MEM mode widening here. + Use MEM_P instead of GET_CODE == MEM. + 2015-03-13 Ilya Verbin <ilya.verbin@intel.com> * varpool.c (varpool_node::get_create): Don't set 'offloadable' flag for diff --git a/gcc/combine.c b/gcc/combine.c index f779117..71e5690 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -475,7 +475,7 @@ static rtx force_to_mode (rtx, machine_mode, unsigned HOST_WIDE_INT, int); static rtx if_then_else_cond (rtx, rtx *, rtx *); static rtx known_cond (rtx, enum rtx_code, rtx, rtx); -static int rtx_equal_for_field_assignment_p (rtx, rtx); +static int rtx_equal_for_field_assignment_p (rtx, rtx, bool = false); static rtx make_field_assignment (rtx); static rtx apply_distributive_law (rtx); static rtx distribute_and_simplify_rtx (rtx, int); @@ -9184,8 +9184,23 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val) assignment as a field assignment. */ static int -rtx_equal_for_field_assignment_p (rtx x, rtx y) +rtx_equal_for_field_assignment_p (rtx x, rtx y, bool widen_x) { + if (widen_x && GET_MODE (x) != GET_MODE (y)) + { + if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (y))) + return 0; + if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN) + return 0; + /* For big endian, adjust the memory offset. */ + if (BYTES_BIG_ENDIAN) + x = adjust_address_nv (x, GET_MODE (y), + -subreg_lowpart_offset (GET_MODE (x), + GET_MODE (y))); + else + x = adjust_address_nv (x, GET_MODE (y), 0); + } + if (x == y || rtx_equal_p (x, y)) return 1; @@ -9339,16 +9354,15 @@ make_field_assignment (rtx x) /* The second SUBREG that might get in the way is a paradoxical SUBREG around the first operand of the AND. We want to pretend the operand is as wide as the destination here. We - do this by creating a new MEM in the wider mode for the sole + do this by adjusting the MEM to wider mode for the sole purpose of the call to rtx_equal_for_field_assignment_p. Also note this trick only works for MEMs. */ else if (GET_CODE (rhs) == AND && paradoxical_subreg_p (XEXP (rhs, 0)) - && GET_CODE (SUBREG_REG (XEXP (rhs, 0))) == MEM + && MEM_P (SUBREG_REG (XEXP (rhs, 0))) && CONST_INT_P (XEXP (rhs, 1)) - && rtx_equal_for_field_assignment_p (gen_rtx_MEM (GET_MODE (dest), - XEXP (SUBREG_REG (XEXP (rhs, 0)), 0)), - dest)) + && rtx_equal_for_field_assignment_p (SUBREG_REG (XEXP (rhs, 0)), + dest, true)) c1 = INTVAL (XEXP (rhs, 1)), other = lhs; else if (GET_CODE (lhs) == AND && CONST_INT_P (XEXP (lhs, 1)) @@ -9357,16 +9371,15 @@ make_field_assignment (rtx x) /* The second SUBREG that might get in the way is a paradoxical SUBREG around the first operand of the AND. We want to pretend the operand is as wide as the destination here. We - do this by creating a new MEM in the wider mode for the sole + do this by adjusting the MEM to wider mode for the sole purpose of the call to rtx_equal_for_field_assignment_p. Also note this trick only works for MEMs. */ else if (GET_CODE (lhs) == AND && paradoxical_subreg_p (XEXP (lhs, 0)) - && GET_CODE (SUBREG_REG (XEXP (lhs, 0))) == MEM + && MEM_P (SUBREG_REG (XEXP (lhs, 0))) && CONST_INT_P (XEXP (lhs, 1)) - && rtx_equal_for_field_assignment_p (gen_rtx_MEM (GET_MODE (dest), - XEXP (SUBREG_REG (XEXP (lhs, 0)), 0)), - dest)) + && rtx_equal_for_field_assignment_p (SUBREG_REG (XEXP (lhs, 0)), + dest, true)) c1 = INTVAL (XEXP (lhs, 1)), other = rhs; else return x; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 152d36c..d9a46cb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-03-14 Jakub Jelinek <jakub@redhat.com> + + PR rtl-optimization/65401 + * gcc.c-torture/execute/pr65401.c: New test. + 2015-03-13 Kyrylo Tkachov <kyrylo.tkachov@arm.com> PR target/64600 diff --git a/gcc/testsuite/gcc.c-torture/execute/pr65401.c b/gcc/testsuite/gcc.c-torture/execute/pr65401.c new file mode 100644 index 0000000..82cfafc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr65401.c @@ -0,0 +1,59 @@ +/* PR rtl-optimization/65401 */ + +struct S { unsigned short s[64]; }; + +__attribute__((noinline, noclone)) void +foo (struct S *x) +{ + unsigned int i; + unsigned char *s; + + s = (unsigned char *) x->s; + for (i = 0; i < 64; i++) + x->s[i] = s[i * 2] | (s[i * 2 + 1] << 8); +} + +__attribute__((noinline, noclone)) void +bar (struct S *x) +{ + unsigned int i; + unsigned char *s; + + s = (unsigned char *) x->s; + for (i = 0; i < 64; i++) + x->s[i] = (s[i * 2] << 8) | s[i * 2 + 1]; +} + +int +main () +{ + unsigned int i; + struct S s; + if (sizeof (unsigned short) != 2) + return 0; + for (i = 0; i < 64; i++) + s.s[i] = i + ((64 - i) << 8); + foo (&s); +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + for (i = 0; i < 64; i++) + if (s.s[i] != (64 - i) + (i << 8)) + __builtin_abort (); +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + for (i = 0; i < 64; i++) + if (s.s[i] != i + ((64 - i) << 8)) + __builtin_abort (); +#endif + for (i = 0; i < 64; i++) + s.s[i] = i + ((64 - i) << 8); + bar (&s); +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + for (i = 0; i < 64; i++) + if (s.s[i] != (64 - i) + (i << 8)) + __builtin_abort (); +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + for (i = 0; i < 64; i++) + if (s.s[i] != i + ((64 - i) << 8)) + __builtin_abort (); +#endif + return 0; +} |