Re: [PATCH] libcpp: Optimize AArch64 search_line_fast

Alexander Monakov <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
On Fri, 14 Aug 2026, Wilco Dijkstra wrote:

> It's just measuring the throughput of the search_line_fast function for different sizes.
> Then calculate the average from the speedup of each size times the frequency of the
> distribution. As it happens, the old code was doing a lot of unnecessary initialization,
> checks etc, so the speedup goes from ~85% for 1-16 chars to ~50% at 80 chars.

Thanks. It's good to know that new code is that much faster for short lines,
but I suspect averaging in this manner is not ideal if measurements are taken
as if final branch is perfectly predictable.

> > Yeah. When working on x86 SSSE3 implementation I noticed that at 16 characters
> > per iteration, the branch that exits the loop tends to be pretty unpredictable
> > on "typical" C++ sources, so moving to 32 characters per iteration helped with
> > that a bit, even with 16-byte vectors (so two vector loads per iteration, etc)
> >
> > I wonder if you looked at something like that? Doing two 16-character matches
> > per one iteration, then combining results into one GPR for the final CBZ?
> > Not sure if there's a way to make the epilogue cheap enough, though.
> 
> It's certainly possible to do so, but it would be hard to measure whether it ends up
> faster. It probably means saving a trace and then replaying it. How did you measure
> the effect of branch prediction on overall compile time?

With 'perf stat -r 9 cc1plus -fsyntax-only -quiet t-rawstr.cc' where t-rawstr.cc
is a big C++ file created by preprocessing '#include <regex>' (see Makefile in
the attachment). It was posted with my SSSE3-based search_line_fast at
https://inbox.sourceware.org/gcc-patches/[email protected]/
(attaching it again to this message)
and my measurements can be seen at
https://inbox.sourceware.org/gcc-patches/[email protected]/

> >> +  const uchar *limit = (const uchar*) ((uintptr_t)end & ~15);
> >
> > This is not safe in absence of padding: when 's' itself is not aligned,
> > and 'end' is close to it, this may move 'limit' to before 's', and then
> > the load from *limit will pick up bytes prior to 's'.
> 
> Yes that's why I read from limit to get a full vector and then just shift out any
> chars before 's' - this magic removes 0-15 nibbles from the result mask based
> on the alignment of 's':
> 
> +  mask >>= (uintptr_t)s * 4;

Sorry, I missed that. Would have been worth a comment, if it wasn't going!

> > Now, libcpp provides sufficient tail padding (at least 16 bytes, with '\n'
> > at the beginning of padding area) so in context this is safe, but then
> > the final aligned load should never be reached, and computing 'limit' is
> > pointless.
> 
> If we can safely read 16 bytes beyond 'end' then yes, the loop condition could be:
> 
> while (s < end)
>   ... loop
> // no tail code, just return end since it is known that *end == '\n'.
> return end;  

No, I meant you can just have an infinite loop because the test in the loop
will work properly when *end is reached.

Alexander

PS: unfortunately I didn't get a copy of your response to my inbox and had to
fish it out of the mailing list archive
search-line-bench.tgz (application/gzip, 1.7 KB) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.