On Tue, 23 Jun 2026, Zhongyao Chen wrote:
> > I'm trying to understand from the above and the patch, but fail. What's
> > the set of stmts we avoid to externalize because we can swap the
> > (immediate) parent?
> >
> > As said in the PR for the initial patch for the greedy search we
> > perform any heuristic will have downsides and for BB vectorization
> > swapping is as good as not swapping if operand zero discovery
> > ends up with an externalized node.
> >
> > Thanks,
> > Richard.
>
> Hi Richard,
>
> In this regression case, operand-zero discovery does end up
> externalized either way. I'm not trying to avoid externalization
> itself here; what I'm trying to avoid is introducing additional
> parent-level externalization.
>
> In this case, the immediate-parent swap retry is harmful. It swaps
> lanes that are already aligned with the first-lane operand columns,
> breaks that local shape, and then the externalization propagates
> upward. So we do not just externalize the child, we externalize the
> parent as well, which gives a shorter SLP tree and worse codegen.
>
> Without this patch, the dump shows:
> ```
> Build SLP failed: different BIT_FIELD_REF arguments in
> stmp_isum10_93.49_256 = BIT_FIELD_REF <vect__30.48_255, 64, 0>;
> SLP discovery for node ... failed
> SLP discovery for node ... failed
> Re-trying with swapped operands of stmts 1 2 3
> Build SLP for stmp_rsum00_88.79_304 = rsum00_106 + stmp_rsum00_88.79_303;
> Build SLP for stmp_isum00_89.75_298 = BIT_FIELD_REF <vect__18.74_295, 64, 64>;
> Build SLP failed: different operation in stmt
> stmp_isum00_89.75_298 = BIT_FIELD_REF <vect__18.74_295, 64, 64>;
> original stmt
> stmp_rsum00_88.79_304 = rsum00_106 + stmp_rsum00_88.79_303;
> ...
> Building vector operands from scalars
> Building parent vector operands from scalars instead
> ...
> SLP size 15 vs. limit 176.
> ```
>
> With this patch, the child may still externalize, but we skip that
> harmful immediate-parent retry, so the larger parent stays internal.
> The dump then looks like:
>
> ```
> Build SLP failed: different BIT_FIELD_REF arguments in
> stmp_isum10_93.49_256 = BIT_FIELD_REF <vect__30.48_255, 64, 0>;
> SLP discovery for node ... failed
> Building vector operands from scalars
> SLP discovery for node ... succeeded
> ...
> Build SLP for rsum00_147 = _148 + rsum00_181;
> Build SLP for isum00_143 = _144 + isum00_180;
> Build SLP for rsum10_131 = _132 + rsum10_177;
> Build SLP for isum10_127 = _128 + isum10_176;
> ...
> SLP size 19 vs. limit 176.
> ```
>
> So for this PR, "it ends up externalized anyway" is not the same as
> "swapping is as good as not swapping". The old retry makes the
> externalization spread to the parent and leaves a worse final SLP tree.
Hmm, the testcase is a bit complicated since there's loop
vectorization as well. I have tried the following alternative
patch but it doesn't make a difference for me? But in essence
what you are testing is whether both operand0 and operand1 appear
unform but with different enough operation so that swapping would
make it non-uniform. So I'd have expected the following to cover
that case as well, but maybe I misunderstood. I think we want to
avoid creating another "do stmts match" computation, re-using
vect_build_slp_tree_1 would be more reasonable for this (we could
think of refactoring that a bit, of course).
That said, I do see how the heuristic can be bad, and peeking at
operand1 looks reasonable.
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index 2250f6f74a1..c529f9c3f11 100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -3013,6 +3013,18 @@ out:
if (j != 0 && !stmt_can_swap[j])
can_swap_nonmatching = false;
}
+ unsigned char *swapt = XALLOCAVEC (unsigned char, group_size);
+ poly_uint64 max_nunitst;
+ bool *matchest = XALLOCAVEC (bool, group_size);
+ bool two_operatorst = false;
+ tree vectypet = NULL_TREE;
+ if (can_swap_nonmatching
+ && vect_build_slp_tree_1 (vinfo, swapt,
+ oprnds_info[1]->def_stmts,
+ group_size, &max_nunitst,
+ matchest, &two_operatorst,
+ &vectypet))
+ can_swap_nonmatching = false;
}
old_swap_distance = least_upthread_swappable_op_distance;
--
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald; (HRB 36809, AG Nuernberg)