From 5b4dd683cbeb04729193f1409ac0d86947f1d165 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 21 Jul 2015 23:47:18 +0200 Subject: [PATCH] MINOR: standard: provide htonll() and ntohll() These are the 64-bit equivalent of htonl() and ntohl(). They're a bit tricky in order to avoid expensive operations. The principle consists in letting the compiler detect we're playing with a union and simplify most or all operations. The asm-optimized htonl() version involving bswap (x86) / rev (arm) / other is a single operation on little endian, or a NOP on big-endian. In both cases, this lets the compiler "see" that we're rebuilding a 64-bit word from two 32-bit quantities that fit into a 32-bit register. In big endian, the whole code is optimized out. In little endian, with a decent compiler, a few bswap and 2 shifts are left, which is the minimum acceptable. --- include/common/standard.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/common/standard.h b/include/common/standard.h index 085ec791d7..fc044fb6ae 100644 --- a/include/common/standard.h +++ b/include/common/standard.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -992,6 +993,34 @@ static inline unsigned char utf8_return_length(unsigned char code) return code & 0x0f; } +/* Turns 64-bit value from host byte order to network byte order. + * The principle consists in letting the compiler detect we're playing + * with a union and simplify most or all operations. The asm-optimized + * htonl() version involving bswap (x86) / rev (arm) / other is a single + * operation on little endian, or a NOP on big-endian. In both cases, + * this lets the compiler "see" that we're rebuilding a 64-bit word from + * two 32-bit quantities that fit into a 32-bit register. In big endian, + * the whole code is optimized out. In little endian, with a decent compiler, + * a few bswap and 2 shifts are left, which is the minimum acceptable. + */ +static inline unsigned long long htonll(unsigned long long a) +{ + union { + struct { + unsigned int w1; + unsigned int w2; + } by32; + unsigned long long by64; + } w = { .by64 = a }; + return ((unsigned long long)htonl(w.by32.w1) << 32) | htonl(w.by32.w2); +} + +/* Turns 64-bit value from network byte order to host byte order. */ +static inline unsigned long long ntohll(unsigned long long a) +{ + return htonll(a); +} + /* returns a 64-bit a timestamp with the finest resolution available. The * unit is intentionally not specified. It's mostly used to compare dates. */