Re: Canonical way / best practice for 128-bit integers

From: Patrick Mahan <plmahan_at_gmail.com>
Date: Sun, 10 Jul 2022 04:24:47 UTC
On Sat, Jul 9, 2022 at 10:06 AM Dimitry Andric <dim@freebsd.org> wrote:

> On 9 Jul 2022, at 18:26, Marc Veldman <marc@bumblingdork.com> wrote:
> >
> > I’m working on some bluetooth code, and that involves handling 128-bit
> uuids.
> > There are various ways to handle in the FreeBSD codebase, like in sdp.h:
> >
> > /*
> > * SDP int128/uint128 parameter
> > */
> >
> > struct int128 {
> >        int8_t  b[16];
> > };
> > typedef struct int128   int128_t;
> > typedef struct int128   uint128_t;
> >
> > and in sys/dev/random/uint128.h
> >
> > #ifdef USE_REAL_UINT128_T
> > typedef __uint128_t uint128_t;
> > #define UINT128_ZERO 0ULL
> > #else
> > typedef struct {
> >        /* Ignore endianness */
> >        uint64_t u128t_word0;
> >        uint64_t u128t_word1;
> > } uint128_t;
> > static const uint128_t very_long_zero = {0UL,0UL};
> > #define UINT128_ZERO very_long_zero
> > #endif
> >
> > Is there any recommended / standard way to handle 128 bit integers in a
> portable way?
>
> Of course recent compilers have built-in support for __int128_t and
> __uint128_t, but it comes with a *lot* of caveats: not supported on all
> architectures, definitely never on 32-bit ones, differences between
> compilers, and even compiler versions, etc etc.
>
> If you want it portable, the only way is to handle them as two 64 bit
> integers, and leave any arithmetic or conversion to library routines.
>
>
I second this, especially if you want to use any of the underlying assembly
code.  For example, the Intel architecture supports the data type but does
not support 128-bit instructions but instead requires you to shift the
upper 64 bits to operate with a 64-bit instruction.

I found this out when we needed to speed up the ability to walk a 128-bit
bitmask (we were doing it the hard way).   I wound up converting everything
back to 64-bit and saw a tremendous speed up in our code.

I mostly use it for defining the storage of an IP address (either IPv4 or
IPv6) where storage does not need to be exceedingly tight.

Also, I have only used it on Intel/AMD architectures.  Back when I was
working in MIPS architectures (mostly Cavium multi-core) we did not have
this data type available.  And I have only briefly looked at AArch64 so it
may or may not be supported there.

Patrick