added `bswap()` generic macro

the macro uses GCC builtins to guarantee generation of `bswap*` instructions.

Integer types are supported from u/i16 to u/i128

Fix bug in VERSION macro expansion with internal `#undef`"d macros.

Fortune for naka's current commit: Half blessing − 半吉
generic-project-skeleton
Avril 3 years ago
parent 53355bb836
commit d9ccfa0d89
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -71,22 +71,7 @@ _mixin void _drain_val(void* x, ...) { IGNORE(x); }
// Function macros
#define TRACEx(X, msg, ...) (fprintf(stderr, "[" X "] " __FILE__ ":%d->%s(): " msg "\n", __LINE__, __func__, ## __VA_ARGS__))
#ifdef DEBUG
#define TRACE(msg, ...) TRACEx("trace", msg, ## __VA_ARGS__)
#elif defined(_EVAL_DEBUG_ONLY_STMTS)
#define TRACE(msg, ...) _drain(msg, ## __VA_ARGS__)
#else
#define TRACE(msg, ...) _no_op
#endif
#define INFO(msg, ...) TRACEx("info", msg, ## __VA_ARGS__)
#define WARN(msg, ...) TRACEx("warning", msg, ## __VA_ARGS__)
#define ERROR(msg, ...) TRACEx("error", msg, ## __VA_ARGS__)
#define FATAL(msg, ...) (TRACEx("FATAL", msg, ## __VA_ARGS__), abort())
// Assertion macros
// Assertions
#ifdef DEBUG
#define debug_assert(x) assert((x))
@ -108,9 +93,52 @@ _mixin void _drain_val(void* x, ...) { IGNORE(x); }
#define debug_static_assert(x, msg) _Static_assert(1, msg)
#endif
#define static_assert_eq(x,y,msg) _Static_assert((x) == (y), msg)
#define static_assert_ne(x,y,msg) _Static_assert((x) != (y), msg)
// Bitmasking
#define _BSWAP(x) __builtin_bswa x
#define BSWAP_16(x) _BSWAP(p16) (AS((x), uint16_t))
#define BSWAP_32(x) _BSWAP(p32) (AS((x), uint32_t))
#define BSWAP_64(x) _BSWAP(p64) (AS((x), uint64_t))
#define BSWAP_128(x) _BSWAP(p128)(AS((x), uint128_t))
#undef _BSWAP
#define _BSWAP(n) __builtin_bswap ## n
#define bswap(x) _Generic((x), \
uint64_t: _BSWAP(64), int64_t: _BSWAP(64), \
uint32_t: _BSWAP(32), int32_t: _BSWAP(32), \
uint16_t: _BSWAP(16), int16_t: _BSWAP(16), \
__uint128_t: _BSWAP(128), __int128_t: _BSWAP(128)) \
((x))
static_assert_eq(bswap(128lu), 9223372036854775808lu, "bswap128 (lu) failed (1)");
static_assert_eq(128lu, bswap(9223372036854775808lu), "bswap128 (lu) failed (2)");
static_assert_eq(bswap(bswap(128lu)), 128, "bswap128 (lu) failed (3)");
// Trace message output
#define TRACEx(X, msg, ...) (fprintf(stderr, "[" X "] " __FILE__ ":%d->%s(): " msg "\n", __LINE__, __func__, ## __VA_ARGS__))
#ifdef DEBUG
#define TRACE(msg, ...) TRACEx("trace", msg, ## __VA_ARGS__)
#elif defined(_EVAL_DEBUG_ONLY_STMTS)
#define TRACE(msg, ...) _drain(msg, ## __VA_ARGS__)
#else
#define TRACE(msg, ...) _no_op
#endif
#define INFO(msg, ...) TRACEx("info", msg, ## __VA_ARGS__)
#define WARN(msg, ...) TRACEx("warning", msg, ## __VA_ARGS__)
#define ERROR(msg, ...) TRACEx("error", msg, ## __VA_ARGS__)
#define FATAL(msg, ...) (TRACEx("FATAL", msg, ## __VA_ARGS__), abort())
// Version macros
#define _UI(x) ((uint32_t)(x))
#define _AS_u32(x) ((uint32_t)(x))
#define VER_COMP_MAJ 24u
#define VER_COMP_MIN 16u
@ -118,19 +146,18 @@ _mixin void _drain_val(void* x, ...) { IGNORE(x); }
#define VER_COMP_REV 0u
/// Create a `uint32_t` from these version componants
#define VERSION(maj,min,bf,rev) _UI( _UI(maj) << 24u | _UI(min) << 16u | _UI(bf) << 8u | _UI(rev) )
#define VERSION(maj,min,bf,rev) _AS_u32( _AS_u32(maj) << 24u | _AS_u32(min) << 16u | _AS_u32(bf) << 8u | _AS_u32(rev) )
/// Mask `ver` to retain only the version component specified by `mask`
///
/// # Example
/// `_Static_assert( (VERSION_COMP(VERSION(1,2,3,4), VER_COMP_MIN) >> VER_COMP_MIN) == 2u)`
#define VERSION_COMP(ver, mask) _UI( _UI(ver) & (0xffu << _UI(mask)) /*>> _UI(mask)*/ )
#define VERSION_COMP(ver, mask) _AS_u32( _AS_u32(ver) & (0xffu << _AS_u32(mask)) /*>> _AS_u32(mask)*/ )
#define VERSION_MAJ(ver) _UI(VERSION_COMP((ver), 24u) >> 24u)
#define VERSINO_MIN(ver) _UI(VERSION_COMP((ver), 16u) >> 16u)
#define VERSINO_BF(ver) _UI(VERSION_COMP((ver), 8u) >> 8u)
#define VERSINO_REV(ver) _UI(_UI(ver) & 0xffu)
#define VERSION_MAJ(ver) _AS_u32(VERSION_COMP((ver), 24u) >> 24u)
#define VERSINO_MIN(ver) _AS_u32(VERSION_COMP((ver), 16u) >> 16u)
#define VERSINO_BF(ver) _AS_u32(VERSION_COMP((ver), 8u) >> 8u)
#define VERSINO_REV(ver) _AS_u32(_AS_u32(ver) & 0xffu)
_Static_assert( (VERSION_COMP(VERSION(1,2,3,4), VER_COMP_MIN) >> VER_COMP_MIN) == 2u, "invalid native version spec");
#undef _UI
#endif /* _MACROS_H */

@ -12,7 +12,12 @@ int main(int argc, char** argv)
IGNORE(argc);
IGNORE(argv);
INFO("Hello world!");
u64 i = 128;
u32 vers = VERSION(1,2,3,4);
INFO("Hello world %lu %lu %lu!", i, bswap(i), bswap(bswap(i)));
//INFO("Version: 0x%x (0x%x)", vers, bswap(vers)); // Check which version endian was preferrable, we'll stick with the default system endian (little, for this one.)
return 0;
}

Loading…
Cancel
Save