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.