X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/6a0129ea8c11c4fd12a6198dac1a3c4ab8af4ecc..6f444bda1b7deb31cf7fb2395cb0993c3e3b8c42:/bits.h?ds=sidebyside diff --git a/bits.h b/bits.h index 34f5f1f..4f8b582 100644 --- a/bits.h +++ b/bits.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: bits.h,v 1.5 2000/06/17 10:36:06 mdw Exp $ + * $Id: bits.h,v 1.9 2001/01/20 12:05:20 mdw Exp $ * * Portable bit-level manipulation macros * @@ -30,6 +30,18 @@ /*----- Revision history --------------------------------------------------* * * $Log: bits.h,v $ + * Revision 1.9 2001/01/20 12:05:20 mdw + * New hack for storing 64-bit numbers in tables. + * + * Revision 1.8 2000/10/08 11:06:30 mdw + * Shut later versions of GCC up about use of @long long@. + * + * Revision 1.7 2000/07/22 09:48:26 mdw + * Added macros for reading 64-bit values. + * + * Revision 1.6 2000/07/16 12:28:28 mdw + * Add 64-bit support, with faked arithmetic on 32-bit hosts. + * * Revision 1.5 2000/06/17 10:36:06 mdw * Support for 24-bit types. * @@ -58,9 +70,20 @@ #include #include +#if __STDC_VERSION__ >= 199900l +# include +#endif /*----- Decide on some types ----------------------------------------------*/ +/* --- Make GNU C shut up --- */ + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91) +# define MLIB_BITS_EXTENSION __extension__ +#else +# define MLIB_BITS_EXTENSION +#endif + /* --- Decide on a 32-bit type --- * * * I want a type which is capable of expressing 32-bit numbers. Because some @@ -75,6 +98,38 @@ typedef unsigned long uint32; #endif +/* --- Decide on a 64-bit type --- * + * + * The test is quite subtle. Think about it. Note that (at least on my + * machine), the 32-bit macros are *much* faster than GCC's @long long@ + * support. + */ + +#if defined(ULONG_LONG_MAX) && !defined(ULLONG_MAX) +# define ULLONG_MAX ULONG_LONG_MAX +#endif + +#if UINT_MAX >> 31 > 0xffffffff +# define HAVE_UINT64 + typedef unsigned int uint64; +#elif ULONG_MAX >> 31 > 0xffffffff +# define HAVE_UINT64 + typedef unsigned long uint64; +#elif defined(ULLONG_MAX) +# define HAVE_UINT64 + MLIB_BITS_EXTENSION typedef unsigned long long uint64; +#endif + +#ifdef DEBUG64 +# undef HAVE_UINT64 +#endif + +#ifdef HAVE_UINT64 + typedef struct { uint64 i; } kludge64; +#else + typedef struct { uint32 hi, lo; } kludge64; +#endif + /* --- Decide on a 24-bit type --- */ #if UINT_MAX >= 0x00ffffffu @@ -106,6 +161,10 @@ typedef unsigned char octet; #define MASK24 0xffffffu #define MASK32 0xffffffffu +#ifdef HAVE_UINT64 +# define MASK64 MLIB_BITS_EXTENSION 0xffffffffffffffffu +#endif + /* --- Type coercions --- */ #define U8(x) ((octet)((x) & MASK8)) @@ -113,6 +172,13 @@ typedef unsigned char octet; #define U24(x) ((uint24)((x) & MASK24)) #define U32(x) ((uint32)((x) & MASK32)) +#ifdef HAVE_UINT64 +# define U64(x) ((uint64)(x) & MASK64) +# define U64_(d, x) ((d).i = U64(x).i) +#else +# define U64_(d, x) ((d).hi = U32((x).hi), (d).lo = U32((x).lo)) +#endif + /* --- Safe shifting macros --- */ #define LSL8(v, s) U8(U8(v) << ((s) & 7u)) @@ -124,6 +190,44 @@ typedef unsigned char octet; #define LSL32(v, s) U32(U32(v) << ((s) & 31u)) #define LSR32(v, s) U32(U32(v) >> ((s) & 31u)) +#ifdef HAVE_UINT64 +# define LSL64(v, s) U64(U64(v) << ((s) & 63u)) +# define LSR64(v, s) U64(U64(v) >> ((s) & 63u)) +# define LSL64_(d, v, s) ((d).i = LSL64((v).i, (s))) +# define LSR64_(d, v, s) ((d).i = LSR64((v).i, (s))) +#else +# define LSL64_(d, v, s) do { \ + unsigned _s = (s) & 63u; \ + uint32 _l = (v).lo, _h = (v).hi; \ + kludge64 *_d = &(d); \ + if (_s >= 32) { \ + _d->hi = LSL32(_l, _s - 32u); \ + _d->lo = 0; \ + } else if (!_s) { \ + _d->lo = _l; \ + _d->hi = _h; \ + } else { \ + _d->hi = LSL32(_h, _s) | LSR32(_l, 32u - _s); \ + _d->lo = LSL32(_l, _s); \ + } \ + } while (0) +# define LSR64_(d, v, s) do { \ + unsigned _s = (s) & 63u; \ + uint32 _l = (v).lo, _h = (v).hi; \ + kludge64 *_d = &(d); \ + if (_s >= 32) { \ + _d->lo = LSR32(_h, _s - 32u); \ + _d->hi = 0; \ + } else if (!_s) { \ + _d->lo = _l; \ + _d->hi = _h; \ + } else { \ + _d->lo = LSR32(_l, _s) | LSL32(_h, 32u - _s); \ + _d->hi = LSR32(_h, _s); \ + } \ + } while (0) +#endif + /* --- Rotation macros --- */ #define ROL8(v, s) (LSL8((v), (s)) | (LSR8((v), 8u - (s)))) @@ -135,6 +239,44 @@ typedef unsigned char octet; #define ROL32(v, s) (LSL32((v), (s)) | (LSR32((v), 32u - (s)))) #define ROR32(v, s) (LSR32((v), (s)) | (LSL32((v), 32u - (s)))) +#ifdef HAVE_UINT64 +# define ROL64(v, s) (LSL64((v), (s)) | (LSR64((v), 64u - (s)))) +# define ROR64(v, s) (LSR64((v), (s)) | (LSL64((v), 64u - (s)))) +# define ROL64_(d, v, s) ((d).i = ROL64((v).i, (s))) +# define ROR64_(d, v, s) ((d).i = ROR64((v).i, (s))) +#else +# define ROL64_(d, v, s) do { \ + unsigned _s = (s) & 63u; \ + uint32 _l = (v).lo, _h = (v).hi; \ + kludge64 *_d = &(d); \ + if (_s >= 32) { \ + _d->hi = LSL32(_l, _s - 32u) | LSR32(_h, 64u - _s); \ + _d->lo = LSL32(_h, _s - 32u) | LSR32(_l, 64u - _s); \ + } else if (!_s) { \ + _d->lo = _l; \ + _d->hi = _h; \ + } else { \ + _d->hi = LSL32(_h, _s) | LSR32(_l, 32u - _s); \ + _d->lo = LSL32(_l, _s) | LSR32(_h, 32u - _s); \ + } \ + } while (0) +# define ROR64_(d, v, s) do { \ + unsigned _s = (s) & 63u; \ + uint32 _l = (v).lo, _h = (v).hi; \ + kludge64 *_d = &(d); \ + if (_s >= 32) { \ + _d->hi = LSR32(_l, _s - 32u) | LSL32(_h, 64u - _s); \ + _d->lo = LSR32(_h, _s - 32u) | LSL32(_l, 64u - _s); \ + } else if (!_s) { \ + _d->lo = _l; \ + _d->hi = _h; \ + } else { \ + _d->hi = LSR32(_h, _s) | LSL32(_l, 32u - _s); \ + _d->lo = LSR32(_l, _s) | LSL32(_h, 32u - _s); \ + } \ + } while (0) +#endif + /* --- Storage and retrieval --- */ #define GETBYTE(p, o) (((octet *)(p))[o] & MASK8) @@ -203,6 +345,128 @@ typedef unsigned char octet; PUTBYTE((p), 3, (uint32)(v) >> 24)) #define STORE32(p, v) STORE32_B((p), (v)) +#ifdef HAVE_UINT64 + +# define LOAD64_B(p) \ + (((uint64)GETBYTE((p), 0) << 56) | \ + ((uint64)GETBYTE((p), 1) << 48) | \ + ((uint64)GETBYTE((p), 2) << 40) | \ + ((uint64)GETBYTE((p), 3) << 32) | \ + ((uint64)GETBYTE((p), 4) << 24) | \ + ((uint64)GETBYTE((p), 5) << 16) | \ + ((uint64)GETBYTE((p), 6) << 8) | \ + ((uint64)GETBYTE((p), 7) << 0)) +# define LOAD64_L(p) \ + (((uint64)GETBYTE((p), 0) << 0) | \ + ((uint64)GETBYTE((p), 1) << 8) | \ + ((uint64)GETBYTE((p), 2) << 16) | \ + ((uint64)GETBYTE((p), 3) << 24) | \ + ((uint64)GETBYTE((p), 4) << 32) | \ + ((uint64)GETBYTE((p), 5) << 40) | \ + ((uint64)GETBYTE((p), 6) << 48) | \ + ((uint64)GETBYTE((p), 7) << 56)) +# define LOAD64(p) LOAD64_B((p)) +# define LOAD64_B_(d, p) ((d).i = LOAD64_B((p))) +# define LOAD64_L_(d, p) ((d).i = LOAD64_L((p))) +# define LOAD64_(d, p) LOAD64_B_((d), (p)) + +# define STORE64_B(p, v) \ + (PUTBYTE((p), 0, (uint64)(v) >> 56), \ + PUTBYTE((p), 1, (uint64)(v) >> 48), \ + PUTBYTE((p), 2, (uint64)(v) >> 40), \ + PUTBYTE((p), 3, (uint64)(v) >> 32), \ + PUTBYTE((p), 4, (uint64)(v) >> 24), \ + PUTBYTE((p), 5, (uint64)(v) >> 16), \ + PUTBYTE((p), 6, (uint64)(v) >> 8), \ + PUTBYTE((p), 7, (uint64)(v) >> 0)) +# define STORE64_L(p, v) \ + (PUTBYTE((p), 0, (uint64)(v) >> 0), \ + PUTBYTE((p), 1, (uint64)(v) >> 8), \ + PUTBYTE((p), 2, (uint64)(v) >> 16), \ + PUTBYTE((p), 3, (uint64)(v) >> 24), \ + PUTBYTE((p), 4, (uint64)(v) >> 32), \ + PUTBYTE((p), 5, (uint64)(v) >> 40), \ + PUTBYTE((p), 6, (uint64)(v) >> 48), \ + PUTBYTE((p), 7, (uint64)(v) >> 56)) +# define STORE64(p, v) STORE64_B((p), (v)) +# define STORE64_B_(p, v) STORE64_B((p), (v).i) +# define STORE64_L_(p, v) STORE64_L((p), (v).i) +# define STORE64_(p, v) STORE64_B_((p), (v)) + +#else + +# define LOAD64_B_(d, p) \ + ((d).hi = LOAD32_B((octet *)(p) + 0), \ + (d).lo = LOAD32_B((octet *)(p) + 4)) +# define LOAD64_L_(d, p) \ + ((d).lo = LOAD32_L((octet *)(p) + 0), \ + (d).hi = LOAD32_L((octet *)(p) + 4)) +# define LOAD64_(d, p) LOAD64_B_((d), (p)) + +# define STORE64_B_(p, v) \ + (STORE32_B((octet *)(p) + 0, (v).hi), \ + STORE32_B((octet *)(p) + 4, (v).lo)) +# define STORE64_L_(p, v) \ + (STORE32_L((octet *)(p) + 0, (v).lo), \ + STORE32_L((octet *)(p) + 4, (v).hi)) +# define STORE64_(p, v) STORE64_B_((p), (v)) + +#endif + +/* --- Other operations on 64-bit integers --- */ + +#ifdef HAVE_UINT64 +# define SET64(d, h, l) ((d).i = (U64((h)) << 32) | U64((l))) +# define ASSIGN64(d, x) ((d).i = U64((x))) +# define HI64(x) U32((x).i >> 32) +# define LO64(x) U32((x).i) +# define GET64(t, x) ((t)(x).i) +#else +# define SET64(d, h, l) ((d).hi = U32(h), (d).lo = U32(l)) +# define ASSIGN64(d, x) \ + ((d).hi = ((x & ~MASK32) >> 16) >> 16, (d).lo = U32(x)) +# define HI64(x) U32((x).hi) +# define LO64(x) U32((x).lo) +# define GET64(t, x) (((((t)HI64(x) << 16) << 16) & ~MASK32) | (t)LO64(x)) +#endif + +#ifdef HAVE_UINT64 +# define AND64(d, x, y) ((d).i = (x).i & (y).i) +# define OR64(d, x, y) ((d).i = (x).i | (y).i) +# define XOR64(d, x, y) ((d).i = (x).i ^ (y).i) +# define CPL64(d, x) ((d).i = ~(x).i) +# define ADD64(d, x, y) ((d).i = (x).i + (y).i) +# define SUB64(d, x, y) ((d).i = (x).i - (y).i) +# define CMP64(x, op, y) ((x).i op (y).i) +# define ZERO64(x) ((x) == 0) +#else +# define AND64(d, x, y) ((d).lo = (x).lo & (y).lo, (d).hi = (x).hi & (y).hi) +# define OR64(d, x, y) ((d).lo = (x).lo | (y).lo, (d).hi = (x).hi | (y).hi) +# define XOR64(d, x, y) ((d).lo = (x).lo ^ (y).lo, (d).hi = (x).hi ^ (y).hi) +# define CPL64(d, x) ((d).lo = ~(x).lo, (d).hi = ~(x).hi) +# define ADD64(d, x, y) do { \ + uint32 _x = U32((x).lo + (y).lo); \ + (d).hi = (x).hi + (y).hi + (_x < (x).lo); \ + (d).lo = _x; \ + } while (0) +# define SUB64(d, x, y) do { \ + uint32 _x = U32((x).lo - (y).lo); \ + (d).hi = (x).hi - (y).hi - (_x > (x).lo); \ + (d).lo = _x; \ + } while (0) +# define CMP64(x, op, y) \ + ((x).hi == (y).hi ? (x).lo op (y).lo : (x).hi op (y).hi) +# define ZERO64(x) ((x).lo == 0 && (x).hi == 0) +#endif + +/* --- Storing integers in tables --- */ + +#ifdef HAVE_UINT64 +# define X64(x, y) { 0x##x##y } +#else +# define X64(x, y) { 0x##x, 0x##y } +#endif + /*----- That's all, folks -------------------------------------------------*/ #ifdef __cplusplus