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.
This commit is contained in:
Willy Tarreau 2015-07-21 23:47:18 +02:00
parent 763a5d85f7
commit 5b4dd683cb
1 changed files with 29 additions and 0 deletions

View File

@ -30,6 +30,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h>
#include <common/chunk.h> #include <common/chunk.h>
#include <common/config.h> #include <common/config.h>
#include <eb32tree.h> #include <eb32tree.h>
@ -992,6 +993,34 @@ static inline unsigned char utf8_return_length(unsigned char code)
return code & 0x0f; return code & 0x0f;
} }
/* Turns 64-bit value <a> 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 <a> 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 /* returns a 64-bit a timestamp with the finest resolution available. The
* unit is intentionally not specified. It's mostly used to compare dates. * unit is intentionally not specified. It's mostly used to compare dates.
*/ */