2015-09-03 Bill Schmidt * optabs.c (expand_binop): Don't create a broadcast vector with a source element wider than the inner mode. * gcc.target/powerpc/vec-shift.c: New test. --- gcc/optabs.c +++ gcc/optabs.c @@ -1608,6 +1608,15 @@ expand_binop (machine_mode mode, optab binoptab, rtx op0, rtx op1, if (otheroptab && optab_handler (otheroptab, mode) != CODE_FOR_nothing) { + /* The scalar may have been extended to be too wide. Truncate + it back to the proper size to fit in the broadcast vector. */ + machine_mode inner_mode = GET_MODE_INNER (mode); + if (!CONST_INT_P (op1) + && (GET_MODE_BITSIZE (inner_mode) + < GET_MODE_BITSIZE (GET_MODE (op1)))) + op1 = force_reg (inner_mode, + simplify_gen_unary (TRUNCATE, inner_mode, op1, + GET_MODE (op1))); rtx vop1 = expand_vector_broadcast (mode, op1); if (vop1) { --- /dev/null +++ gcc/testsuite/gcc.target/powerpc/vec-shift.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target { powerpc*-*-* } } } */ +/* { dg-require-effective-target powerpc_altivec_ok } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power7" } } */ +/* { dg-options "-mcpu=power7 -O2" } */ + +/* This used to ICE. During gimplification, "i" is widened to an unsigned + int. We used to fail at expand time as we tried to cram an SImode item + into a QImode memory slot. This has been fixed to properly truncate the + shift amount when splatting it into a vector. */ + +typedef unsigned char v16ui __attribute__((vector_size(16))); + +v16ui vslb(v16ui v, unsigned char i) +{ + return v << i; +} + +/* { dg-final { scan-assembler "vspltb" } } */ +/* { dg-final { scan-assembler "vslb" } } */