On Fri, 3 Apr 2026 at 05:53, Andrew Pinski
<[email protected]> wrote:
>
> On Thu, Apr 2, 2026 at 8:31 PM Hans-Peter Nilsson <[email protected]> wrote:
> >
> > On Thu, 2 Apr 2026, Philipp Tomsich wrote:
> > > On Thu, 2 Apr 2026 at 03:52, Hans-Peter Nilsson <[email protected]> wrote:
> > > >
> > > > On Fri, 13 Mar 2026, Philipp Tomsich wrote:
> > > >
> > > > > Add a new SSA pass (pass_widen_accum) that widens narrow integer
> > > > > loop accumulators (e.g. short, char) to int-width, eliminating
> > > > > per-iteration sign-/zero-extension truncations.
> > > >
> > > > I see you really mean int-width, like
> > > >  tree wide_type = unsigned_type_node
> > >
> > > The widening to int is intentional; it's the minimum width that
> > > eliminates the per-iteration truncations, and going wider would hurt
> > > vectorization.

To clarify — the pass runs before the vectorizer. The vectorizer sees
the widened type and vectorizes at the wider element width (e.g., e32
instead of e16 for a short accumulator widened to int). The concern
about implicit zero-extend not being free for vectorization is about
the scalar-to-vector transition at loop boundaries, not the loop body
itself. Inside the vectorized loop, the element width determines
throughput: e16 gives 2x the elements per vector register vs e32. So
the choice of widening target directly affects vector throughput,
which is why we want the minimum width that eliminates the truncation
— and that's target-dependent (hence the hook; see my response to
H-P's original mail.).

> > Confusing argument about a separate optimization, though
> > pragmatically it might be correct for some targets.  But, that
> > argument isn't found in the patch-set, is it?
>
> In fact I think we need a few versions of this pass through the
> pipeline. In a few different ways.
> We need a pass which does this for induction variables and that should
> be done to the width of the WORD_MODE.
> Second is we need a pass which does it to the smallest size that is
> being loaded.
>
> Third will be the pass late before expand which corrects up the
> smallest size case to either word mode or a few modes that is
> reasonable for the target. And then have the ability to remove some
> zero/sign extends inside the loop.

The three-pass architecture (induction variable widening, accumulator
widening to load width, late pre-expand cleanup) is an interesting
direction.
This work originated from a 4 year old ticket targeting a measured
CoreMark bottleneck; it handles the case if "widen and eliminate
in-loop truncations".
A broader architecture with 3 passes could be pursued as a follow-on.

> From the sound of it, the version we are talking about here is the
> second one. But I am not sure widening to int is correct either. Even
> for aarch64, the implicit zero-extend is not free for vectorization at
> all. So that argument goes out the window. But then I go and read what
> it does, it actually sounds like the third case.
>
> Also there was almost no description of the pass in the original
> message to the mailing list except in the code itself. Having a wiki
> page on the pass which describes what it does and why the choices are
> happening that way would be nice.

 I'll add a comment block at the top of the pass explaining the design
rationale, pass placement, and interaction with vectorization.
Happy to create a wiki page if you think that's more appropriate than
inline documentation — I must admit that I can't remember when I went
to the Wiki to look for information about a pass (I exclusively check
the source file implementing it for documentation).  Your call on
creating the Wiki-page.

> On a secondary note to this, I think we should start up the RFC
> process again and start up the release planning process like we had
> back in early 4.x days (e.g.
> https://gcc.gnu.org/wiki/GCC_4.3_Release_Planning). Especially if we
> are going to have these huge pass additions.
>
>
> Also comments on the code here:
> +      /* Already verified on a convergent path -- ok.  In-loop merge
> +        PHIs cannot form cycles without going through the header
> +        PHI, so a previously visited node is safe.  */
> +      if (visited.add (name))
> +       return true;
>
> Since name is always a SSA_NAME (you check above), you could just make
> visited a bitmap that is pre-allocated and mark it that way instead of
> a hash_map. That would be faster and small and not worry about hash
> conflicts.

Acknowledged and agreed.

>
> +  tree *mapped = narrow_to_wide.get (back_arg);
> +  if (mapped)
> +    return *mapped;
>
> narrow_to_wide could be a vect since you again have a SSA_NAME. Or
> better yet use the version as the key rather than tree.

Acknowledged and agreed.


> Thanks,
> Andrew Pinski
>
> >
> > > The pass already trades vector throughput for truncation elimination:
> > > a short accumulator vectorizes at e16 (VLEN/16 elements on RVV, 8
> > > elements in a NEON 128-bit register), and widening to int halves that
> > > to e32. Widening further to register width (64-bit) would halve it
> > > again to e64 ? a 4x reduction from the original.
> >
> > I see.
> >
> > > > So, those sign-/zero-extension truncations will still typically
> > > > happen for LP64-targets, where "int" is 32 bits and registers
> > > > are 64 bits.  So, shouldn't that "int-width" better be
> > > > "register-width", typically (u)intptr_t?
> > >
> > > On the targets where 32-bit operations still produce implicit extensions:
> > > - AArch64 and x86-64: 32-bit register operations implicitly
> > > zero-extend to 64 bits. Widening to int already eliminates all
> > > truncation overhead ? no 32-to-64 extensions remain.
> > > - RISC-V 64: addw/subw sign-extend their 32-bit result to 64 bits. Any
> > > explicit sext.w after them is redundant and is cleaned up by REE,
> > > combine, and ext-dce at the RTL level. The residual cases (unsigned
> > > accumulator needing zero-extension in a 64-bit context) should be rare
> > > and will (hopefully) be handled by ext-dce's bit-level liveness
> > > analysis.
> >
> > No, that's not a complete list.  It might be the targets you
> > know or care about, but it's still incomplete.  Hint:
> > LP64 targets that don't have vectorization.
> >
> > > Register-width widening would sacrifice vector throughput on every
> > > target for a cleanup that RTL passes should already handle.
> >
> > Incorrect.  I'd suggest a target hook.  If it would default to
> > register-sized type in the absence of vectorization, it'd be
> > perfect.  The current setting with a comment about the
> > vectorisation reasoning and targets better see to the best
> > setting themselves, could also be ok.  The hook should be
> > controllable from the target as an implicit effect of a target
> > option (like, one that selects vectorization for that target),
> > so from a function call rather than a constant.
> >
> > brgds, H-P

Reply via email to