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

            Bug ID: 126101
           Summary: GCC trunk vs Intel oneAPI : Missed SLP vectorization
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: Reshma.Roy at amd dot com
  Target Milestone: ---

Created attachment 64927
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=64927&action=edit
The preprocessed input file to be used for the command mentioned in the
description

----------------------------------------------------------------------
GCC trunk vs Intel oneAPI : Missed SLP vectorization
----------------------------------------------------------------------

Compiler Versions
oneAPI     : Intel oneAPI 2025.3
gcc trunk  : gcc (GCC) 17.0.0 20260623 (experimental)

The gcc behavior is compared with oneapi for a portion of the code in the
508.namd_r benchmark at location ComputeNonbondedBase2.h:129. Oneapi vectorizes
it whereas gcc failed to do so.

Reduced testcase from the benchmark:
------------------------------------
typedef double BigReal;
typedef float  Charge;

typedef struct { BigReal x, y, z; } Vector;
typedef Vector Position;
typedef Vector Force;

typedef struct {
    Position position;
    Charge   charge;
    short    vdwType;
    unsigned char partition;
    unsigned int  bits;            
} CompAtom;


typedef struct { BigReal A, B; } LJTableEntry;

__attribute__((noinline))
void calc_pair_energy_fullelect(
        int npairi,
        const int          *restrict pairlisti,
        const unsigned int *restrict r2iilist,
        int                          r2_delta_expc,
        const BigReal      *restrict r2list,
        const BigReal      *restrict r2_table,
        const BigReal      *restrict table_four,
        const CompAtom     *restrict p_1,
        const LJTableEntry *restrict lj_row,
        BigReal scaling, BigReal kq_i,
        Force              *restrict f_1,
        BigReal *restrict out_vdwEnergy,
        BigReal *restrict out_electEnergy)
{
    BigReal vdwEnergy = 0, electEnergy = 0;

    for (int k = 0; k < npairi; ++k) {
        int table_i = (r2iilist[2 * k] >> 14) + r2_delta_expc;
        const int j = pairlisti[k];
        const CompAtom *p_j = p_1 + j;

        BigReal diffa = r2list[k] - r2_table[table_i];
        const BigReal *const table_four_i = table_four + 16 * table_i;

        const LJTableEntry *lj_pars = lj_row + 2 * p_j->vdwType;
        BigReal kqq = kq_i * p_j->charge;

        /* ---- the opportunity:(Base2.h:129-132) ------------------ */
        const BigReal A = scaling * lj_pars->A;
        const BigReal B = scaling * lj_pars->B;

        BigReal vdw_d = A * table_four_i[0] - B * table_four_i[2];
        BigReal vdw_c = A * table_four_i[1] - B * table_four_i[3];
        BigReal vdw_b = A * table_four_i[4] - B * table_four_i[6];
        BigReal vdw_a = A * table_four_i[5] - B * table_four_i[7];
        /* ----------------------------------------------------------*/


        BigReal vdw_val =
            ((diffa * vdw_d * (1 / 6.) + vdw_c * (1 / 4.)) * diffa
             + vdw_b * (1 / 2.)) * diffa + vdw_a;
        vdwEnergy -= vdw_val;


        BigReal fast_d = kqq * table_four_i[8];
        BigReal fast_c = kqq * table_four_i[9];
        BigReal fast_b = kqq * table_four_i[10];
        BigReal fast_a = kqq * table_four_i[11];


        BigReal fast_val =
            ((diffa * fast_d * (1 / 6.) + fast_c * (1 / 4.)) * diffa
             + fast_b * (1 / 2.)) * diffa + fast_a;
        electEnergy -= fast_val;

      /*--------------------------------------------*/
        fast_d += vdw_d;
        fast_c += vdw_c;
        fast_b += vdw_b;
        fast_a += vdw_a;
     /* --------------------------------------------*/
        BigReal fast_dir = (diffa * fast_d + fast_c) * diffa + fast_b;


        Force *f_j = f_1 + j;
        f_j->x -= fast_dir;
        f_j->y -= fast_dir;
        f_j->z -= fast_dir;
    }

    *out_vdwEnergy = vdwEnergy;
    *out_electEnergy = electEnergy;
}

Commands used:
---------------
gcc -O3 -march=znver5 -fdump-tree-slp-details -fopt-info-vec-missed   -S -o
opp3_vdw_coeff.s  opp3_vdw_coeff.i  2> gcc_vec_missed.txt

icx -O3 -march=graniterapids   -S -Rpass=slp-vectorizer -o opp3_vdw_coeff_icx.s
 opp3_vdw_coeff.i  2> icx_vect.log

>From the gcc slp dump, we could not see any logs stating the discovery of SLP
for fast_* which is the reduction that consumes the vdw_*. Also, the missed-opt
log contains only loop-vectorizer messages unrelated to the coefficient group;
there is no BB-SLP missed-opt entry for vdw_*, looks like SLP is never seeded
on it in the first place. Even though BB-SLP is active and succeeds on the
neighboring store group. In icx the Rpass log states successful vectorization.

opp3_vdw_coeff.c:175:16: remark: SLP vectorized with cost -4 and with tree size
11 [-Rpass=slp-vectorizer]
  5   175 |         fast_c += vdw_c;
  6       |                ^

In gcc, the vdw_* group is emitted as scalar vmulsd + vfmsub231sd/vfmsub132sd.
icx, in contrast, reports SLP vectorized with cost -4 and tree size 11 at
fast_c += vdw_c and packs the group into 2-lane %xmm (vmovddup + vmulpd +
vfmsub231pd). This seems to be like SLP seed/discovery gap on straight-line
group of four A*table_four_i[i] - B*table_four_i[j] expression which share
scalars A,B and use contiguous loads.

Reply via email to