LCOV - code coverage report
Current view: top level - gcc - vec-perm-indices.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.7 % 165 153
Test Date: 2026-07-11 15:47:05 Functions: 91.7 % 12 11
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* A representation of vector permutation indices.
       2              :    Copyright (C) 2017-2026 Free Software Foundation, Inc.
       3              : 
       4              : This file is part of GCC.
       5              : 
       6              : GCC is free software; you can redistribute it and/or modify it under
       7              : the terms of the GNU General Public License as published by the Free
       8              : Software Foundation; either version 3, or (at your option) any later
       9              : version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14              : for more details.
      15              : 
      16              : You should have received a copy of the GNU General Public License
      17              : along with GCC; see the file COPYING3.  If not see
      18              : <http://www.gnu.org/licenses/>.  */
      19              : 
      20              : #include "config.h"
      21              : #include "system.h"
      22              : #include "coretypes.h"
      23              : #include "vec-perm-indices.h"
      24              : #include "tree.h"
      25              : #include "fold-const.h"
      26              : #include "tree-vector-builder.h"
      27              : #include "backend.h"
      28              : #include "rtl.h"
      29              : #include "memmodel.h"
      30              : #include "emit-rtl.h"
      31              : #include "selftest.h"
      32              : #include "rtx-vector-builder.h"
      33              : 
      34              : 
      35              : /* Switch to a new permutation vector that selects between NINPUTS vector
      36              :    inputs that have NELTS_PER_INPUT elements each.  Take the elements of the
      37              :    new permutation vector from ELEMENTS, clamping each one to be in range.  */
      38              : 
      39              : void
      40      4001214 : vec_perm_indices::new_vector (const vec_perm_builder &elements,
      41              :                               unsigned int ninputs,
      42              :                               bool input0_bitwise_zero_p,
      43              :                               bool input1_bitwise_zero_p,
      44              :                               poly_uint64 nelts_per_input)
      45              : {
      46      4001214 :   m_ninputs = ninputs;
      47      4001214 :   m_nelts_per_input = nelts_per_input;
      48      4001214 :   m_input0_bitwise_zero_p = input0_bitwise_zero_p;
      49      4001214 :   m_input1_bitwise_zero_p = input1_bitwise_zero_p;
      50              :   /* If the vector has a constant number of elements, expand the
      51              :      encoding and clamp each element.  E.g. { 0, 2, 4, ... } might
      52              :      wrap halfway if there is only one vector input, and we want
      53              :      the wrapped form to be the canonical one.
      54              : 
      55              :      If the vector has a variable number of elements, just copy
      56              :      the encoding.  In that case the unwrapped form is canonical
      57              :      and there is no way of representing the wrapped form.  */
      58      4001214 :   poly_uint64 full_nelts = elements.full_nelts ();
      59      4001214 :   unsigned HOST_WIDE_INT copy_nelts;
      60      4001214 :   if (full_nelts.is_constant (&copy_nelts))
      61      4001214 :     m_encoding.new_vector (full_nelts, copy_nelts, 1);
      62              :   else
      63              :     {
      64              :       copy_nelts = elements.encoded_nelts ();
      65              :       m_encoding.new_vector (full_nelts, elements.npatterns (),
      66              :                              elements.nelts_per_pattern ());
      67              :     }
      68      4001214 :   unsigned int npatterns = m_encoding.npatterns ();
      69     32224727 :   for (unsigned int i = 0; i < npatterns; ++i)
      70     28223759 :     m_encoding.quick_push (clamp (elements.elt (i)));
      71              :   /* Use the fact that:
      72              : 
      73              :         (a + b) % c == ((a % c) + (b % c)) % c
      74              : 
      75              :      to simplify the clamping of variable-length vectors.  */
      76      4001214 :   for (unsigned int i = npatterns; i < copy_nelts; ++i)
      77              :     {
      78            0 :       element_type step = clamp (elements.elt (i)
      79            0 :                                  - elements.elt (i - npatterns));
      80            0 :       m_encoding.quick_push (clamp (m_encoding[i - npatterns] + step));
      81              :     }
      82      4001214 :   m_encoding.finalize ();
      83      4001214 : }
      84              : 
      85              : /* Switch to a new permutation vector that selects the same input elements
      86              :    as ORIG, but with each element split into FACTOR pieces.  For example,
      87              :    if ORIG is { 1, 2, 0, 3 } and FACTOR is 2, the new permutation is
      88              :    { 2, 3, 4, 5, 0, 1, 6, 7 }.  */
      89              : 
      90              : void
      91       663401 : vec_perm_indices::new_expanded_vector (const vec_perm_indices &orig,
      92              :                                        unsigned int factor)
      93              : {
      94       663401 :   m_ninputs = orig.m_ninputs;
      95       663401 :   m_input0_bitwise_zero_p = orig.m_input0_bitwise_zero_p;
      96       663401 :   m_input1_bitwise_zero_p = orig.m_input1_bitwise_zero_p;
      97       663401 :   m_nelts_per_input = orig.m_nelts_per_input * factor;
      98       663401 :   m_encoding.new_vector (orig.m_encoding.full_nelts () * factor,
      99       663401 :                          orig.m_encoding.npatterns () * factor,
     100              :                          orig.m_encoding.nelts_per_pattern ());
     101       663401 :   unsigned int encoded_nelts = orig.m_encoding.encoded_nelts ();
     102      2199900 :   for (unsigned int i = 0; i < encoded_nelts; ++i)
     103              :     {
     104      1536499 :       element_type base = orig.m_encoding[i] * factor;
     105      9877159 :       for (unsigned int j = 0; j < factor; ++j)
     106      8340660 :         m_encoding.quick_push (base + j);
     107              :     }
     108       663401 :   m_encoding.finalize ();
     109       663401 : }
     110              : 
     111              : /* Check whether we can switch to a new permutation vector that
     112              :    selects the same input elements as ORIG, but with each element
     113              :    built up from FACTOR pieces.  Return true if yes, otherwise
     114              :    return false.  Every FACTOR permutation indexes should be
     115              :    continuous separately and the first one of each batch should
     116              :    be able to exactly modulo FACTOR.  For example, if ORIG is
     117              :    { 2, 3, 4, 5, 0, 1, 6, 7 } and FACTOR is 2, the new permutation
     118              :    is { 1, 2, 0, 3 }.  */
     119              : 
     120              : bool
     121           24 : vec_perm_indices::new_shrunk_vector (const vec_perm_indices &orig,
     122              :                                      unsigned int factor)
     123              : {
     124           24 :   gcc_assert (factor > 0);
     125              : 
     126           24 :   if (maybe_lt (orig.m_nelts_per_input, factor))
     127              :     return false;
     128              : 
     129           24 :   poly_uint64 nelts;
     130              :   /* Invalid if vector units number isn't multiple of factor.  */
     131           48 :   if (!multiple_p (orig.m_nelts_per_input, factor, &nelts))
     132              :     return false;
     133              : 
     134              :   /* Only handle the case that npatterns is multiple of factor.
     135              :      FIXME: Try to see whether we can reshape it by factor npatterns.  */
     136           24 :   if (orig.m_encoding.npatterns () % factor != 0)
     137              :     return false;
     138              : 
     139           11 :   unsigned int encoded_nelts = orig.m_encoding.encoded_nelts ();
     140           11 :   auto_vec<element_type, 32> encoding (encoded_nelts);
     141              :   /* Separate all encoded elements into batches by size factor,
     142              :      then ensure the first element of each batch is multiple of
     143              :      factor and all elements in each batch is consecutive from
     144              :      the first one.  */
     145           12 :   for (unsigned int i = 0; i < encoded_nelts; i += factor)
     146              :     {
     147           11 :       element_type first = orig.m_encoding[i];
     148           11 :       element_type new_index;
     149           11 :       if (!multiple_p (first, factor, &new_index))
     150           10 :         return false;
     151           25 :       for (unsigned int j = 1; j < factor; ++j)
     152           24 :         if (maybe_ne (first + j, orig.m_encoding[i + j]))
     153           10 :           return false;
     154            1 :       encoding.quick_push (new_index);
     155              :     }
     156              : 
     157            1 :   m_ninputs = orig.m_ninputs;
     158            1 :   m_nelts_per_input = nelts;
     159            1 :   poly_uint64 full_nelts = exact_div (orig.m_encoding.full_nelts (), factor);
     160            1 :   unsigned int npatterns = orig.m_encoding.npatterns () / factor;
     161              : 
     162            1 :   m_encoding.new_vector (full_nelts, npatterns,
     163              :                          orig.m_encoding.nelts_per_pattern ());
     164            1 :   m_encoding.splice (encoding);
     165            1 :   m_encoding.finalize ();
     166              : 
     167            1 :   return true;
     168           11 : }
     169              : 
     170              : /* Rotate the inputs of the permutation right by DELTA inputs.  This changes
     171              :    the values of the permutation vector but it doesn't change the way that
     172              :    the elements are encoded.  */
     173              : 
     174              : void
     175        15102 : vec_perm_indices::rotate_inputs (int delta)
     176              : {
     177        15102 :   element_type element_delta = delta * m_nelts_per_input;
     178        78192 :   for (unsigned int i = 0; i < m_encoding.length (); ++i)
     179        63090 :     m_encoding[i] = clamp (m_encoding[i] + element_delta);
     180        15102 : }
     181              : 
     182              : /* Return true if index OUT_BASE + I * OUT_STEP selects input
     183              :    element IN_BASE + I * IN_STEP.  For example, the call to test
     184              :    whether a permute reverses a vector of N elements would be:
     185              : 
     186              :      series_p (0, 1, N - 1, -1)
     187              : 
     188              :    which would return true for { N - 1, N - 2, N - 3, ... }.
     189              :    The calls to test for an interleaving of elements starting
     190              :    at N1 and N2 would be:
     191              : 
     192              :      series_p (0, 2, N1, 1) && series_p (1, 2, N2, 1).
     193              : 
     194              :    which would return true for { N1, N2, N1 + 1, N2 + 1, ... }.  */
     195              : 
     196              : bool
     197      4151106 : vec_perm_indices::series_p (unsigned int out_base, unsigned int out_step,
     198              :                             element_type in_base, element_type in_step) const
     199              : {
     200              :   /* Check the base value.  */
     201      4151106 :   if (maybe_ne (clamp (m_encoding.elt (out_base)), clamp (in_base)))
     202              :     return false;
     203              : 
     204      1340848 :   element_type full_nelts = m_encoding.full_nelts ();
     205      1340848 :   unsigned int npatterns = m_encoding.npatterns ();
     206              : 
     207              :   /* Calculate which multiple of OUT_STEP elements we need to get
     208              :      back to the same pattern.  */
     209      1340848 :   unsigned int cycle_length = least_common_multiple (out_step, npatterns);
     210              : 
     211              :   /* Check the steps.  */
     212      1340848 :   in_step = clamp (in_step);
     213      1340848 :   out_base += out_step;
     214      1340848 :   unsigned int limit = 0;
     215      2438380 :   for (;;)
     216              :     {
     217              :       /* Succeed if we've checked all the elements in the vector.  */
     218      1889614 :       if (known_ge (out_base, full_nelts))
     219      1340848 :         return true;
     220              : 
     221      1586189 :       if (out_base >= npatterns)
     222              :         {
     223              :           /* We've got to the end of the "foreground" values.  Check
     224              :              2 elements from each pattern in the "background" values.  */
     225       949622 :           if (limit == 0)
     226       872712 :             limit = out_base + cycle_length * 2;
     227        76910 :           else if (out_base >= limit)
     228              :             return true;
     229              :         }
     230              : 
     231      1558512 :       element_type v0 = m_encoding.elt (out_base - out_step);
     232      1558512 :       element_type v1 = m_encoding.elt (out_base);
     233      1880058 :       if (maybe_ne (clamp (v1 - v0), in_step))
     234              :         return false;
     235              : 
     236       548766 :       out_base += out_step;
     237       548766 :     }
     238              : }
     239              : 
     240              : /* Return true if all elements of the permutation vector are in the range
     241              :    [START, START + SIZE).  */
     242              : 
     243              : bool
     244      3515103 : vec_perm_indices::all_in_range_p (element_type start, element_type size) const
     245              : {
     246              :   /* Check the first two elements of each pattern.  */
     247      3515103 :   unsigned int npatterns = m_encoding.npatterns ();
     248      3515103 :   unsigned int nelts_per_pattern = m_encoding.nelts_per_pattern ();
     249      3515103 :   unsigned int base_nelts = npatterns * MIN (nelts_per_pattern, 2);
     250     14916262 :   for (unsigned int i = 0; i < base_nelts; ++i)
     251     24974896 :     if (!known_in_range_p (m_encoding[i], start, size))
     252              :       return false;
     253              : 
     254              :   /* For stepped encodings, check the full range of the series.  */
     255      1342525 :   if (nelts_per_pattern == 3)
     256              :     {
     257       402163 :       element_type limit = input_nelts ();
     258              : 
     259              :       /* The number of elements in each pattern beyond the first two
     260              :          that we checked above.  */
     261       402163 :       poly_int64 step_nelts = exact_div (m_encoding.full_nelts (),
     262       402163 :                                          npatterns) - 2;
     263       843184 :       for (unsigned int i = 0; i < npatterns; ++i)
     264              :         {
     265              :           /* BASE1 has been checked but BASE2 hasn't.   */
     266       637852 :           element_type base1 = m_encoding[i + npatterns];
     267       637852 :           element_type base2 = m_encoding[i + base_nelts];
     268              : 
     269              :           /* The step to add to get from BASE1 to each subsequent value.  */
     270       637852 :           element_type step = clamp (base2 - base1);
     271              : 
     272              :           /* STEP has no inherent sign, so a value near LIMIT can
     273              :              act as a negative step.  The series is in range if it
     274              :              is in range according to one of the two interpretations.
     275              : 
     276              :              Since we're dealing with clamped values, ELEMENT_TYPE is
     277              :              wide enough for overflow not to be a problem.  */
     278       637852 :           element_type headroom_down = base1 - start;
     279       637852 :           element_type headroom_up = size - headroom_down - 1;
     280       637852 :           HOST_WIDE_INT diff;
     281       637852 :           if ((!step.is_constant (&diff)
     282       637852 :                || maybe_lt (headroom_up, diff * step_nelts))
     283       197056 :               && (!(limit - step).is_constant (&diff)
     284       197056 :                   || maybe_lt (headroom_down, diff * step_nelts)))
     285      2369409 :             return false;
     286              :         }
     287              :     }
     288              :   return true;
     289              : }
     290              : 
     291              : /* Try to read the contents of VECTOR_CST CST as a constant permutation
     292              :    vector.  Return true and add the elements to BUILDER on success,
     293              :    otherwise return false without modifying BUILDER.  */
     294              : 
     295              : bool
     296      2072941 : tree_to_vec_perm_builder (vec_perm_builder *builder, tree cst)
     297              : {
     298      2072941 :   unsigned int encoded_nelts = vector_cst_encoded_nelts (cst);
     299     10543309 :   for (unsigned int i = 0; i < encoded_nelts; ++i)
     300      8470393 :     if (!tree_fits_poly_int64_p (VECTOR_CST_ENCODED_ELT (cst, i)))
     301              :       return false;
     302              : 
     303      4145832 :   builder->new_vector (TYPE_VECTOR_SUBPARTS (TREE_TYPE (cst)),
     304      2072916 :                        VECTOR_CST_NPATTERNS (cst),
     305      2072916 :                        VECTOR_CST_NELTS_PER_PATTERN (cst));
     306     10543284 :   for (unsigned int i = 0; i < encoded_nelts; ++i)
     307      8470368 :     builder->quick_push (tree_to_poly_int64 (VECTOR_CST_ENCODED_ELT (cst, i)));
     308              :   return true;
     309              : }
     310              : 
     311              : /* Try to read the contents of VECTOR_CST PERM_CST as a constant permutation
     312              :    vector permuting OP0 and OP1.  Return true and populate INDICES on success,
     313              :    otherwise return false without modifying INDICES.  */
     314              : 
     315              : bool
     316       322558 : tree_to_vec_perm_indices (vec_perm_indices *indices, tree op0, tree op1,
     317              :                           tree perm_cst)
     318              : {
     319       322558 :   vec_perm_builder builder;
     320       322558 :   if (!tree_to_vec_perm_builder (&builder, perm_cst))
     321              :     return false;
     322       322557 :   indices->new_vector (builder, op0 == op1 ? 1 : 2,
     323       322557 :                        initializer_zerop (op0), initializer_zerop (op1),
     324       322557 :                        TYPE_VECTOR_SUBPARTS (TREE_TYPE (op0)));
     325       322557 :   return true;
     326       322558 : }
     327              : 
     328              : 
     329              : /* Return a VECTOR_CST of type TYPE for the permutation vector in INDICES.  */
     330              : 
     331              : tree
     332      1235107 : vec_perm_indices_to_tree (tree type, const vec_perm_indices &indices)
     333              : {
     334      1235107 :   gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (type), indices.length ()));
     335      1235107 :   tree_vector_builder sel (type, indices.encoding ().npatterns (),
     336      1235107 :                            indices.encoding ().nelts_per_pattern ());
     337      1235107 :   unsigned int encoded_nelts = sel.encoded_nelts ();
     338      8376415 :   for (unsigned int i = 0; i < encoded_nelts; i++)
     339      7141308 :     sel.quick_push (build_int_cst (TREE_TYPE (type), indices[i]));
     340      1235107 :   return sel.build ();
     341      1235107 : }
     342              : 
     343              : /* Return a CONST_VECTOR of mode MODE that contains the elements of
     344              :    INDICES.  */
     345              : 
     346              : rtx
     347            0 : vec_perm_indices_to_rtx (machine_mode mode, const vec_perm_indices &indices)
     348              : {
     349            0 :   gcc_assert (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
     350              :               && known_eq (GET_MODE_NUNITS (mode), indices.length ()));
     351            0 :   rtx_vector_builder sel (mode, indices.encoding ().npatterns (),
     352            0 :                           indices.encoding ().nelts_per_pattern ());
     353            0 :   unsigned int encoded_nelts = sel.encoded_nelts ();
     354            0 :   for (unsigned int i = 0; i < encoded_nelts; i++)
     355            0 :     sel.quick_push (gen_int_mode (indices[i], GET_MODE_INNER (mode)));
     356            0 :   return sel.build ();
     357            0 : }
     358              : 
     359              : #if CHECKING_P
     360              : 
     361              : namespace selftest {
     362              : 
     363              : /* Test a 12-element vector.  */
     364              : 
     365              : static void
     366            4 : test_vec_perm_12 (void)
     367              : {
     368            4 :   vec_perm_builder builder (12, 12, 1);
     369           20 :   for (unsigned int i = 0; i < 4; ++i)
     370              :     {
     371           16 :       builder.quick_push (i * 5);
     372           16 :       builder.quick_push (3 + i);
     373           16 :       builder.quick_push (2 + 3 * i);
     374              :     }
     375            4 :   vec_perm_indices indices (builder, 1, 12);
     376            4 :   ASSERT_TRUE (indices.series_p (0, 3, 0, 5));
     377            4 :   ASSERT_FALSE (indices.series_p (0, 3, 3, 5));
     378            4 :   ASSERT_FALSE (indices.series_p (0, 3, 0, 8));
     379            4 :   ASSERT_TRUE (indices.series_p (1, 3, 3, 1));
     380            4 :   ASSERT_TRUE (indices.series_p (2, 3, 2, 3));
     381              : 
     382            4 :   ASSERT_TRUE (indices.series_p (0, 4, 0, 4));
     383            4 :   ASSERT_FALSE (indices.series_p (1, 4, 3, 4));
     384              : 
     385            4 :   ASSERT_TRUE (indices.series_p (0, 6, 0, 10));
     386            4 :   ASSERT_FALSE (indices.series_p (0, 6, 0, 100));
     387              : 
     388            4 :   ASSERT_FALSE (indices.series_p (1, 10, 3, 7));
     389            4 :   ASSERT_TRUE (indices.series_p (1, 10, 3, 8));
     390              : 
     391            4 :   ASSERT_TRUE (indices.series_p (0, 12, 0, 10));
     392            4 :   ASSERT_TRUE (indices.series_p (0, 12, 0, 11));
     393            4 :   ASSERT_TRUE (indices.series_p (0, 12, 0, 100));
     394            4 : }
     395              : 
     396              : /* Run selftests for this file.  */
     397              : 
     398              : void
     399            4 : vec_perm_indices_cc_tests ()
     400              : {
     401            4 :   test_vec_perm_12 ();
     402            4 : }
     403              : 
     404              : } // namespace selftest
     405              : 
     406              : #endif
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.