Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 03 Jun 2026 12:47:04 +0000
From:      Renato Botelho <garga@FreeBSD.org>
To:        ports-committers@FreeBSD.org, dev-commits-ports-all@FreeBSD.org, dev-commits-ports-main@FreeBSD.org
Subject:   git: 5d154bfea96e - main - net-mgmt/iprange: Backport fix for 32-bit platforms
Message-ID:  <6a202248.256d0.5f955116@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by garga:

URL: https://cgit.FreeBSD.org/ports/commit/?id=5d154bfea96e26773ce19e8aa7103c338d128424

commit 5d154bfea96e26773ce19e8aa7103c338d128424
Author:     Renato Botelho <garga@FreeBSD.org>
AuthorDate: 2026-06-03 12:42:56 +0000
Commit:     Renato Botelho <garga@FreeBSD.org>
CommitDate: 2026-06-03 12:46:59 +0000

    net-mgmt/iprange: Backport fix for 32-bit platforms
    
    I've added it as a local patch instead of using PATCHFILES because
    upstream patch touches CMakeLists.txt, which is not present on release
    tarball for some unknown reason.
    
    Obtained from:  upstream 268d7d8794f3f8a6c2d6f08dc4351e767990e683
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 net-mgmt/iprange/Makefile                          |    7 +-
 .../patch-268d7d8794f3f8a6c2d6f08dc4351e767990e683 | 1083 ++++++++++++++++++++
 2 files changed, 1087 insertions(+), 3 deletions(-)

diff --git a/net-mgmt/iprange/Makefile b/net-mgmt/iprange/Makefile
index c25b60bdf246..bd912c6e6489 100644
--- a/net-mgmt/iprange/Makefile
+++ b/net-mgmt/iprange/Makefile
@@ -1,5 +1,6 @@
 PORTNAME=	iprange
 PORTVERSION=	2.0.0
+PORTREVISION=	1
 CATEGORIES=	net-mgmt
 MASTER_SITES=	https://github.com/firehol/iprange/releases/download/v${PORTVERSION}/
 
@@ -10,13 +11,13 @@ WWW=		https://github.com/firehol/iprange
 LICENSE=	GPLv2+
 LICENSE_FILE=	${WRKSRC}/COPYING
 
-USES=		tar:xz
-
-IGNORE_i386=	__uint128_t is not available on i386 and is required for mandatory IPv6 support
+USES=		autoreconf tar:xz
 
 GNU_CONFIGURE=	yes
 GNU_CONFIGURE_MANPREFIX=	${PREFIX}/share
 
+PATCH_STRIP=	-p1
+
 PLIST_FILES=	bin/iprange \
 		share/man/man1/iprange.1.gz
 
