[PATCH] libstdc++: Optimize chrono year::is_leap
Francisco Muniz
munizfco@gmail.com
Thu Jul 30 15:52:58 GMT 2026
Thanks, I had only checked scalar code generation initially. In an
isolated scalar test on x86_64, the new form is 7 instructions versus 10
for the existing form, but I can reproduce that benchmark results depend on
optimization context. With GCC 17 -O3 generic, the loop favors the
existing form, while with -fno-tree-vectorize or -march=native the new form
is faster on my machine.
Given that, I have to do more benchmarking before claiming this is a
performance improvement, focus was mostly on number of instructions
Em qui., 30 de jul. de 2026 às 12:11, Jonathan Wakely <jwakely@redhat.com>
escreveu:
> On Thu, 30 Jul 2026 at 01:58, Francisco Muniz wrote:
> >
> > Use Falk Hueffner's leap-year test for year::is_leap after shifting
> > the valid std::chrono::year range by a multiple of 400. The shift
> > preserves divisibility by 4, 100, and 400, and the unsigned conversion
> > gives the intended modulo 2^32 arithmetic.
> >
> > Idea by Cassio Neri: add 32800, which is 82 * 400, to shift the signed
> > year range into the supported non-negative range.
>
> This is interesting, but your new code is slower than Cassio's code
> when I benchmark it. Have you done your own benchmarking?
>
> >
> > Tested on x86_64-pc-linux-gnu:
> > make -j$(nproc) all-gcc
> > make -j$(nproc) all-target-libstdc++-v3
> > make check RUNTESTFLAGS='conformance.exp=std/time/year/1.cc'
> > make check RUNTESTFLAGS='conformance.exp=std/time/year/2.cc'
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/std/chrono (year::is_leap): Use Hueffner leap-year
> > test after biasing the year by a multiple of 400.
> >
> > Signed-off-by: Francisco Muniz <munizfco@gmail.com>
> > ---
> > libstdc++-v3/include/std/chrono | 31 ++++++++-----------------------
> > 1 file changed, 8 insertions(+), 23 deletions(-)
> >
> > diff --git a/libstdc++-v3/include/std/chrono
> b/libstdc++-v3/include/std/chrono
> > index 692fd6025e7..4483914c08b 100644
> > --- a/libstdc++-v3/include/std/chrono
> > +++ b/libstdc++-v3/include/std/chrono
> > @@ -904,29 +904,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > constexpr bool
> > is_leap() const noexcept
> > {
> > - // Testing divisibility by 100 first gives better performance
> [1], i.e.,
> > - // return _M_y % 100 == 0 ? _M_y % 400 == 0 : _M_y % 16 == 0;
> > - // Furthermore, if _M_y % 100 == 0, then _M_y % 400 == 0 is
> equivalent
> > - // to _M_y % 16 == 0, so we can simplify it to
> > - // return _M_y % 100 == 0 ? _M_y % 16 == 0 : _M_y % 4 == 0.
> // #1
> > - // Similarly, we can replace 100 with 25 (which is good since
> > - // _M_y % 25 == 0 requires one fewer instruction than _M_y % 100
> == 0
> > - // [2]):
> > - // return _M_y % 25 == 0 ? _M_y % 16 == 0 : _M_y % 4 == 0.
> // #2
> > - // Indeed, first assume _M_y % 4 != 0. Then _M_y % 16 != 0 and
> hence,
> > - // _M_y % 4 == 0 and _M_y % 16 == 0 are both false. Therefore,
> #2
> > - // returns false as it should (regardless of _M_y % 25.) Now
> assume
> > - // _M_y % 4 == 0. In this case, _M_y % 25 == 0 if, and only if,
> > - // _M_y % 100 == 0, that is, #1 and #2 are equivalent. Finally,
> #2 is
> > - // equivalent to
> > - // return (_M_y & (_M_y % 25 == 0 ? 15 : 3)) == 0.
> > -
> > - // References:
> > - // [1] https://github.com/cassioneri/calendar
> > - // [2] https://godbolt.org/z/55G8rn77e
> > - // [3]
> https://gcc.gnu.org/pipermail/libstdc++/2021-June/052815.html
> > -
> > - return (_M_y & (_M_y % 25 == 0 ? 15 : 3)) == 0;
> > + // Shift into the range supported by Falk Hueffner's leap-year
> test:
> > + //
> hueffner.de/falk/blog/a-leap-year-check-in-three-instructions.html
> > + // Adding a multiple of 400 preserves divisibility by 4, 100,
> and 400.
> > + // Idea by Cassio Neri: add 32800 (82 * 400).
> > + // The conversion to uint32_t gives the algorithm's intended
> modulo 2^32
> > + // arithmetic.
> > + const auto __y = static_cast<uint32_t>(_M_y) + 32800u;
> > + return ((__y * 1073750999u) & 3221352463u) <= 126976u;
> > }
> >
> > explicit constexpr
> > --
> > 2.47.3
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260730/1b00c65d/attachment.htm>
More information about the Libstdc++
mailing list