This fixes PR47968, we are trying to expand a bitfield extraction through vec_extract but strip subregs making the inputs invalid. We try to compensate for this searching for a more proper vector mode but then we have a strange requirement that NUNITS should stay the same when the most important thing is to have matching element mode.
Bootstrapped and tested on x86_64-unknown-linux-gnu, ok? Thanks, Richard. 2011-03-03 Richard Guenther <rguent...@suse.de> PR middle-end/47968 * expmed.c (extract_bit_field_1): Prefer vector modes that vec_extract patterns can handle. * gcc.dg/torture/pr47968.c: New testcase. Index: gcc/expmed.c =================================================================== *** gcc/expmed.c (revision 170649) --- gcc/expmed.c (working copy) *************** extract_bit_field_1 (rtx str_rtx, unsign *** 1205,1211 **** && GET_MODE_INNER (GET_MODE (op0)) != tmode) { enum machine_mode new_mode; - int nunits = GET_MODE_NUNITS (GET_MODE (op0)); if (GET_MODE_CLASS (tmode) == MODE_FLOAT) new_mode = MIN_MODE_VECTOR_FLOAT; --- 1205,1210 ---- *************** extract_bit_field_1 (rtx str_rtx, unsign *** 1221,1228 **** new_mode = MIN_MODE_VECTOR_INT; for (; new_mode != VOIDmode ; new_mode = GET_MODE_WIDER_MODE (new_mode)) ! if (GET_MODE_NUNITS (new_mode) == nunits ! && GET_MODE_SIZE (new_mode) == GET_MODE_SIZE (GET_MODE (op0)) && targetm.vector_mode_supported_p (new_mode)) break; if (new_mode != VOIDmode) --- 1220,1226 ---- new_mode = MIN_MODE_VECTOR_INT; for (; new_mode != VOIDmode ; new_mode = GET_MODE_WIDER_MODE (new_mode)) ! if (GET_MODE_SIZE (new_mode) == GET_MODE_SIZE (GET_MODE (op0)) && targetm.vector_mode_supported_p (new_mode)) break; if (new_mode != VOIDmode) Index: gcc/testsuite/gcc.dg/torture/pr47968.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr47968.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr47968.c (revision 0) *************** *** 0 **** --- 1,11 ---- + /* { dg-do compile } */ + + typedef __attribute__ ((vector_size (16))) float float4; + typedef __attribute__ ((vector_size (16))) double double2; + + float foo (double2 d2) + { + float4 f4 = (float4) d2; + return *(float *) &f4; + } +