diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a155a4a6eb8..a3d521e43cb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2015-09-03 Bill Schmidt + + * optabs.c (expand_binop): Don't create a broadcast vector with a + source element wider than the inner mode. + 2015-09-03 Richard Biener * varasm.c (output_constant): Use fold_convert instead of diff --git a/gcc/optabs.c b/gcc/optabs.c index e533e6efb36..79c6f06b991 100644 --- a/gcc/optabs.c +++ b/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) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 191c22b325d..4ca1b6a6e5a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2015-09-03 Bill Schmidt + + * gcc.target/powerpc/vec-shift.c: New test. + 2015-09-03 Tom de Vries PR tree-optimization/65637 diff --git a/gcc/testsuite/gcc.target/powerpc/vec-shift.c b/gcc/testsuite/gcc.target/powerpc/vec-shift.c new file mode 100644 index 00000000000..80b59a2d3e7 --- /dev/null +++ b/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" } } */