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