The following should fix PR71984 which stems from a bogus (but harmless for CONCAT) use of GET_MODE_UNIT_SIZE vs. GET_MODE_SIZE (where the former is really really badly named...). In the process of fixing it I also hardened it against VOIDmode which might have occured for CONCAT as well given we have CSImode.
Bootstrap / regtest running on x86_64-unknown-linux-gnu. I don't have AVX512 HW to check but by inspection the testcase is fixed. (and the issue is obvious once you analyzed it) It was Honza who sneaked in this GET_MODE_UNIT_SIZE use, the bad name exists since the initial repository version. Ok for trunk? Thanks, Richard. 2016-07-25 Richard Biener <rguent...@suse.de> PR rtl-optimization/71984 * simplify-rtx.c (simplify_subreg): Use GET_MODE_SIZE and prepare for VOIDmode. * gcc.dg/torture/pr71984.c: New testcase. Index: gcc/simplify-rtx.c =================================================================== *** gcc/simplify-rtx.c (revision 238710) --- gcc/simplify-rtx.c (working copy) *************** simplify_subreg (machine_mode outermode, *** 6116,6122 **** unsigned int part_size, final_offset; rtx part, res; ! part_size = GET_MODE_UNIT_SIZE (GET_MODE (XEXP (op, 0))); if (byte < part_size) { part = XEXP (op, 0); --- 6116,6125 ---- unsigned int part_size, final_offset; rtx part, res; ! enum machine_mode part_mode = GET_MODE (XEXP (op, 0)); ! if (part_mode == VOIDmode) ! part_mode = GET_MODE_INNER (GET_MODE (op)); ! part_size = GET_MODE_SIZE (part_mode); if (byte < part_size) { part = XEXP (op, 0); *************** simplify_subreg (machine_mode outermode, *** 6131,6137 **** if (final_offset + GET_MODE_SIZE (outermode) > part_size) return NULL_RTX; ! enum machine_mode part_mode = GET_MODE (part); if (part_mode == VOIDmode) part_mode = GET_MODE_INNER (GET_MODE (op)); res = simplify_subreg (outermode, part, part_mode, final_offset); --- 6134,6140 ---- if (final_offset + GET_MODE_SIZE (outermode) > part_size) return NULL_RTX; ! part_mode = GET_MODE (part); if (part_mode == VOIDmode) part_mode = GET_MODE_INNER (GET_MODE (op)); res = simplify_subreg (outermode, part, part_mode, final_offset); Index: gcc/testsuite/gcc.dg/torture/pr71984.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr71984.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr71984.c (working copy) *************** *** 0 **** --- 1,21 ---- + /* { dg-do run { target lp64 } } */ + /* { dg-additional-options "-w -Wno-psabi" } */ + + typedef unsigned char v64u8 __attribute__((vector_size(64))); + typedef unsigned long v64u64 __attribute__((vector_size(64))); + typedef unsigned char u8; + + static u8 __attribute__ ((noinline, noclone)) + foo (v64u64 v64u64_0) + { + return ((v64u8)(v64u64){0, v64u64_0[0]})[13]; + } + + int + main () + { + u8 x = foo((v64u64){0x0706050403020100UL}); + if (x != 5) + __builtin_abort (); + return 0; + }