diff --git a/net-mgmt/iprange/files/patch-268d7d8794f3f8a6c2d6f08dc4351e767990e683 b/net-mgmt/iprange/files/patch-268d7d8794f3f8a6c2d6f08dc4351e767990e683
new file mode 100644
index 000000000000..1006dfafebf6
--- /dev/null
+++ b/net-mgmt/iprange/files/patch-268d7d8794f3f8a6c2d6f08dc4351e767990e683
@@ -0,0 +1,1083 @@
+From 268d7d8794f3f8a6c2d6f08dc4351e767990e683 Mon Sep 17 00:00:00 2001
+From: "R. Christian McDonald" <rcm@rcm.sh>
+Date: Tue, 2 Jun 2026 11:57:11 -0400
+Subject: [PATCH] ipv6: support 32-bit platforms without __uint128_t
+
+IPv6 support (2.0.0) relied on the __uint128_t builtin, which i386 and
+armv7 lack, so the build hard-errored there.
+
+Add src/uint128.h: on 64-bit it typedefs __uint128_t and inlines the bare
+operators (unchanged codegen); on 32-bit it falls back to a portable
+{hi, lo} struct with explicit arithmetic.
+---
+ Makefile.am           |   1 +
+ configure.ac          |   5 +-
+ src/iprange6.h        |  53 +++++-----
+ src/iprange6_main.c   |  24 ++---
+ src/ipset6.c          |   4 +-
+ src/ipset6.h          |  20 ++--
+ src/ipset6_binary.c   |  36 +++----
+ src/ipset6_common.c   |   8 +-
+ src/ipset6_diff.c     |  24 ++---
+ src/ipset6_exclude.c  |  16 +--
+ src/ipset6_load.c     |  12 +--
+ src/ipset6_optimize.c |  16 +--
+ src/ipset6_print.c    |  22 ++--
+ src/uint128.h         | 230 ++++++++++++++++++++++++++++++++++++++++++
+ 15 files changed, 356 insertions(+), 121 deletions(-)
+ create mode 100644 src/uint128.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 64353db..fa9043f 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -34,6 +34,7 @@ iprange_SOURCES = \
+ 	src/iprange.c \
+ 	src/iprange.h \
+ 	src/iprange6.h \
++	src/uint128.h \
+ 	src/iprange6_main.c \
+ 	src/ipset.c \
+ 	src/ipset.h \
+diff --git a/configure.ac b/configure.ac
+index 0015482..992b67b 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -73,8 +73,9 @@ CC="${PTHREAD_CC}"
+ AC_TYPE_UINT32_T
+ AC_C_INLINE
+ 
+-AC_CHECK_TYPE([__uint128_t], [],
+-  [AC_MSG_ERROR([Your compiler does not support __uint128_t, required for IPv6 support.])],
++AC_CHECK_TYPE([__uint128_t],
++  [AC_MSG_NOTICE([Native __uint128_t detected — using hardware 128-bit integers for IPv6])],
++  [AC_MSG_NOTICE([__uint128_t not available — using portable 128-bit arithmetic for IPv6])],
+   [/* no includes needed */])
+ 
+ test "${with_compare_with_common}" = "yes" && AC_DEFINE([COMPARE_WITH_COMMON], [1], [compare settings])
+diff --git a/src/iprange6.h b/src/iprange6.h
+index 2bf0871..448f28c 100644
+--- a/src/iprange6.h
++++ b/src/iprange6.h
+@@ -2,10 +2,11 @@
+ #define IPRANGE_IPRANGE6_H
+ 
+ #include "iprange.h"
++#include "uint128.h"
+ #include <string.h>
+ 
+ /* IPv6 address type: 128-bit unsigned integer in host byte order */
+-typedef __uint128_t ipv6_addr_t;
++typedef uint128_t ipv6_addr_t;
+ 
+ /* IPv6 network address type: one field for the net address, one for broadcast */
+ typedef struct network_addr6 {
+@@ -14,11 +15,11 @@ typedef struct network_addr6 {
+ } network_addr6_t;
+ 
+ /* Maximum IPv6 address */
+-#define IPV6_ADDR_MAX ((ipv6_addr_t)((__uint128_t)(-1)))
++#define IPV6_ADDR_MAX U128_MAX
+ 
+ /* IPv4-mapped IPv6 prefix: ::ffff:0:0/96 */
+-#define IPV6_MAPPED_PREFIX ((ipv6_addr_t)0xFFFF00000000ULL)
+-#define IPV6_MAPPED_MASK   ((ipv6_addr_t)0xFFFFFFFFULL)
++#define IPV6_MAPPED_PREFIX (u128_from_u64(0xFFFF00000000ULL))
++#define IPV6_MAPPED_MASK   (u128_from_u64(0xFFFFFFFFULL))
+ 
+ #define IP6STR_MAX_LEN 46
+ 
+@@ -28,18 +29,18 @@ typedef struct network_addr6 {
+ /*----------------------------------------------------------------------*/
+ 
+ static inline ipv6_addr_t in6_addr_to_ipv6(const struct in6_addr *in6) {
+-    ipv6_addr_t result = 0;
++    ipv6_addr_t result = U128_ZERO;
+     int i;
+     for(i = 0; i < 16; i++)
+-        result = (result << 8) | in6->s6_addr[i];
++        result = u128_or(u128_shl(result, 8), u128_from_u64(in6->s6_addr[i]));
+     return result;
+ }
+ 
+ static inline void ipv6_to_in6_addr(ipv6_addr_t addr, struct in6_addr *in6) {
+     int i;
+     for(i = 15; i >= 0; i--) {
+-        in6->s6_addr[i] = (uint8_t)(addr & 0xFF);
+-        addr >>= 8;
++        in6->s6_addr[i] = (uint8_t)u128_lo64(addr);
++        addr = u128_shr(addr, 8);
+     }
+ }
+ 
+@@ -48,24 +49,24 @@ static inline void ipv6_to_in6_addr(ipv6_addr_t addr, struct in6_addr *in6) {
+ /*----------------------------------------------*/
+ static inline ipv6_addr_t netmask6(int prefix) {
+     if(prefix == 0)
+-        return (ipv6_addr_t)0;
++        return U128_ZERO;
+     if(prefix >= 128)
+         return IPV6_ADDR_MAX;
+-    return IPV6_ADDR_MAX << (128 - prefix);
++    return u128_shl(U128_MAX, 128 - prefix);
+ }
+ 
+ /*----------------------------------------------------*/
+ /* Compute broadcast address given address and prefix  */
+ /*----------------------------------------------------*/
+ static inline ipv6_addr_t broadcast6(ipv6_addr_t addr, int prefix) {
+-    return addr | ~netmask6(prefix);
++    return u128_or(addr, u128_not(netmask6(prefix)));
+ }
+ 
+ /*--------------------------------------------------*/
+ /* Compute network address given address and prefix  */
+ /*--------------------------------------------------*/
+ static inline ipv6_addr_t network6(ipv6_addr_t addr, int prefix) {
+-    return addr & netmask6(prefix);
++    return u128_and(addr, netmask6(prefix));
+ }
+ 
+ /*------------------------------------------------------------------*/
+@@ -73,9 +74,9 @@ static inline ipv6_addr_t network6(ipv6_addr_t addr, int prefix) {
+ /*------------------------------------------------------------------*/
+ static inline ipv6_addr_t set_bit6(ipv6_addr_t addr, int bitno, int val) {
+     if(val)
+-        return addr | ((__uint128_t)1 << (128 - bitno));
++        return u128_or(addr, u128_shl(U128_ONE, 128 - bitno));
+     else
+-        return addr & ~((__uint128_t)1 << (128 - bitno));
++        return u128_and(addr, u128_not(u128_shl(U128_ONE, 128 - bitno)));
+ }
+ 
+ /*-----------------------------------------------------------*/
+@@ -121,8 +122,8 @@ static inline network_addr6_t str2netaddr6(char *ipstr, int *err) {
+                     || parsed_prefix < 0 || parsed_prefix > 128)) {
+             if(err) (*err)++;
+             fprintf(stderr, "%s: Invalid IPv6 prefix /%s\n", PROG, prefixstr);
+-            netaddr.addr = 0;
+-            netaddr.broadcast = 0;
++            netaddr.addr = U128_ZERO;
++            netaddr.broadcast = U128_ZERO;
+             return netaddr;
+         }
+         prefix = (int)parsed_prefix;
+@@ -131,8 +132,8 @@ static inline network_addr6_t str2netaddr6(char *ipstr, int *err) {
+     if(!str_to_ipv6(ipstr, &addr)) {
+         if(err) (*err)++;
+         fprintf(stderr, "%s: Invalid IPv6 address %s\n", PROG, ipstr);
+-        netaddr.addr = 0;
+-        netaddr.broadcast = 0;
++        netaddr.addr = U128_ZERO;
++        netaddr.broadcast = U128_ZERO;
+         return netaddr;
+     }
+ 
+@@ -149,21 +150,21 @@ static inline network_addr6_t str2netaddr6(char *ipstr, int *err) {
+ /* Check if an IPv6 address is IPv4-mapped (::ffff:x.x.x.x)  */
+ /*-----------------------------------------------------------*/
+ static inline int is_ipv4_mapped(ipv6_addr_t addr) {
+-    return (addr >> 32) == 0xFFFF;
++    return u128_eq(u128_shr(addr, 32), u128_from_u64(0xFFFF));
+ }
+ 
+ /*-----------------------------------------------------------*/
+ /* Convert IPv4 to IPv4-mapped IPv6                           */
+ /*-----------------------------------------------------------*/
+ static inline ipv6_addr_t ipv4_to_mapped6(in_addr_t ipv4) {
+-    return IPV6_MAPPED_PREFIX | (ipv6_addr_t)ipv4;
++    return u128_or(IPV6_MAPPED_PREFIX, u128_from_u64(ipv4));
+ }
+ 
+ /*-----------------------------------------------------------*/
+ /* Extract IPv4 from IPv4-mapped IPv6                         */
+ /*-----------------------------------------------------------*/
+ static inline in_addr_t mapped6_to_ipv4(ipv6_addr_t addr) {
+-    return (in_addr_t)(addr & IPV6_MAPPED_MASK);
++    return (in_addr_t)u128_lo64(u128_and(addr, IPV6_MAPPED_MASK));
+ }
+ 
+ /*-----------------------------------------------------------*/
+@@ -171,18 +172,18 @@ static inline in_addr_t mapped6_to_ipv4(ipv6_addr_t addr) {
+ /* Returns pointer to start of number within buf               */
+ /* buf must be at least 40 bytes                               */
+ /*-----------------------------------------------------------*/
+-static inline char *u128_to_dec(char *buf, size_t buflen, __uint128_t val) {
++static inline char *u128_to_dec(char *buf, size_t buflen, uint128_t val) {
+     char *p = buf + buflen - 1;
+     *p = '\0';
+ 
+-    if(val == 0) {
++    if(u128_is_zero(val)) {
+         *(--p) = '0';
+         return p;
+     }
+ 
+-    while(val > 0) {
+-        *(--p) = '0' + (char)(val % 10);
+-        val /= 10;
++    while(!u128_is_zero(val)) {
++        *(--p) = '0' + (char)u128_mod10(val);
++        val = u128_div10(val);
+     }
+     return p;
+ }
+diff --git a/src/iprange6_main.c b/src/iprange6_main.c
+index 0484406..07c9e8d 100644
+--- a/src/iprange6_main.c
++++ b/src/iprange6_main.c
+@@ -42,9 +42,9 @@ static void free_pathnames6(char **files, size_t entries)
+     free(files);
+ }
+ 
+-static __uint128_t ipset6_report_unique_ips(ipset6 *ips, size_t *entries)
++static uint128_t ipset6_report_unique_ips(ipset6 *ips, size_t *entries)
+ {
+-    __uint128_t unique_ips = ipset6_unique_ips(ips);
++    uint128_t unique_ips = ipset6_unique_ips(ips);
+     if(entries) *entries = ips->entries;
+     return unique_ips;
+ }
+@@ -337,7 +337,7 @@ int iprange6_run(int argc, char **argv, int mode, IPSET_PRINT_CMD print,
+         if(mode == MODE_COMBINE)
+             ipset6_print(root, print);
+         else if(mode == MODE_COUNT_UNIQUE_MERGED) {
+-            __uint128_t unique_ips = ipset6_report_unique_ips(root, NULL);
++            uint128_t unique_ips = ipset6_report_unique_ips(root, NULL);
+             if(unlikely(header)) printf("entries,unique_ips\n");
+             printf("%zu,%s\n", root->entries, u128_to_dec(u128buf, sizeof(u128buf), unique_ips));
+         }
+@@ -381,7 +381,7 @@ int iprange6_run(int argc, char **argv, int mode, IPSET_PRINT_CMD print,
+         ips6 = ipset6_diff(root, second);
+         if(!quiet) ipset6_print(ips6, print);
+ 
+-        if(ips6->unique_ips) ret = 1;
++        if(!u128_is_zero(ips6->unique_ips)) ret = 1;
+         else ret = 0;
+     }
+     else if(mode == MODE_COMPARE) {
+@@ -400,8 +400,8 @@ int iprange6_run(int argc, char **argv, int mode, IPSET_PRINT_CMD print,
+             for(ips2 = ips6; ips2; ips2 = ips2->next) {
+                 ipset6 *comips;
+                 size_t entries1, entries2;
+-                __uint128_t unique1 = ipset6_report_unique_ips(ips6, &entries1);
+-                __uint128_t unique2 = ipset6_report_unique_ips(ips2, &entries2);
++                uint128_t unique1 = ipset6_report_unique_ips(ips6, &entries1);
++                uint128_t unique2 = ipset6_report_unique_ips(ips2, &entries2);
+ 
+                 if(ips6 == ips2) continue;
+ 
+@@ -416,7 +416,7 @@ int iprange6_run(int argc, char **argv, int mode, IPSET_PRINT_CMD print,
+                     u128_to_dec(u128buf, sizeof(u128buf), unique1));
+                 printf("%s,", u128_to_dec(u128buf, sizeof(u128buf), unique2));
+                 printf("%s,", u128_to_dec(u128buf, sizeof(u128buf), comips->unique_ips));
+-                printf("%s\n", u128_to_dec(u128buf, sizeof(u128buf), unique1 + unique2 - comips->unique_ips));
++                printf("%s\n", u128_to_dec(u128buf, sizeof(u128buf), u128_sub(u128_add(unique1, unique2), comips->unique_ips)));
+                 ipset6_free(comips);
+             }
+         }
+@@ -437,8 +437,8 @@ int iprange6_run(int argc, char **argv, int mode, IPSET_PRINT_CMD print,
+         for(ips6 = root; ips6; ips6 = ips6->next) {
+             for(ips2 = second; ips2; ips2 = ips2->next) {
+                 size_t entries1, entries2;
+-                __uint128_t unique1 = ipset6_report_unique_ips(ips6, &entries1);
+-                __uint128_t unique2 = ipset6_report_unique_ips(ips2, &entries2);
++                uint128_t unique1 = ipset6_report_unique_ips(ips6, &entries1);
++                uint128_t unique2 = ipset6_report_unique_ips(ips2, &entries2);
+ 
+                 ipset6 *combined = ipset6_combine(ips6, ips2);
+                 if(!combined) {
+@@ -451,7 +451,7 @@ int iprange6_run(int argc, char **argv, int mode, IPSET_PRINT_CMD print,
+                     u128_to_dec(u128buf, sizeof(u128buf), unique1));
+                 printf("%s,", u128_to_dec(u128buf, sizeof(u128buf), unique2));
+                 printf("%s,", u128_to_dec(u128buf, sizeof(u128buf), combined->unique_ips));
+-                printf("%s\n", u128_to_dec(u128buf, sizeof(u128buf), unique1 + unique2 - combined->unique_ips));
++                printf("%s\n", u128_to_dec(u128buf, sizeof(u128buf), u128_sub(u128_add(unique1, unique2), combined->unique_ips)));
+                 ipset6_free(combined);
+             }
+         }
+@@ -468,7 +468,7 @@ int iprange6_run(int argc, char **argv, int mode, IPSET_PRINT_CMD print,
+ 
+         for(ips6 = root; ips6; ips6 = ips6->next) {
+             size_t entries;
+-            __uint128_t unique_ips = ipset6_report_unique_ips(ips6, &entries);
++            uint128_t unique_ips = ipset6_report_unique_ips(ips6, &entries);
+ 
+             if(ips6 == first) continue;
+ 
+@@ -481,7 +481,7 @@ int iprange6_run(int argc, char **argv, int mode, IPSET_PRINT_CMD print,
+             ipset6_optimize(comips);
+             printf("%s,%zu,%s,", ips6->filename, entries,
+                 u128_to_dec(u128buf, sizeof(u128buf), unique_ips));
+-            printf("%s\n", u128_to_dec(u128buf, sizeof(u128buf), unique_ips + first->unique_ips - comips->unique_ips));
++            printf("%s\n", u128_to_dec(u128buf, sizeof(u128buf), u128_sub(u128_add(unique_ips, first->unique_ips), comips->unique_ips)));
+             ipset6_free(comips);
+         }
+     }
+diff --git a/src/ipset6.c b/src/ipset6.c
+index a34833d..79aa360 100644
+--- a/src/ipset6.c
++++ b/src/ipset6.c
+@@ -24,7 +24,7 @@ ipset6 *ipset6_create(const char *filename, size_t entries) {
+     ips->lines = 0;
+     ips->entries = 0;
+     ips->entries_max = entries;
+-    ips->unique_ips = 0;
++    ips->unique_ips = U128_ZERO;
+     ips->next = NULL;
+     ips->prev = NULL;
+     ips->flags = 0;
+@@ -87,7 +87,7 @@ void ipset6_grow_internal(ipset6 *ips, size_t free_entries_needed) {
+     }
+ }
+ 
+-inline __uint128_t ipset6_unique_ips(ipset6 *ips) {
++inline uint128_t ipset6_unique_ips(ipset6 *ips) {
+     if(unlikely(!(ips->flags & IPSET_FLAG_OPTIMIZED)))
+         ipset6_optimize(ips);
+ 
+diff --git a/src/ipset6.h b/src/ipset6.h
+index aa9c9c5..c4cd11e 100644
+--- a/src/ipset6.h
++++ b/src/ipset6.h
+@@ -9,7 +9,7 @@ typedef struct ipset6 {
+     size_t lines;
+     size_t entries;
+     size_t entries_max;
+-    __uint128_t unique_ips;
++    uint128_t unique_ips;
+ 
+     uint32_t flags;
+ 
+@@ -25,7 +25,7 @@ extern void ipset6_free_all(ipset6 *ips);
+ 
+ extern size_t prefix6_counters[129];
+ 
+-extern __uint128_t ipset6_unique_ips(ipset6 *ips);
++extern uint128_t ipset6_unique_ips(ipset6 *ips);
+ 
+ static inline int ipset6_entries_allocation_overflows(size_t entries) {
+     return (entries > (SIZE_MAX / sizeof(network_addr6_t)));
+@@ -56,26 +56,26 @@ static inline void ipset6_added_entry(ipset6 *ips) {
+ 
+     ips->lines++;
+ 
+-    /* overflow-safe unique_ips: 2^128 doesn't fit in __uint128_t, saturate at max */
+-    if(lo == 0 && hi == IPV6_ADDR_MAX)
++    /* overflow-safe unique_ips: 2^128 doesn't fit in uint128_t, saturate at max */
++    if(u128_is_zero(lo) && u128_eq(hi, IPV6_ADDR_MAX))
+         ips->unique_ips = IPV6_ADDR_MAX;
+     else {
+-        __uint128_t size = hi - lo + 1;
+-        if(ips->unique_ips > IPV6_ADDR_MAX - size)
++        uint128_t size = u128_add(u128_sub(hi, lo), U128_ONE);
++        if(u128_gt(ips->unique_ips, u128_sub(IPV6_ADDR_MAX, size)))
+             ips->unique_ips = IPV6_ADDR_MAX;
+         else
+-            ips->unique_ips += size;
++            ips->unique_ips = u128_add(ips->unique_ips, size);
+     }
+ 
+     if(likely(ips->flags & IPSET_FLAG_OPTIMIZED && entries > 0)) {
+         /* overflow-safe adjacency: broadcast + 1 wraps at IPV6_ADDR_MAX */
+-        if(unlikely(ips->netaddrs[entries - 1].broadcast != IPV6_ADDR_MAX &&
+-                    lo == (ips->netaddrs[entries - 1].broadcast + 1))) {
++        if(unlikely(!u128_eq(ips->netaddrs[entries - 1].broadcast, IPV6_ADDR_MAX) &&
++                    u128_eq(lo, u128_inc(ips->netaddrs[entries - 1].broadcast)))) {
+             ips->netaddrs[entries - 1].broadcast = hi;
+             return;
+         }
+ 
+-        if(likely(lo > ips->netaddrs[entries - 1].broadcast)) {
++        if(likely(u128_gt(lo, ips->netaddrs[entries - 1].broadcast))) {
+             ips->entries++;
+             return;
+         }
+diff --git a/src/ipset6_binary.c b/src/ipset6_binary.c
+index bc6caa9..c23a3e2 100644
+--- a/src/ipset6_binary.c
++++ b/src/ipset6_binary.c
+@@ -10,15 +10,15 @@ static void binary6_write_failed(void) {
+     exit(1);
+ }
+ 
+-static int binary6_validate_payload(ipset6 *ips, int header_optimized, size_t entries, __uint128_t expected_unique_ips, int *payload_is_optimized)
++static int binary6_validate_payload(ipset6 *ips, int header_optimized, size_t entries, uint128_t expected_unique_ips, int *payload_is_optimized)
+ {
+     size_t i;
+-    __uint128_t actual_unique_ips = 0;
++    uint128_t actual_unique_ips = U128_ZERO;
+ 
+     *payload_is_optimized = 1;
+ 
+     if(!entries) {
+-        if(unlikely(expected_unique_ips != 0)) {
++        if(unlikely(!u128_is_zero(expected_unique_ips))) {
+             fprintf(stderr, "%s: %s: unique IPs do not match the binary payload\n", PROG, ips->filename);
+             return 1;
+         }
+@@ -26,7 +26,7 @@ static int binary6_validate_payload(ipset6 *ips, int header_optimized, size_t en
+     }
+ 
+     for(i = 0; i < entries; i++) {
+-        if(unlikely(ips->netaddrs[ips->entries + i].addr > ips->netaddrs[ips->entries + i].broadcast)) {
++        if(unlikely(u128_gt(ips->netaddrs[ips->entries + i].addr, ips->netaddrs[ips->entries + i].broadcast))) {
+             fprintf(stderr, "%s: %s: invalid binary record %zu has addr > broadcast\n", PROG, ips->filename, i + 1);
+             return 1;
+         }
+@@ -36,9 +36,9 @@ static int binary6_validate_payload(ipset6 *ips, int header_optimized, size_t en
+         network_addr6_t *prev = &ips->netaddrs[ips->entries + i - 1];
+         network_addr6_t *curr = &ips->netaddrs[ips->entries + i];
+ 
+-        if(curr->addr < prev->addr
+-           || curr->addr <= prev->broadcast
+-           || (prev->broadcast != IPV6_ADDR_MAX && curr->addr == (prev->broadcast + 1))) {
++        if(u128_lt(curr->addr, prev->addr)
++           || u128_le(curr->addr, prev->broadcast)
++           || (!u128_eq(prev->broadcast, IPV6_ADDR_MAX) && u128_eq(curr->addr, u128_inc(prev->broadcast)))) {
+             *payload_is_optimized = 0;
+             break;
+         }
+@@ -46,8 +46,8 @@ static int binary6_validate_payload(ipset6 *ips, int header_optimized, size_t en
+ 
+     if(*payload_is_optimized) {
+         for(i = 0; i < entries; i++) {
+-            __uint128_t size = ips->netaddrs[ips->entries + i].broadcast - ips->netaddrs[ips->entries + i].addr + 1;
+-            actual_unique_ips += size;
++            uint128_t size = u128_add(u128_sub(ips->netaddrs[ips->entries + i].broadcast, ips->netaddrs[ips->entries + i].addr), U128_ONE);
++            actual_unique_ips = u128_add(actual_unique_ips, size);
+         }
+     }
+     else {
+@@ -57,7 +57,7 @@ static int binary6_validate_payload(ipset6 *ips, int header_optimized, size_t en
+         actual_unique_ips = expected_unique_ips;
+     }
+ 
+-    if(unlikely(expected_unique_ips != actual_unique_ips)) {
++    if(unlikely(!u128_eq(expected_unique_ips, actual_unique_ips))) {
+         fprintf(stderr, "%s: %s: unique IPs do not match the binary payload\n", PROG, ips->filename);
+         return 1;
+     }
+@@ -91,9 +91,9 @@ static int parse_binary6_size_field(ipset6 *ips, const char *field, const char *
+     return 0;
+ }
+ 
+-static int parse_binary6_u128_field(ipset6 *ips, const char *field, const char *value, __uint128_t *parsed_value)
++static int parse_binary6_u128_field(ipset6 *ips, const char *field, const char *value, uint128_t *parsed_value)
+ {
+-    __uint128_t result = 0;
++    uint128_t result = U128_ZERO;
+     const char *s = value;
+ 
+     if(!s || *s < '0' || *s > '9') {
+@@ -102,9 +102,9 @@ static int parse_binary6_u128_field(ipset6 *ips, const char *field, const char *
+     }
+ 
+     while(*s >= '0' && *s <= '9') {
+-        __uint128_t prev = result;
+-        result = result * 10 + (*s - '0');
+-        if(unlikely(result < prev)) {
++        uint128_t prev = result;
++        result = u128_add(u128_mul_u64(result, 10), u128_from_u64(*s - '0'));
++        if(unlikely(u128_lt(result, prev))) {
+             fprintf(stderr, "%s: %s: %s value overflow\n", PROG, ips->filename, field);
+             return 1;
+         }
+@@ -123,7 +123,7 @@ static int parse_binary6_u128_field(ipset6 *ips, const char *field, const char *
+ int ipset6_load_binary_v20(FILE *fp, ipset6 *ips, int first_line_missing) {
+     char buffer[MAX_LINE + 1], *s;
+     size_t entries, bytes, lines, expected_bytes, record_size;
+-    __uint128_t unique_ips;
++    uint128_t unique_ips;
+     uint32_t endian;
+     size_t loaded;
+     int header_optimized = 0;
+@@ -230,7 +230,7 @@ int ipset6_load_binary_v20(FILE *fp, ipset6 *ips, int first_line_missing) {
+         return 1;
+     }
+ 
+-    if(unique_ips < entries && unique_ips != 0) {
++    if(u128_lt(unique_ips, u128_from_u64(entries)) && !u128_is_zero(unique_ips)) {
+         fprintf(stderr, "%s: %s: unique IPs cannot be less than entries (%zu)\n", PROG, ips->filename, entries);
+         return 1;
+     }
+@@ -263,7 +263,7 @@ int ipset6_load_binary_v20(FILE *fp, ipset6 *ips, int first_line_missing) {
+ 
+     ips->entries += loaded;
+     ips->lines += lines;
+-    ips->unique_ips += unique_ips;
++    ips->unique_ips = u128_add(ips->unique_ips, unique_ips);
+     ips->flags &= ~IPSET_FLAG_OPTIMIZED;
+     if(header_optimized && payload_is_optimized) ips->flags |= IPSET_FLAG_OPTIMIZED;
+ 
+diff --git a/src/ipset6_common.c b/src/ipset6_common.c
+index f284144..d84cf1a 100644
+--- a/src/ipset6_common.c
++++ b/src/ipset6_common.c
+@@ -33,7 +33,7 @@ inline ipset6 *ipset6_common(ipset6 *ips1, ipset6 *ips2) {
+     hi2 = ips2->netaddrs[0].broadcast;
+ 
+     while(i1 < n1 && i2 < n2) {
+-        if(lo1 > hi2) {
++        if(u128_gt(lo1, hi2)) {
+             i2++;
+             if(i2 < n2) {
+                 lo2 = ips2->netaddrs[i2].addr;
+@@ -42,7 +42,7 @@ inline ipset6 *ipset6_common(ipset6 *ips1, ipset6 *ips2) {
+             continue;
+         }
+ 
+-        if(lo2 > hi1) {
++        if(u128_gt(lo2, hi1)) {
+             i1++;
+             if(i1 < n1) {
+                 lo1 = ips1->netaddrs[i1].addr;
+@@ -51,9 +51,9 @@ inline ipset6 *ipset6_common(ipset6 *ips1, ipset6 *ips2) {
+             continue;
+         }
+ 
+-        lo = (lo1 > lo2) ? lo1 : lo2;
++        lo = u128_gt(lo1, lo2) ? lo1 : lo2;
+ 
+-        if(hi1 < hi2) {
++        if(u128_lt(hi1, hi2)) {
+             hi = hi1;
+             i1++;
+             if(i1 < n1) {
+diff --git a/src/ipset6_diff.c b/src/ipset6_diff.c
+index f629ae3..7f07d9c 100644
+--- a/src/ipset6_diff.c
++++ b/src/ipset6_diff.c
+@@ -53,7 +53,7 @@ inline ipset6 *ipset6_diff(ipset6 *ips1, ipset6 *ips2) {
+     hi2 = ips2->netaddrs[0].broadcast;
+ 
+     while(i1 < n1 && i2 < n2) {
+-        if(lo1 > hi2) {
++        if(u128_gt(lo1, hi2)) {
+             ipset6_add_ip_range(ips, lo2, hi2);
+             i2++;
+             if(i2 < n2) {
+@@ -62,7 +62,7 @@ inline ipset6 *ipset6_diff(ipset6 *ips1, ipset6 *ips2) {
+             }
+             continue;
+         }
+-        if(lo2 > hi1) {
++        if(u128_gt(lo2, hi1)) {
+             ipset6_add_ip_range(ips, lo1, hi1);
+             i1++;
+             if(i1 < n1) {
+@@ -72,14 +72,14 @@ inline ipset6 *ipset6_diff(ipset6 *ips1, ipset6 *ips2) {
+             continue;
+         }
+ 
+-        if(lo1 > lo2)
+-            ipset6_add_ip_range(ips, lo2, lo1 - 1);
+-        else if(lo2 > lo1)
+-            ipset6_add_ip_range(ips, lo1, lo2 - 1);
++        if(u128_gt(lo1, lo2))
++            ipset6_add_ip_range(ips, lo2, u128_dec(lo1));
++        else if(u128_gt(lo2, lo1))
++            ipset6_add_ip_range(ips, lo1, u128_dec(lo2));
+ 
+-        if(hi1 > hi2) {
+-            if(hi2 == IPV6_ADDR_MAX) { i1++; i2++; }
+-            else { lo1 = hi2 + 1; i2++; }
++        if(u128_gt(hi1, hi2)) {
++            if(u128_eq(hi2, IPV6_ADDR_MAX)) { i1++; i2++; }
++            else { lo1 = u128_inc(hi2); i2++; }
+             if(i2 < n2) {
+                 lo2 = ips2->netaddrs[i2].addr;
+                 hi2 = ips2->netaddrs[i2].broadcast;
+@@ -90,9 +90,9 @@ inline ipset6 *ipset6_diff(ipset6 *ips1, ipset6 *ips2) {
+             }
+             continue;
+         }
+-        else if(hi2 > hi1) {
+-            if(hi1 == IPV6_ADDR_MAX) { i1++; i2++; }
+-            else { lo2 = hi1 + 1; i1++; }
++        else if(u128_gt(hi2, hi1)) {
++            if(u128_eq(hi1, IPV6_ADDR_MAX)) { i1++; i2++; }
++            else { lo2 = u128_inc(hi1); i1++; }
+             if(i1 < n1) {
+                 lo1 = ips1->netaddrs[i1].addr;
+                 hi1 = ips1->netaddrs[i1].broadcast;
+diff --git a/src/ipset6_exclude.c b/src/ipset6_exclude.c
+index c7bb969..75dbaaf 100644
+--- a/src/ipset6_exclude.c
++++ b/src/ipset6_exclude.c
+@@ -43,7 +43,7 @@ inline ipset6 *ipset6_exclude(ipset6 *ips1, ipset6 *ips2) {
+     hi2 = ips2->netaddrs[0].broadcast;
+ 
+     while(i1 < n1 && i2 < n2) {
+-        if(lo1 > hi2) {
++        if(u128_gt(lo1, hi2)) {
+             i2++;
+             if(i2 < n2) {
+                 lo2 = ips2->netaddrs[i2].addr;
+@@ -52,7 +52,7 @@ inline ipset6 *ipset6_exclude(ipset6 *ips1, ipset6 *ips2) {
+             continue;
+         }
+ 
+-        if(lo2 > hi1) {
++        if(u128_gt(lo2, hi1)) {
+             ipset6_add_ip_range(ips, lo1, hi1);
+             i1++;
+             if(i1 < n1) {
+@@ -62,12 +62,12 @@ inline ipset6 *ipset6_exclude(ipset6 *ips1, ipset6 *ips2) {
+             continue;
+         }
+ 
+-        if(lo1 < lo2) {
+-            ipset6_add_ip_range(ips, lo1, lo2 - 1);
++        if(u128_lt(lo1, lo2)) {
++            ipset6_add_ip_range(ips, lo1, u128_dec(lo2));
+             lo1 = lo2;
+         }
+ 
+-        if(hi1 == hi2) {
++        if(u128_eq(hi1, hi2)) {
+             i1++;
+             if(i1 < n1) {
+                 lo1 = ips1->netaddrs[i1].addr;
+@@ -79,7 +79,7 @@ inline ipset6 *ipset6_exclude(ipset6 *ips1, ipset6 *ips2) {
+                 hi2 = ips2->netaddrs[i2].broadcast;
+             }
+         }
+-        else if(hi1 < hi2) {
++        else if(u128_lt(hi1, hi2)) {
+             i1++;
+             if(i1 < n1) {
+                 lo1 = ips1->netaddrs[i1].addr;
+@@ -89,7 +89,7 @@ inline ipset6 *ipset6_exclude(ipset6 *ips1, ipset6 *ips2) {
+         else {
+             /* hi2 + 1 would overflow if hi2 == IPV6_ADDR_MAX, but that means
+              * ips2 covers everything from lo1..max, so nothing remains in ips1 */
+-            if(hi2 == IPV6_ADDR_MAX) {
++            if(u128_eq(hi2, IPV6_ADDR_MAX)) {
+                 i1++;
+                 if(i1 < n1) {
+                     lo1 = ips1->netaddrs[i1].addr;
+@@ -97,7 +97,7 @@ inline ipset6 *ipset6_exclude(ipset6 *ips1, ipset6 *ips2) {
+                 }
+             }
+             else {
+-                lo1 = hi2 + 1;
++                lo1 = u128_inc(hi2);
+             }
+             i2++;
+             if(i2 < n2) {
+diff --git a/src/ipset6_load.c b/src/ipset6_load.c
+index 6295ef2..b64ca9f 100644
+--- a/src/ipset6_load.c
++++ b/src/ipset6_load.c
+@@ -152,8 +152,8 @@ static network_addr6_t parse_address6(char *ipstr, int *err) {
+     else if(addr_class == 4) {
+         network_addr_t v4 = str2netaddr(ipstr, err);
+         if(*err) {
+-            netaddr.addr = 0;
+-            netaddr.broadcast = 0;
++            netaddr.addr = U128_ZERO;
++            netaddr.broadcast = U128_ZERO;
+             return netaddr;
+         }
+ 
+@@ -164,8 +164,8 @@ static network_addr6_t parse_address6(char *ipstr, int *err) {
+ 
+     if(err) (*err)++;
+     fprintf(stderr, "%s: Cannot parse address: %s\n", PROG, ipstr);
+-    netaddr.addr = 0;
+-    netaddr.broadcast = 0;
++    netaddr.addr = U128_ZERO;
++    netaddr.broadcast = U128_ZERO;
+     return netaddr;
+ }
+ 
+@@ -275,8 +275,8 @@ ipset6 *ipset6_load(const char *filename) {
+                     continue;
+                 }
+ 
+-                ipv6_addr_t lo = (net1.addr < net2.addr) ? net1.addr : net2.addr;
+-                ipv6_addr_t hi = (net1.broadcast > net2.broadcast) ? net1.broadcast : net2.broadcast;
++                ipv6_addr_t lo = u128_lt(net1.addr, net2.addr) ? net1.addr : net2.addr;
++                ipv6_addr_t hi = u128_gt(net1.broadcast, net2.broadcast) ? net1.broadcast : net2.broadcast;
+                 ipset6_add_ip_range(ips, lo, hi);
+             }
+                 break;
+diff --git a/src/ipset6_optimize.c b/src/ipset6_optimize.c
+index f11a7d4..d0c1734 100644
+--- a/src/ipset6_optimize.c
++++ b/src/ipset6_optimize.c
+@@ -6,10 +6,10 @@ static int compar_netaddr6(const void *p1, const void *p2) {
+     const network_addr6_t *na1 = (const network_addr6_t *)p1;
+     const network_addr6_t *na2 = (const network_addr6_t *)p2;
+ 
+-    if(na1->addr < na2->addr) return -1;
+-    if(na1->addr > na2->addr) return 1;
+-    if(na1->broadcast > na2->broadcast) return -1;
+-    if(na1->broadcast < na2->broadcast) return 1;
++    if(u128_lt(na1->addr, na2->addr)) return -1;
++    if(u128_gt(na1->addr, na2->addr)) return 1;
++    if(u128_gt(na1->broadcast, na2->broadcast)) return -1;
++    if(u128_lt(na1->broadcast, na2->broadcast)) return 1;
+     return 0;
+ }
+ 
+@@ -25,7 +25,7 @@ inline void ipset6_optimize(ipset6 *ips) {
+ 
+     if(unlikely(n == 0)) {
+         ips->flags |= IPSET_FLAG_OPTIMIZED;
+-        ips->unique_ips = 0;
++        ips->unique_ips = U128_ZERO;
+         return;
+     }
+ 
+@@ -39,17 +39,17 @@ inline void ipset6_optimize(ipset6 *ips) {
+ 
+     ips->netaddrs = naddrs;
+     ips->entries = 0;
+-    ips->unique_ips = 0;
++    ips->unique_ips = U128_ZERO;
+     ips->lines = 0;
+ 
+     lo = oaddrs[0].addr;
+     hi = oaddrs[0].broadcast;
+     for(i = 1; i < n; i++) {
+-        if(oaddrs[i].broadcast <= hi)
++        if(u128_le(oaddrs[i].broadcast, hi))
+             continue;
+ 
+         /* overflow-safe adjacency check: hi + 1 would overflow if hi == max */
+-        if(oaddrs[i].addr <= hi || (hi != IPV6_ADDR_MAX && oaddrs[i].addr == hi + 1)) {
++        if(u128_le(oaddrs[i].addr, hi) || (!u128_eq(hi, IPV6_ADDR_MAX) && u128_eq(oaddrs[i].addr, u128_inc(hi)))) {
+             hi = oaddrs[i].broadcast;
+             continue;
+         }
+diff --git a/src/ipset6_print.c b/src/ipset6_print.c
+index 32794b0..0dafe25 100644
+--- a/src/ipset6_print.c
++++ b/src/ipset6_print.c
+@@ -41,7 +41,7 @@ inline void print_addr6(ipv6_addr_t addr, int prefix) {
+ inline void print_addr6_range(ipv6_addr_t lo, ipv6_addr_t hi) {
+     char buf[IP6STR_MAX_LEN + 1];
+ 
+-    if(unlikely(lo > hi)) {
++    if(unlikely(u128_gt(lo, hi))) {
+         ipv6_addr_t t = hi;
+         fprintf(stderr, "%s: WARNING: invalid range reversed start=%s", PROG, ip6str_r(buf, lo));
+         fprintf(stderr, " end=%s\n", ip6str_r(buf, hi));
+@@ -49,7 +49,7 @@ inline void print_addr6_range(ipv6_addr_t lo, ipv6_addr_t hi) {
+         lo = t;
+     }
+ 
+-    if(lo == hi) {
++    if(u128_eq(lo, hi)) {
+         printf("%s%s-", print_prefix_ips, ip6str_r(buf, lo));
+         printf("%s%s\n", ip6str_r(buf, hi), print_suffix_ips);
+     }
+@@ -72,7 +72,7 @@ inline void print_addr6_single(ipv6_addr_t x) {
+ inline int split_range6(ipv6_addr_t addr, int prefix, ipv6_addr_t lo, ipv6_addr_t hi, void (*print)(ipv6_addr_t, int)) {
+     ipv6_addr_t bc, lower_half, upper_half;
+ 
+-    if(unlikely(lo > hi)) {
++    if(unlikely(u128_gt(lo, hi))) {
+         ipv6_addr_t t = hi;
+         char buf[IP6STR_MAX_LEN + 1];
+         fprintf(stderr, "%s: WARNING: invalid range reversed start=%s", PROG, ip6str_r(buf, lo));
+@@ -88,13 +88,13 @@ inline int split_range6(ipv6_addr_t addr, int prefix, ipv6_addr_t lo, ipv6_addr_
+ 
+     bc = broadcast6(addr, prefix);
+ 
+-    if(unlikely(lo < addr || hi > bc)) {
++    if(unlikely(u128_lt(lo, addr) || u128_gt(hi, bc))) {
+         char buf[IP6STR_MAX_LEN + 1];
+         fprintf(stderr, "%s: Out of range limits for IPv6 network %s/%d\n", PROG, ip6str_r(buf, addr), prefix);
+         return 0;
+     }
+ 
+-    if(lo == addr && hi == bc && prefix6_enabled[prefix]) {
++    if(u128_eq(lo, addr) && u128_eq(hi, bc) && prefix6_enabled[prefix]) {
+         print(addr, prefix);
+         return 1;
+     }
+@@ -103,9 +103,9 @@ inline int split_range6(ipv6_addr_t addr, int prefix, ipv6_addr_t lo, ipv6_addr_
+     lower_half = addr;
+     upper_half = set_bit6(addr, prefix, 1);
+ 
+-    if(hi < upper_half)
++    if(u128_lt(hi, upper_half))
+         return split_range6(lower_half, prefix, lo, hi, print);
+-    else if(lo >= upper_half)
++    else if(u128_ge(lo, upper_half))
+         return split_range6(upper_half, prefix, lo, hi, print);
+     else
+         return (
+@@ -136,7 +136,7 @@ void ipset6_print(ipset6 *ips, IPSET_PRINT_CMD print) {
+ 
+             n = ips->entries;
+             for(i = 0; i < n; i++)
+-                total += split_range6((__uint128_t)0, 0, ips->netaddrs[i].addr, ips->netaddrs[i].broadcast, print_addr6);
++                total += split_range6(U128_ZERO, 0, ips->netaddrs[i].addr, ips->netaddrs[i].broadcast, print_addr6);
+             break;
+ 
+         case PRINT_SINGLE_IPS:
+@@ -146,7 +146,7 @@ void ipset6_print(ipset6 *ips, IPSET_PRINT_CMD print) {
+                 ipv6_addr_t end = ips->netaddrs[i].broadcast;
+                 ipv6_addr_t x;
+ 
+-                if(unlikely(start > end)) {
++                if(unlikely(u128_gt(start, end))) {
+                     char buf[IP6STR_MAX_LEN + 1];
+                     fprintf(stderr, "%s: WARNING: invalid range reversed start=%s", PROG, ip6str_r(buf, start));
+                     fprintf(stderr, " end=%s\n", ip6str_r(buf, end));
+@@ -154,13 +154,13 @@ void ipset6_print(ipset6 *ips, IPSET_PRINT_CMD print) {
+                     end = start;
+                     start = x;
+                 }
+-                if(unlikely(end - start > IPV6_SINGLE_IP_CAP)) {
++                if(unlikely(u128_gt(u128_sub(end, start), u128_from_u64(IPV6_SINGLE_IP_CAP)))) {
+                     char buf[IP6STR_MAX_LEN + 1];
+                     fprintf(stderr, "%s: too big range eliminated start=%s", PROG, ip6str_r(buf, start));
+                     fprintf(stderr, " end=%s\n", ip6str_r(buf, end));
+                     continue;
+                 }
+-                for(x = start; x >= start && x <= end; x++) {
++                for(x = start; u128_ge(x, start) && u128_le(x, end); x = u128_inc(x)) {
+                     print_addr6_single(x);
+                     total++;
+                 }
+diff --git a/src/uint128.h b/src/uint128.h
+new file mode 100644
+index 0000000..0da5873
+--- /dev/null
++++ b/src/uint128.h
+@@ -0,0 +1,230 @@
++#ifndef IPRANGE_UINT128_H
++#define IPRANGE_UINT128_H
++
++#include <stdint.h>
++
++/* Define IPRANGE_FORCE_PORTABLE_U128 to compile the portable (struct-based)
++ * 128-bit path even on platforms that have native __uint128_t. This lets the
++ * 32-bit code path be exercised by the test suite on a 64-bit host. */
++#if defined(__SIZEOF_INT128__) && !defined(IPRANGE_FORCE_PORTABLE_U128)
++
++/* ================================================================
++ * Native 128-bit path (64-bit platforms with compiler support).
++ * Every function compiles to the native operator — zero overhead.
++ * ================================================================ */
++
++typedef __uint128_t uint128_t;
++
++#define U128_ZERO ((uint128_t)0)
++#define U128_ONE  ((uint128_t)1)
++#define U128_MAX  ((uint128_t)((__uint128_t)(-1)))
++
++static inline uint128_t u128_from_u64(uint64_t v)  { return (uint128_t)v; }
++static inline uint128_t u128_from_u32(uint32_t v)  { return (uint128_t)v; }
++
++static inline uint64_t u128_hi64(uint128_t a) { return (uint64_t)(a >> 64); }
++static inline uint64_t u128_lo64(uint128_t a) { return (uint64_t)a; }
++
++static inline int u128_is_zero(uint128_t a)         { return a == 0; }
++static inline int u128_eq(uint128_t a, uint128_t b)  { return a == b; }
++static inline int u128_lt(uint128_t a, uint128_t b)  { return a < b; }
++static inline int u128_gt(uint128_t a, uint128_t b)  { return a > b; }
++static inline int u128_le(uint128_t a, uint128_t b)  { return a <= b; }
++static inline int u128_ge(uint128_t a, uint128_t b)  { return a >= b; }
++
++static inline uint128_t u128_add(uint128_t a, uint128_t b) { return a + b; }
++static inline uint128_t u128_sub(uint128_t a, uint128_t b) { return a - b; }
++static inline uint128_t u128_inc(uint128_t a) { return a + 1; }
++static inline uint128_t u128_dec(uint128_t a) { return a - 1; }
++
++static inline uint128_t u128_and(uint128_t a, uint128_t b) { return a & b; }
++static inline uint128_t u128_or(uint128_t a, uint128_t b)  { return a | b; }
++static inline uint128_t u128_not(uint128_t a)               { return ~a; }
++static inline uint128_t u128_shl(uint128_t a, int n)        { return a << n; }
++static inline uint128_t u128_shr(uint128_t a, int n)        { return a >> n; }
++
++static inline uint128_t u128_mul_u64(uint128_t a, uint64_t b) { return a * b; }
++static inline uint128_t u128_div10(uint128_t a) { return a / 10; }
++static inline int       u128_mod10(uint128_t a) { return (int)(a % 10); }
++
++#else /* !__SIZEOF_INT128__ */
++
++/* ================================================================
++ * Portable 128-bit path (32-bit platforms without __uint128_t).
++ * Uses a struct of two uint64_t with explicit arithmetic.
++ * ================================================================ */
++
++/* Field order matches the byte layout of a native __uint128_t on the same
++ * endianness, so that an array of these structs is binary-compatible with one
++ * of native __uint128_t. This lets binary ipset files written by a 64-bit
++ * (native) build load correctly on a 32-bit (portable) build of the same
++ * endianness, and vice versa. All code refers to the fields by name, so the
++ * order is irrelevant to arithmetic; only the in-memory layout changes. */
++#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++typedef struct { uint64_t hi; uint64_t lo; } uint128_t;
++#else
++typedef struct { uint64_t lo; uint64_t hi; } uint128_t;
++#endif
++
++#define U128_ZERO ((uint128_t){ .hi = 0, .lo = 0 })
++#define U128_ONE  ((uint128_t){ .hi = 0, .lo = 1 })
++#define U128_MAX  ((uint128_t){ .hi = UINT64_MAX, .lo = UINT64_MAX })
++
++static inline uint128_t u128_from_u64(uint64_t v) {
++    uint128_t r = { .hi = 0, .lo = v };
++    return r;
++}
++
*** 153 LINES SKIPPED ***


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a202248.256d0.5f955116>