Commit a4b55f2a by Jakub Jelinek Committed by Jakub Jelinek

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
parent efdea4d5
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> 2015-03-13 Ilya Verbin <ilya.verbin@intel.com>
* varpool.c (varpool_node::get_create): Don't set 'offloadable' flag for * varpool.c (varpool_node::get_create): Don't set 'offloadable' flag for
......
...@@ -475,7 +475,7 @@ static rtx force_to_mode (rtx, machine_mode, ...@@ -475,7 +475,7 @@ static rtx force_to_mode (rtx, machine_mode,
unsigned HOST_WIDE_INT, int); unsigned HOST_WIDE_INT, int);
static rtx if_then_else_cond (rtx, rtx *, rtx *); static rtx if_then_else_cond (rtx, rtx *, rtx *);
static rtx known_cond (rtx, enum rtx_code, 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 make_field_assignment (rtx);
static rtx apply_distributive_law (rtx); static rtx apply_distributive_law (rtx);
static rtx distribute_and_simplify_rtx (rtx, int); static rtx distribute_and_simplify_rtx (rtx, int);
...@@ -9184,8 +9184,23 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val) ...@@ -9184,8 +9184,23 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
assignment as a field assignment. */ assignment as a field assignment. */
static int 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)) if (x == y || rtx_equal_p (x, y))
return 1; return 1;
...@@ -9339,16 +9354,15 @@ make_field_assignment (rtx x) ...@@ -9339,16 +9354,15 @@ make_field_assignment (rtx x)
/* The second SUBREG that might get in the way is a paradoxical /* The second SUBREG that might get in the way is a paradoxical
SUBREG around the first operand of the AND. We want to SUBREG around the first operand of the AND. We want to
pretend the operand is as wide as the destination here. We 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 purpose of the call to rtx_equal_for_field_assignment_p. Also
note this trick only works for MEMs. */ note this trick only works for MEMs. */
else if (GET_CODE (rhs) == AND else if (GET_CODE (rhs) == AND
&& paradoxical_subreg_p (XEXP (rhs, 0)) && 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)) && CONST_INT_P (XEXP (rhs, 1))
&& rtx_equal_for_field_assignment_p (gen_rtx_MEM (GET_MODE (dest), && rtx_equal_for_field_assignment_p (SUBREG_REG (XEXP (rhs, 0)),
XEXP (SUBREG_REG (XEXP (rhs, 0)), 0)), dest, true))
dest))
c1 = INTVAL (XEXP (rhs, 1)), other = lhs; c1 = INTVAL (XEXP (rhs, 1)), other = lhs;
else if (GET_CODE (lhs) == AND else if (GET_CODE (lhs) == AND
&& CONST_INT_P (XEXP (lhs, 1)) && CONST_INT_P (XEXP (lhs, 1))
...@@ -9357,16 +9371,15 @@ make_field_assignment (rtx x) ...@@ -9357,16 +9371,15 @@ make_field_assignment (rtx x)
/* The second SUBREG that might get in the way is a paradoxical /* The second SUBREG that might get in the way is a paradoxical
SUBREG around the first operand of the AND. We want to SUBREG around the first operand of the AND. We want to
pretend the operand is as wide as the destination here. We 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 purpose of the call to rtx_equal_for_field_assignment_p. Also
note this trick only works for MEMs. */ note this trick only works for MEMs. */
else if (GET_CODE (lhs) == AND else if (GET_CODE (lhs) == AND
&& paradoxical_subreg_p (XEXP (lhs, 0)) && 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)) && CONST_INT_P (XEXP (lhs, 1))
&& rtx_equal_for_field_assignment_p (gen_rtx_MEM (GET_MODE (dest), && rtx_equal_for_field_assignment_p (SUBREG_REG (XEXP (lhs, 0)),
XEXP (SUBREG_REG (XEXP (lhs, 0)), 0)), dest, true))
dest))
c1 = INTVAL (XEXP (lhs, 1)), other = rhs; c1 = INTVAL (XEXP (lhs, 1)), other = rhs;
else else
return x; return x;
......
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> 2015-03-13 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
PR target/64600 PR target/64600
......
/* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment