Hi!

As detailed in the PR, output_move_double sometimes modifies the
operands array it is called on (when it intends to return a template
string that should be output by the caller).  Unfortunately, since
arm_count_output_move_double_insns has been added, this can lead into
clobbering of recog_data.operands already during computation of insn sizes,
and if no other insn is recognized in between that and the output of that
insn, we might be called with second operand of SImode r1 instead of
a MEM and ICE, because it sees a DImode r0 = SImode r1 move.

Fixed thusly, ok for trunk?

2012-01-20  Jakub Jelinek  <ja...@redhat.com>

        PR target/51915
        * config/arm/arm.c (arm_count_output_move_double_insns): Call
        output_move_double on a copy of operands array.

        * gcc.target/arm/pr51915.c: New test.

--- gcc/config/arm/arm.c.jj     2012-01-20 12:35:15.000000000 +0100
+++ gcc/config/arm/arm.c        2012-01-20 13:51:06.781889121 +0100
@@ -24664,7 +24664,12 @@ int
 arm_count_output_move_double_insns (rtx *operands)
 {
   int count;
-  output_move_double (operands, false, &count);
+  rtx ops[2];
+  /* output_move_double may modify the operands array, so call it
+     here on a copy of the array.  */
+  ops[0] = operands[0];
+  ops[1] = operands[1];
+  output_move_double (ops, false, &count);
   return count;
 }
 
--- gcc/testsuite/gcc.target/arm/pr51915.c.jj   2012-01-20 14:04:38.036245754 
+0100
+++ gcc/testsuite/gcc.target/arm/pr51915.c      2012-01-20 14:04:21.000000000 
+0100
@@ -0,0 +1,13 @@
+/* PR target/51915 */
+/* { dg-do compile } */
+/* { dg-options "-march=armv7-a -mfloat-abi=hard -O2" } */
+
+struct S { int s1; void *s2; };
+struct T { struct S t1; unsigned long long t2; };
+struct S *foo (unsigned long long);
+
+struct S *
+bar (struct S *x)
+{
+  return foo (((struct T *) x)->t2);
+}

        Jakub

Reply via email to