https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127862
Bug ID: 127862
Summary: VEC_PERM_EXPR merge patterns mishandle permutes whose
inputs and result differ in length (ICE with svld1rq +
svrev, wrong code)
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: ice-on-valid-code, wrong-code
Severity: normal
Priority: P3
Component: middle-end
Assignee: unassigned at gcc dot gnu.org
Reporter: igor at tachyum dot com
CC: rguenth at gcc dot gnu.org
Target Milestone: ---
Target: aarch64-*-*, x86_64-*-*
Created attachment 65818
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65818&action=edit
vec-perm-merge-sve.c
This is in the same family as PR123175 and PR123573: a VEC_PERM_EXPR with a
constant selector may have inputs and a result with different numbers of
elements, but the match.pd patterns that merge two consecutive
VEC_PERM_EXPRs, and is_combined_permutation_identity in forwprop, still
assume that both permutes and all their inputs have the same number of
elements.
Seen on trunk r17 at e1cf6f306d9 (20261012), on aarch64 (cross compiler)
and x86_64-pc-linux-gnu; 16.2.1 on x86_64 fails the same way.
A) aarch64, plain C (vec-perm-merge-sve.c). svld1rq folds to a permute
from a 128-bit vector to the SVE vector, and a following permute of that
gets merged into it:
svint32_t
f1 (int32_t *p)
{
svint32_t c = svld1rq_s32 (svptrue_b8 (), p);
return svrev_s32 (c);
}
$ gcc -O2 -march=armv8.2-a+sve -msve-vector-bits=256 vec-perm-merge-sve.c
error: vectors with different element number found in 'vec_perm_expr'
vector(4) int
vector(4) int
vector(4) int
vector(8) ssizetype
_1 = VEC_PERM_EXPR <_6, _6, { 3, 2, 1, 0, 3, 2, 1, 0 }>;
error: conversion of register to a different size in 'view_convert_expr'
VIEW_CONVERT_EXPR<svint32_t>(_1);
_5 = VIEW_CONVERT_EXPR<svint32_t>(_1);
during GIMPLE pass: forwprop
internal compiler error: verify_gimple failed
Same with -msve-vector-bits=512, and with svzip1/svuzp1/svuzp2/svtrn2 in
place of svrev, with c as one or both operands. With -fno-checking (so
presumably with a release compiler):
f1: compiles; the 128-bit permute result is stored to the stack and
reloaded as a 256-bit vector, so the upper half is garbage.
f2 (svzip1 (x, c)): internal compiler error: in expand_vec_perm_const,
at optabs.cc:6896 (during RTL pass: expand)
vec-perm-merge-sve-run.c is a runtime test (svrev (c) and
svtrn2 (c, x)); built with -O2 -msve-vector-bits=256 -fno-checking it
aborts under qemu-aarch64 with a 256-bit vector length, for each of its
two functions on its own. It passes at -O0.
B) Target independent, GIMPLE FE (vec-perm-merge-{1,2,3}.c, tested on
x86_64). These cover the other direction, inputs wider than the result,
which I could not get from plain C on x86_64 since
ix86_vectorize_vec_perm_const rejects vmode != op_mode. All three pass
at -O0.
1) vec-perm-merge-1.c: d = VEC_PERM <c, c>, c = VEC_PERM <a, b>, d narrower
than c.
c_ = __VEC_PERM (a_, b_, _Literal (v8si) { 8, 0, 9, 1, 10, 2, 11, 3 });
d_ = __VEC_PERM (c_, c_, _Literal (v4si) { 1, 2, 3, 4 });
The pattern builds the merged selector with d's element count as the
number of elements per input and gives the new permute a's type:
$ gcc -O1 -fgimple vec-perm-merge-1.c
vec-perm-merge-1.c:20:1: error: vectors with different element number found
in 'vec_perm_expr'
vector(8) int
v8si
v8si
v4si
_7 = VEC_PERM_EXPR <b__3, b__3, { 0, 1, 1, 2 }>;
vec-perm-merge-1.c:20:1: error: conversion of register to a different size
in 'view_convert_expr'
VIEW_CONVERT_EXPR<v4si>(_7);
d__5 = VIEW_CONVERT_EXPR<v4si>(_7);
during GIMPLE pass: forwprop
vec-perm-merge-1.c:20:1: internal compiler error: verify_gimple failed
The selector is wrong as well ({ a0, b1, a1, b2 } is expected, the result
uses only b). With -fno-checking, or a release compiler:
-O1: wrong code, the test aborts
-O2 -mavx2: internal compiler error: in ix86_vectorize_vec_perm_const,
at config/i386/i386-expand.cc:27393 (during RTL pass: expand)
2) vec-perm-merge-2.c: d = VEC_PERM <x, c>, c = VEC_PERM <a, b>, d narrower
than c. Silent wrong code at -O1 and above, also with checking enabled.
c_ = __VEC_PERM (a_, b_, _Literal (v8si) { 7, 6, 5, 4, 8, 9, 10, 11 });
d_ = __VEC_PERM (x_, c_, _Literal (v4si) { 0, 9, 7, 11 });
forwprop1 turns this into
d__6 = VEC_PERM_EXPR <x__4, x__4, { 0, 6, 7, 4 }>;
so the lanes that should come from c (a6 and a4) are taken from x. The
<c, x> variant of the pattern has the same problem.
3) vec-perm-merge-3.c: d = VEC_PERM <c, c>, c = VEC_PERM <a, b>, c narrower
than a and b.
c_ = __VEC_PERM (a_, b_, _Literal (v2hi) { 7, 6 });
d_ = __VEC_PERM (c_, c_, _Literal (v2hi) { 1, 2 });
$ gcc -O1 -fgimple vec-perm-merge-3.c
vec-perm-merge-3.c:20:1: error: vectors with different element number found
in 'vec_perm_expr'
vector(4) short int
v4hi
v4hi
v2hi
_7 = VEC_PERM_EXPR <b__3, b__3, { 2, 3 }>;
...
vec-perm-merge-3.c:20:1: internal compiler error: verify_gimple failed
With -fno-checking: internal compiler error: in
ix86_vectorize_vec_perm_const, at config/i386/i386-expand.cc:27393
(during GIMPLE pass: veclower2).
This one also has a second bug behind the first. With the match.pd
pattern fixed, simplify_permutation in forwprop sees the pair first;
is_combined_permutation_identity reduces the composed selector by the
length of c instead of the length of b, takes { 7, 6 } o { 1, 2 } for an
identity on b, and replaces the V2HI result by the V4HI input
("error: non-trivial conversion in 'ssa_name'"). With other selectors
the same path ICEs in fold_vec_perm, at fold-const.cc:10668.
I have a patch for the three match.pd patterns and for forwprop and will
post it to gcc-patches.