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

            Bug ID: 127152
           Summary: [17 Regression] Miscompile in vect_transform_reduction
                    since r17-3692
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dhruvc at gcc dot gnu.org
                CC: rguenth at gcc dot gnu.org
  Target Milestone: ---
            Target: aarch64

Reduced from a miscompare in 731.astcenc_r.

Source:

===
__attribute__((noipa)) float
f (float *a, int n)
{
  float s = 0.0f;
  for (int i = 0; i < n; i++)
    if (a[i] > 0.0f)
      s += a[i];
  return s;
}

int
main (void)
{
  float a[16];
  for (int i = 0; i < 16; i++)
    a[i] = (i & 1) ? 1.0f : -1.0f;
  if (f (a, 16) != 8.0f)
    __builtin_abort ();
  return 0;
}
===

Flags: -O3 -march=armv8-a+sve --param vect-partial-vector-usage=0

Compiler explorer: https://godbolt.org/z/4Ge3aqxGf

===

LLM-generated summary (might be useful, dunno):

The commit changed the vectype_in computed in vect_transform_reduction:

-  tree vectype_in = SLP_TREE_VECTYPE (slp_node);
-  if (lane_reducing_op_p (op.code))
-    vectype_in = SLP_TREE_VECTYPE (SLP_TREE_CHILDREN (slp_node)[0]);
+  slp_tree node_in = SLP_TREE_CHILDREN (slp_node)[reduc_index == 0 ? 1 : 0];
+  tree vectype_in = SLP_TREE_VECTYPE (node_in);

For an IFN_COND_* reduction, SLP_TREE_CHILDREN (slp_node)[0] is the mask node,
so vectype_in becomes a boolean vector type. That value is passed straight into
vectorize_fold_left_reduction, where

internal_fn mask_reduc_fn = get_masked_reduction_fn (reduc_fn, vectype_in);
...
if (LOOP_VINFO_FULLY_MASKED_P (loop_vinfo) && mask && mask_reduc_fn ==
IFN_LAST)
  def0 = merge_with_identity (gsi, mask, vectype_out, def0, vector_identity);

if (reduc_fn != IFN_LAST || (mask && mask_reduc_fn != IFN_LAST))
  {
    ...
    else if (mask && mask_reduc_fn == IFN_MASK_FOLD_LEFT_PLUS)
      new_stmt = ... (mask_reduc_fn, 3, reduc_var, def0, mask);
    else
      new_stmt = ... (reduc_fn, 2, reduc_var, def0);   /* <-- mask dropped */
  }

With the boolean vectype, get_masked_reduction_fn no longer returns
IFN_MASK_FOLD_LEFT_PLUS, so the emit falls into the unmasked branch and the
condition mask is silently dropped. The merge_with_identity compensation above
it only runs under LOOP_VINFO_FULLY_MASKED_P, hence:

    fully-masked loop -> mask re-applied via VCOND_MASK, value-neutral (dump
only shows MASK_FOLD_LEFT_PLUS -> FOLD_LEFT_PLUS);
    not fully masked  -> every element is accumulated regardless of the
condition -> wrong values.

Reply via email to