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
