https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127860

            Bug ID: 127860
           Summary: expand_vec_perm_const reduces the selector by the
                    result length for a VEC_PERM_EXPR with wider inputs
                    (latent wrong code)
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: igor at tachyum dot com
  Target Milestone: ---

Created attachment 65815
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65815&action=edit
vec-perm-wide.c

expand_vec_perm_const (optabs.cc) builds the selector with the element
count of the result mode:

  vec_perm_indices indices (sel, 2, GET_MODE_NUNITS (mode));

Since r13-1055 a VEC_PERM_EXPR with a constant selector may have inputs
with a different number of elements than the result, and the selector
indexes the concatenation of the inputs (tree.def).  When the inputs
have more elements than the result, the constructor above reduces every
index modulo twice the result length, so an index into the second
input becomes an index into the first one before the target hook sees
it.  If the hook rejects the permute, the vec_shr/vec_shl shortcut and
the byte-permute and vec_perm fallbacks then use the wider inputs as
if they had the result mode.

lower_vec_perm asks can_vec_perm_const_p with indices built from the
input length (tree_to_vec_perm_indices), so the hook is asked about one
permute and handed a different one at expand time.

This is latent in tree: every vec_perm_const hook rejects
vmode != op_mode (aarch64 only accepts the SVE dupq case, which widens
and uses indices below the input length), so can_vec_perm_const_p is
false and veclower expands such a permute piecewise.  The attached
testcase passes on x86_64 trunk (r17-5096).  We hit this with an
out-of-tree port whose hook accepts permutes of inputs with twice as
many elements as the result.

To see it on x86_64, apply the attached demo change to
ix86_vectorize_vec_perm_const (not for commit; it accepts such a permute
as a permute in the input mode followed by a lowpart).  For

  v8si a_; v8si b_; v4si r_;
  r_ = __VEC_PERM (a_, b_, _Literal (v4si) { 0, 8, 1, 9 });

the result should be { a[0], b[0], a[1], b[1] }, but the hook receives
{ 0, 0, 1, 1 } and emits a single-input vpermd of a:

$ gcc -O2 -mavx2 -fgimple vec-perm-wide.c && ./a.out
0 0 1 1
Aborted

(expected 0 100 1 101; same at -O0 and with -mavx512f.)

The indices should be built with the element count of the input mode,
and the paths that need the inputs in the result mode should not be
used for wider inputs.  Patch to follow.

Reply via email to