https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127670
--- Comment #4 from Richard Biener <rguenth at gcc dot gnu.org> ---
t.c:5:1: note: node 0x55b3790 (refcnt=1) vector(4) int @_12 = x[3];
t.c:5:1: note: op template: _3 = _1 << _22;
t.c:5:1: note: stmt 0 _3 = _1 << _22;
t.c:5:1: note: stmt 1 _5 = _4 << _2;
t.c:5:1: note: stmt 2 _9 = _8 << _2;
t.c:5:1: note: stmt 3 _13 = _12 << _2;
t.c:5:1: note: children 0x55b38f0 0x55b39a0
so we disagree with the result analysis vs. transform which fails at
vec_mode = TYPE_MODE (vectype);
icode = (int) optab_handler (optab, vec_mode);
if (icode == CODE_FOR_nothing)
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"shift op not supported by target.\n");
return false;
with V4SImode for vashl_optab while during analysis we ue ashl_optab.
So scalar shift vs. non-scalar shift is mis-recognized.
During analysis:
(gdb) p debug (slp_node)
t.c:5:1: note: node 0x55b3790 (refcnt=1) vector(4) int
t.c:5:1: note: op template: _3 = _1 << _2;
t.c:5:1: note: stmt 0 _3 = _1 << _2;
t.c:5:1: note: stmt 1 _5 = _4 << _2;
t.c:5:1: note: stmt 2 _9 = _8 << _2;
t.c:5:1: note: stmt 3 _13 = _12 << _2;
t.c:5:1: note: children 0x55b38f0 0x55b39a0
so somehow the scalar statements changed which happens via
#0 set_ssa_use_from_ptr (use=0x7ffff6600488, val=<ssa_name 0x7ffff6602cb8 22>)
at /space/rguenther/src/gcc-clean/gcc/ssa-iterators.h:333
#1 0x0000000001f14393 in vectorizable_live_operation (vinfo=0x5621c20,
stmt_info=0x5621cf0, slp_node=0x55b36e0, slp_node_instance=0x55191e0,
slp_index=0, vec_stmt_p=true, cost_vec=0x0)
at /space/rguenther/src/gcc-clean/gcc/tree-vect-loop.cc:10519
#2 0x0000000001ee3c22 in vect_transform_stmt (vinfo=0x5621c20,
stmt_info=0x5621cf0, gsi=0x7fffffffc8a0, slp_node=0x55b36e0,
slp_node_instance=0x55191e0)
at /space/rguenther/src/gcc-clean/gcc/tree-vect-stmts.cc:13288
#3 0x0000000001f5f2bb in vect_schedule_slp_node (vinfo=0x5621c20,
node=0x55b36e0,
instance=0x55191e0, place_only=false)
at /space/rguenther/src/gcc-clean/gcc/tree-vect-slp.cc:12548
so we have a "live" lane of the SLP graph feeding its own external def,
but we somehow oddly arrive at _2 being live. The graph we vectorize is
t.c:7:8: note: node 0x2c43b5e0 (refcnt=1) vector(4) int @x[3] = _15;
t.c:7:8: note: op template: x[0] = _4;
t.c:7:8: note: stmt 0 x[0] = _4;
t.c:7:8: note: stmt 1 x[1] = _7;
t.c:7:8: note: stmt 2 x[2] = _11;
t.c:7:8: note: stmt 3 x[3] = _15;
t.c:7:8: note: children 0x2c43b690
t.c:7:8: note: node 0x2c43b690 (refcnt=1) vector(4) int @_12 = x[3];
t.c:7:8: note: op template: _4 = _2 + _3;
t.c:7:8: note: stmt 0 _4 = _2 + _3;
t.c:7:8: note: stmt 1 _7 = _5 + _6;
t.c:7:8: note: stmt 2 _11 = _9 + _10;
t.c:7:8: note: stmt 3 _15 = _13 + _14;
t.c:7:8: note: children 0x2c43b7f0 0x2c43b8a0
t.c:7:8: note: node 0x2c43b7f0 (refcnt=1) vector(4) int @_2 = j[0];
t.c:7:8: note: op template: _2 = j[0];
t.c:7:8: note: [l*]stmt 0 _2 = j[0];
t.c:7:8: note: stmt 1 _6 = j[1];
t.c:7:8: note: stmt 2 _10 = j[2];
t.c:7:8: note: stmt 3 _14 = j[3];
t.c:7:8: note: node 0x2c43b8a0 (refcnt=1) vector(4) int @_12 = x[3];
t.c:7:8: note: op template: _3 = _1 << _2;
t.c:7:8: note: stmt 0 _3 = _1 << _2;
t.c:7:8: note: stmt 1 _5 = _4 << _2;
t.c:7:8: note: stmt 2 _9 = _8 << _2;
t.c:7:8: note: stmt 3 _13 = _12 << _2;
t.c:7:8: note: children 0x2c43ba00 0x2c43bab0
t.c:7:8: note: node (external) 0x2c43ba00 (refcnt=1) vector(4) int @_12 = x[3];
t.c:7:8: note: { _1, _4, _8, _12 }
t.c:7:8: note: node 0x2c43bab0 (refcnt=1) vector(4) int @_2 = j[0];
t.c:7:8: note: op template: _2 = j[0];
t.c:7:8: note: [l] stmt 0 _2 = j[0];
t.c:7:8: note: [l] stmt 1 _2 = j[0];
t.c:7:8: note: [l] stmt 2 _2 = j[0];
t.c:7:8: note: [l] stmt 3 _2 = j[0];
t.c:7:8: note: load permutation { 0 0 0 0 }
but only _1, _4, _8 and _12 are required and only _4 is part of a vector,
so that should have been live? Ah, so SLP coverage excludes _4 because
it's used in an extern, it doesn't become PURE_SLP and so the use of _2
in it makes _2 live. Likewise this makes _3 = _1 << _2 not PURE_SLP
and so we replace _2 therein with the live lane.
The whole thing is conservative for the scalar costing, but for vectorizing
we should probably prune the SLP graph when it has these kind of "cycles"
through externs for optimality reasons though this conflicts with having
analyzed the graph before.
vectorizable_shift itself is a bit of a mess :/ I'll fix it half-heartedly.
We then code generate
_1 = x[0];
vect__2.5_21 = MEM <vector(4) int> [(int *)&j];
_22 = BIT_FIELD_REF <vect__2.5_21, 32, 0>;
_3 = _1 << _22;
_4 = _3 + _22;
_8 = x[2];
_12 = x[3];
_23 = {_1, _4, _8, _12};
vect__3.10_27 = _23 << _22;
vect__4.11_28 = vect__2.5_21 + vect__3.10_27;
MEM <vector(4) int> [(int *)&x] = vect__4.11_28;
and
movdqa j(%rip), %xmm2
movl x(%rip), %edx
movd x(%rip), %xmm0
movd x+12(%rip), %xmm3
movd %xmm2, %ecx
sall %cl, %edx
addl %ecx, %edx
movslq %ecx, %rcx
movd %edx, %xmm1
movq %rcx, %xmm4
punpckldq %xmm1, %xmm0
movd x+8(%rip), %xmm1
punpckldq %xmm3, %xmm1
shufps $68, %xmm1, %xmm0
pslld %xmm4, %xmm0
paddd %xmm2, %xmm0
movaps %xmm0, x(%rip)
ret
vs
movl j(%rip), %ecx
movl x(%rip), %eax
sall %cl, %eax
addl %ecx, %eax
movl %eax, x(%rip)
sall %cl, %eax
addl j+4(%rip), %eax
movl %eax, x+4(%rip)
movl x+8(%rip), %eax
sall %cl, %eax
addl j+8(%rip), %eax
movl %eax, x+8(%rip)
movl x+12(%rip), %eax
sall %cl, %eax
addl j+12(%rip), %eax
movl %eax, x+12(%rip)
ret