On Fri, Apr 3, 2026 at 3:45 AM Philipp Tomsich <[email protected]> wrote:
>
> 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.).


See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65084#c6 which is
close to the idea I was mentioning.
This is why I said there needs to be more than one pass.

Thanks,
Andrew

>
> > > 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