Hi! The attached testcase ICEs on arm, because extract_fixed_bit_field with tmode SImode (and SImode non-NULL target) decides to use DImode for the signed shifts, but doesn't clear target and thus attempts to use that SImode target for DImode shifts. The code apparently already has if (mode != tmode) target = 0;, just done at a wrong spot before mode can be changed.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux and tested with a cross to arm-linux on the testcase, ok for trunk/4.6? 2011-05-18 Jakub Jelinek <ja...@redhat.com> PR middle-end/49029 * expmed.c (extract_fixed_bit_field): Test whether target can be used only after deciding which mode to use. * gcc.c-torture/compile/pr49029.c: New test. --- gcc/expmed.c.jj 2011-05-11 19:39:04.000000000 +0200 +++ gcc/expmed.c 2011-05-18 11:38:43.000000000 +0200 @@ -1769,8 +1769,6 @@ extract_fixed_bit_field (enum machine_mo /* To extract a signed bit-field, first shift its msb to the msb of the word, then arithmetic-shift its lsb to the lsb of the word. */ op0 = force_reg (mode, op0); - if (mode != tmode) - target = 0; /* Find the narrowest integer mode that contains the field. */ @@ -1782,6 +1780,9 @@ extract_fixed_bit_field (enum machine_mo break; } + if (mode != tmode) + target = 0; + if (GET_MODE_BITSIZE (mode) != (bitsize + bitpos)) { int amount = GET_MODE_BITSIZE (mode) - (bitsize + bitpos); --- gcc/testsuite/gcc.c-torture/compile/pr49029.c.jj 2011-05-18 11:55:25.000000000 +0200 +++ gcc/testsuite/gcc.c-torture/compile/pr49029.c 2011-05-18 11:54:22.000000000 +0200 @@ -0,0 +1,10 @@ +/* PR middle-end/49029 */ +struct S { volatile unsigned f : 11; signed g : 30; } __attribute__((packed)); +struct T { volatile struct S h; } __attribute__((packed)) a; +void foo (int); + +void +bar () +{ + foo (a.h.g); +} Jakub