summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-05-22 09:05:15 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-05-22 09:05:15 -0700
commit16eb3d22a29911981371b98e83008f8741903cc8 (patch)
tree4f80b90d1026ec44fb06d1359b368589040a69b4
parent663b75b357e77bfc47e31830b4e49cf1b026b141 (diff)
downloadtxr-16eb3d22a29911981371b98e83008f8741903cc8.tar.gz
txr-16eb3d22a29911981371b98e83008f8741903cc8.tar.bz2
txr-16eb3d22a29911981371b98e83008f8741903cc8.zip
ffi: allow bitfields based on endian types.
This is very nice: you can now declaratively match a structure that uses bitfields, and comes from a different endian system. * ffi.c (ffi_kind_t): Replace FFI_KIND_NUM type with FFI_KIND_INT, FFI_KIND_UINT and FFI_KIND_FLO. Now using the tft->kind value, we can distinguish integer and floating types, and determine signedness. (struct txr_ffi_type): New flag, bigendian, which is set to 1 for all big types that are big endian. This is not just the endian types like be-int32, but natural types like int, if the underlying platform is big endian. (swap_get32, swap_put32, swap_get64, swap_put64): New static functions. (ffi_generic_swap_fat_ubit_put, ffi_generic_swap_fat_sbit_put, ffi_generic_swap_fat_ubit_get, ffi_generic_swap_fat_sbit_get, ffi_generic_swap_ubit_put, ffi_generic_swap_sbit_put, ffi_generic_swap_ubit_get, ffi_generic_swap_sbit_get): New static functions. (ffi_make_type_builtin): On big endian, set the bigendian flag on every type. For the endian types, this will get adjusted as an additional construction step. (make_ffi_type_endian): New static function. Calls ffi_make_type_builtin, and then initializes the bigendian flag with the given value. (make_ffi_type_struct, make_ffi_type_union): Because bitfields can have endiannness now, we can no longer refer to the machine's own endianness in laying them out; we have to look at the mtft->bigendian value. Furthermore, we need an additional rule: when a bitfield member follows a member that has different endian, a new allocation unit has to begin. (ffi_type_compile): the sbit and ubit types must set the type to FFI_KIND_INT and FFI_KIND_UINT now. For the big operator, we can simplify the error checking: instead of exhaustively comparing the type to all the supported integer types, we just now check whether it is FFI_KIND_INT or FFI_KIND_UINT. Here, if we detect that an endian bitfield has opposite byte order from the machine, then we instantiate the bitfield with the ffi_generic_swap_* virtual functions. These perform the required byte swapping accesses to the bitfield storage cells, so then the bit field manipulation code just works using the local integer representation (shifting and masking). Of course, the shift amount depends on the endian; and that is calculated at type creation time in make_ffi_type_struct. (ffi_init_types): Replace FFI_KIND_NUM with the appropriate constant for each affected type. In some cases, we have to calculate whether to use the INT or UINT one, for the types whose signedness is not specified. We switch all the endian types to new constructor make_ffi_type_endian, passing the required value of the bigendian flag. * txr.1: Documented.
-rw-r--r--ffi.c710
-rw-r--r--txr.198
2 files changed, 598 insertions, 210 deletions
diff --git a/ffi.c b/ffi.c
index a2bad2b3..ca4c123d 100644
--- a/ffi.c
+++ b/ffi.c
@@ -99,8 +99,10 @@ typedef unsigned long ffi_arg;
typedef enum {
FFI_KIND_VOID,
- FFI_KIND_NUM,
+ FFI_KIND_INT,
+ FFI_KIND_UINT,
FFI_KIND_ENUM,
+ FFI_KIND_FLO,
FFI_KIND_PTR,
FFI_KIND_STRUCT,
FFI_KIND_UNION,
@@ -218,6 +220,7 @@ struct txr_ffi_type {
unsigned incomplete : 1;
unsigned flexible : 1;
unsigned bitfield : 1;
+ unsigned bigendian : 1;
struct txr_ffi_type *(*clone)(struct txr_ffi_type *);
#if HAVE_LIBFFI
void (*calcft)(struct txr_ffi_type *);
@@ -1621,6 +1624,278 @@ static val ffi_generic_fat_ubit_get(struct txr_ffi_type *tft,
#endif
+#if HAVE_LITTLE_ENDIAN
+
+static u32_t swap_get32(const mem_t *src, cnum size)
+{
+ u32_t val = 0;
+
+ if (size-- > 0)
+ val = convert(u32_t, src[0]) << 24;
+ if (size-- > 0)
+ val |= convert(u32_t, src[1]) << 16;
+ if (size-- > 0)
+ val |= convert(u32_t, src[2]) << 8;
+ if (size > 0)
+ val |= src[3];
+
+ return val;
+}
+
+static void swap_put32(mem_t *dst, u32_t val, cnum size)
+{
+ if (size-- > 0)
+ dst[0] = val >> 24;
+ if (size-- > 0)
+ dst[1] = val >> 16;
+ if (size-- > 0)
+ dst[2] = val >> 8;
+ if (size-- > 0)
+ dst[3] = val;
+}
+
+#if HAVE_I64
+
+static u64_t swap_get64(const mem_t *src, cnum size)
+{
+ u64_t val = 0;
+
+ if (size-- > 0)
+ val = convert(u64_t, src[0]) << 56;
+ if (size-- > 0)
+ val |= convert(u64_t, src[1]) << 48;
+ if (size-- > 0)
+ val |= convert(u64_t, src[2]) << 40;
+ if (size-- > 0)
+ val |= convert(u64_t, src[3]) << 32;
+ if (size-- > 0)
+ val |= convert(u64_t, src[4]) << 24;
+ if (size-- > 0)
+ val |= convert(u64_t, src[5]) << 16;
+ if (size-- > 0)
+ val |= convert(u64_t, src[6]) << 8;
+ if (size > 0)
+ val |= src[7];
+
+ return val;
+}
+
+static void swap_put64(mem_t *dst, u64_t val, cnum size)
+{
+ if (size-- > 0)
+ dst[0] = val >> 56;
+ if (size-- > 0)
+ dst[1] = val >> 48;
+ if (size-- > 0)
+ dst[2] = val >> 40;
+ if (size-- > 0)
+ dst[3] = val >> 32;
+ if (size-- > 0)
+ dst[4] = val >> 24;
+ if (size-- > 0)
+ dst[5] = val >> 16;
+ if (size-- > 0)
+ dst[6] = val >> 8;
+ if (size > 0)
+ dst[7] = val;
+}
+
+#endif
+
+#else
+
+static u32_t swap_get32(const mem_t *src, cnum size)
+{
+ u32_t val = 0;
+
+ switch (size) {
+ case 4:
+ val = *src++;
+ val <<= 8;
+ /* fallthrough */
+ case 3:
+ val |= *src++;
+ val <<= 8;
+ /* fallthrough */
+ case 2:
+ val |= *src++;
+ val <<= 8;
+ /* fallthrough */
+ case 1:
+ val |= *src;
+ break;
+ }
+ return val;
+}
+
+static void swap_put32(mem_t *dst, u32_t val, cnum size) {
+ switch (size) {
+ case 4:
+ *dst++ = val;
+ val >>= 8;
+ /* fallthrough */
+ case 3:
+ *dst++ = val;
+ val >>= 8;
+ /* fallthrough */
+ case 2:
+ *dst++ = val;
+ val >>= 8;
+ /* fallthrough */
+ case 1:
+ *dst = val;
+ break;
+ }
+}
+
+#if HAVE_I64
+
+static u64_t swap_get64(const mem_t *src, cnum lim)
+{
+ u64_t val = 0;
+
+ switch (lim) {
+ case 8:
+ val = *src++;
+ val <<= 8;
+ /* fallthrough */
+ case 7:
+ val |= *src++;
+ val <<= 8;
+ /* fallthrough */
+ case 6:
+ val |= *src++;
+ val <<= 8;
+ /* fallthrough */
+ case 5:
+ val |= *src++;
+ val <<= 8;
+ /* fallthrough */
+ case 4:
+ val |= *src++;
+ val <<= 8;
+ /* fallthrough */
+ case 3:
+ val |= *src++;
+ val <<= 8;
+ /* fallthrough */
+ case 2:
+ val |= *src++;
+ val <<= 8;
+ /* fallthrough */
+ case 1:
+ val |= *src;
+ break;
+ }
+ return val;
+}
+
+static void swap_put64(mem_t *dst, u64_t val, cnum size)
+{
+ switch (size) {
+ case 8:
+ *dst++ = val;
+ val >>= 8;
+ /* fallthrough */
+ case 7:
+ *dst++ = val;
+ val >>= 8;
+ /* fallthrough */
+ case 6:
+ *dst++ = val;
+ val >>= 8;
+ /* fallthrough */
+ case 5:
+ *dst++ = val;
+ val >>= 8;
+ /* fallthrough */
+ case 4:
+ *dst++ = val;
+ val >>= 8;
+ /* fallthrough */
+ case 3:
+ *dst++ = val;
+ val >>= 8;
+ /* fallthrough */
+ case 2:
+ *dst++ = val;
+ val >>= 8;
+ /* fallthrough */
+ case 1:
+ *dst = val;
+ break;
+ }
+}
+
+#endif
+
+#endif
+
+static void ffi_generic_swap_sbit_put(struct txr_ffi_type *tft, val n,
+ mem_t *dst, val self)
+{
+ u32_t tmp = swap_get32(dst, tft->size);
+ ffi_sbit_put(tft, n, coerce(mem_t *, &tmp), self);
+ swap_put32(dst, tmp, tft->size);
+}
+
+static val ffi_generic_swap_sbit_get(struct txr_ffi_type *tft,
+ mem_t *src, val self)
+{
+ u32_t tmp = swap_get32(src, tft->size);
+ return ffi_sbit_get(tft, coerce(mem_t *, &tmp), self);
+}
+
+static void ffi_generic_swap_ubit_put(struct txr_ffi_type *tft, val n,
+ mem_t *dst, val self)
+{
+ u32_t tmp = swap_get32(dst, tft->size);
+ ffi_ubit_put(tft, n, coerce(mem_t *, &tmp), self);
+ memcpy(dst, coerce(mem_t *, &tmp), tft->size);
+ swap_put32(dst, tmp, tft->size);
+}
+
+static val ffi_generic_swap_ubit_get(struct txr_ffi_type *tft,
+ mem_t *src, val self)
+{
+ u32_t tmp = swap_get32(src, tft->size);
+ return ffi_ubit_get(tft, coerce(mem_t *, &tmp), self);
+}
+
+#if HAVE_I64
+
+static void ffi_generic_swap_fat_sbit_put(struct txr_ffi_type *tft, val n,
+ mem_t *dst, val self)
+{
+ u64_t tmp = swap_get64(dst, tft->size);
+ ffi_fat_sbit_put(tft, n, coerce(mem_t *, &tmp), self);
+ swap_put64(dst, tmp, tft->size);
+}
+
+static val ffi_generic_swap_fat_sbit_get(struct txr_ffi_type *tft,
+ mem_t *src, val self)
+{
+ u64_t tmp = swap_get64(src, tft->size);
+ return ffi_fat_sbit_get(tft, coerce(mem_t *, &tmp), self);
+}
+
+static void ffi_generic_swap_fat_ubit_put(struct txr_ffi_type *tft, val n,
+ mem_t *dst, val self)
+{
+ u64_t tmp = swap_get64(dst, tft->size);
+ ffi_fat_ubit_put(tft, n, coerce(mem_t *, &tmp), self);
+ swap_put64(dst, tmp, tft->size);
+}
+
+static val ffi_generic_swap_fat_ubit_get(struct txr_ffi_type *tft,
+ mem_t *src, val self)
+{
+ u64_t tmp = swap_get64(src, tft->size);
+ return ffi_fat_ubit_get(tft, coerce(mem_t *, &tmp), self);
+}
+
+#endif
+
static void ffi_bool_put(struct txr_ffi_type *tft, val truth,
mem_t *dst, val self)
{
@@ -3291,6 +3566,7 @@ static val make_ffi_type_builtin(val syntax, val lisp_type, ffi_kind_t kind,
#if !HAVE_LITTLE_ENDIAN
tft->rput = (rput ? rput : put);
tft->rget = (rget ? rget : get);
+ tft->bigendian = 1;
#else
(void) rput;
(void) rget;
@@ -3299,6 +3575,25 @@ static val make_ffi_type_builtin(val syntax, val lisp_type, ffi_kind_t kind,
return obj;
}
+static val make_ffi_type_endian(val syntax, val lisp_type, ffi_kind_t kind,
+ cnum size, cnum align, ffi_type *ft,
+ void (*put)(struct txr_ffi_type *,
+ val obj, mem_t *dst, val self),
+ val (*get)(struct txr_ffi_type *,
+ mem_t *src, val self),
+ void (*rput)(struct txr_ffi_type *,
+ val obj, mem_t *dst, val self),
+ val (*rget)(struct txr_ffi_type *,
+ mem_t *src, val self),
+ int bigendian)
+{
+ val type = make_ffi_type_builtin(syntax, lisp_type, kind, size, align, ft,
+ put, get, rput, rget);
+ struct txr_ffi_type *tft = ffi_type_struct(type);
+ tft->bigendian = bigendian;
+ return type;
+}
+
static val make_ffi_type_pointer(val syntax, val lisp_type,
void (*put)(struct txr_ffi_type *, val obj,
mem_t *dst, val self),
@@ -3489,6 +3784,7 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
ucnum offs = 0;
ucnum most_align = 1;
ucnum prev_align = 1;
+ uint prev_bigendian = 0;
int need_out_handler = 0;
int bit_offs = 0;
const unsigned bits_int = 8 * sizeof(int);
@@ -3554,7 +3850,9 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
setcheck(obj, slot);
setcheck(obj, type);
- if (mtft->bitfield && align != prev_align) {
+ if (mtft->bitfield && (align != prev_align ||
+ mtft->bigendian != prev_bigendian))
+ {
if (bit_offs)
offs++;
offs = (offs + almask) & ~almask;
@@ -3585,16 +3883,14 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
memb[i].offs = offs;
-#if HAVE_LITTLE_ENDIAN
- mtft->shift = bit_offs;
-#else
+ if (!mtft->bigendian)
+ mtft->shift = bit_offs;
#if HAVE_I64
- if (size > sizeof (int))
+ else if (size > (sizeof (int)))
mtft->shift = bits_llint - bit_offs - bits;
- else
#endif
+ else
mtft->shift = bits_int - bit_offs - bits;
-#endif
#if HAVE_I64
if (size > sizeof (int)) {
@@ -3633,6 +3929,7 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
}
prev_align = align;
+ prev_bigendian = mtft->bigendian;
need_out_handler = need_out_handler || mtft->out != 0;
@@ -3750,16 +4047,14 @@ static val make_ffi_type_union(val syntax, val use_existing, val self)
continue;
}
-#if HAVE_LITTLE_ENDIAN
- mtft->shift = 0;
-#else
+ if (!mtft->bigendian)
+ mtft->shift = 0;
#if HAVE_I64
- if (size > sizeof (int))
+ else if (size > (sizeof (int)))
mtft->shift = bits_llint - bits;
- else
#endif
+ else
mtft->shift = bits_int - bits;
-#endif
#if HAVE_I64
if (mtft->size > (int) sizeof (int)) {
@@ -3864,7 +4159,7 @@ static val make_ffi_type_enum(val syntax, val enums,
val enum_env = make_env(nil, nil, nil);
val shadow_menv = make_env(nil, nil, nil);
- if (btft->kind != FFI_KIND_NUM)
+ if (btft->kind != FFI_KIND_INT && btft->kind != FFI_KIND_UINT)
uw_throwf(error_s, lit("~a: type ~s can't be basis for enum"),
self, btft->syntax, nao);
@@ -4249,7 +4544,8 @@ val ffi_type_compile(val syntax)
cnum nb = c_num(nbits, self);
val xsyntax = list(sym, nbits, nao);
val type = make_ffi_type_builtin(xsyntax, integer_s,
- FFI_KIND_NUM,
+ if3(sym == sbit_s,
+ FFI_KIND_INT, FFI_KIND_UINT),
sizeof (int), alignof (int),
&ffi_type_void,
if3(sym == sbit_s,
@@ -4290,24 +4586,16 @@ val ffi_type_compile(val syntax)
#endif
val type_copy = ffi_type_copy(type);
struct txr_ffi_type *tft_cp = ffi_type_struct(type_copy);
- val syn = tft->syntax;
int unsgnd = 0;
if (cdddr(syntax))
goto excess;
- if (syn == uint8_s || syn == uint16_s || syn == uint32_s ||
- syn == uint64_s ||
- syn == uchar_s || syn == ushort_s || syn == uint_s)
- {
+ if (tft_cp->kind == FFI_KIND_UINT)
unsgnd = 1;
- } else if (syn != int8_s && syn != int16_s && syn != int32_s &&
- syn != int64_s &&
- syn != char_s && syn != short_s && syn != int_s)
- {
+ else if (tft_cp->kind != FFI_KIND_INT)
uw_throwf(error_s, lit("~a: ~s not supported as bitfield type"),
self, type, nao);
- }
if (nb < 0 || nb > bits_lim)
uw_throwf(error_s, lit("~a: bitfield size ~s in ~s: "
@@ -4316,19 +4604,42 @@ val ffi_type_compile(val syntax)
tft_cp->syntax = xsyntax;
tft_cp->nelem = nb;
+ if ((!tft_cp->bigendian && HAVE_LITTLE_ENDIAN) ||
+ (tft_cp->bigendian && !HAVE_LITTLE_ENDIAN))
+ {
#if HAVE_I64
- if (tft->size > (int) sizeof (int)) {
- tft_cp->put = if3(unsgnd,
- ffi_generic_fat_ubit_put,
- ffi_generic_fat_sbit_put);
- tft_cp->get = if3(unsgnd,
- ffi_generic_fat_ubit_get,
- ffi_generic_fat_sbit_get);
- } else
+ if (tft->size > (int) sizeof (int)) {
+ tft_cp->put = if3(unsgnd,
+ ffi_generic_fat_ubit_put,
+ ffi_generic_fat_sbit_put);
+ tft_cp->get = if3(unsgnd,
+ ffi_generic_fat_ubit_get,
+ ffi_generic_fat_sbit_get);
+ } else
#endif
- {
- tft_cp->put = if3(unsgnd, ffi_generic_ubit_put, ffi_generic_sbit_put);
- tft_cp->get = if3(unsgnd, ffi_generic_ubit_get, ffi_generic_sbit_get);
+ {
+ tft_cp->put = if3(unsgnd, ffi_generic_ubit_put, ffi_generic_sbit_put);
+ tft_cp->get = if3(unsgnd, ffi_generic_ubit_get, ffi_generic_sbit_get);
+ }
+ } else {
+#if HAVE_I64
+ if (tft->size > (int) sizeof (int)) {
+ tft_cp->put = if3(unsgnd,
+ ffi_generic_swap_fat_ubit_put,
+ ffi_generic_swap_fat_sbit_put);
+ tft_cp->get = if3(unsgnd,
+ ffi_generic_swap_fat_ubit_get,
+ ffi_generic_swap_fat_sbit_get);
+ } else
+#endif
+ {
+ tft_cp->put = if3(unsgnd,
+ ffi_generic_swap_ubit_put,
+ ffi_generic_swap_sbit_put);
+ tft_cp->get = if3(unsgnd,
+ ffi_generic_swap_ubit_get,
+ ffi_generic_swap_sbit_get);
+ }
}
tft_cp->bitfield = 1;
/* mask needed at type compilation time by (enumed (bit ...)) */
@@ -4508,14 +4819,14 @@ static void ffi_init_types(void)
#if HAVE_I8
ffi_typedef(uint8_s, make_ffi_type_builtin(uint8_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_UINT,
sizeof (i8_t), alignof (i8_t),
&ffi_type_uint8,
ffi_u8_put, ffi_u8_get,
ifbe(ffi_u8_rput),
ifbe(ffi_u8_rget)));
ffi_typedef(int8_s, make_ffi_type_builtin(int8_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_INT,
sizeof (i8_t), alignof (i8_t),
&ffi_type_sint8,
ffi_i8_put, ffi_i8_get,
@@ -4524,14 +4835,14 @@ static void ffi_init_types(void)
#endif
#if HAVE_I16
ffi_typedef(uint16_s, make_ffi_type_builtin(uint16_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_UINT,
sizeof (i16_t), alignof (i16_t),
&ffi_type_uint16,
ffi_u16_put, ffi_u16_get,
ifbe(ffi_u16_rput),
ifbe(ffi_u16_rget)));
ffi_typedef(int16_s, make_ffi_type_builtin(int16_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_INT,
sizeof (i16_t), alignof (i16_t),
&ffi_type_sint16,
ffi_i16_put, ffi_i16_get,
@@ -4540,14 +4851,14 @@ static void ffi_init_types(void)
#endif
#if HAVE_I32
ffi_typedef(uint32_s, make_ffi_type_builtin(uint32_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_UINT,
sizeof (i32_t), alignof (i32_t),
&ffi_type_uint32,
ffi_u32_put, ffi_u32_get,
ifbe(ffi_u32_rput),
ifbe(ffi_u32_rget)));
ffi_typedef(int32_s, make_ffi_type_builtin(int32_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_INT,
sizeof (i32_t), alignof (i32_t),
&ffi_type_sint32,
ffi_i32_put, ffi_i32_get,
@@ -4556,46 +4867,49 @@ static void ffi_init_types(void)
#endif
#if HAVE_I64
ffi_typedef(uint64_s, make_ffi_type_builtin(uint64_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_UINT,
sizeof (i64_t), alignof (i64_t),
&ffi_type_uint64,
ffi_u64_put, ffi_u64_get, 0, 0));
ffi_typedef(int64_s, make_ffi_type_builtin(int64_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_INT,
sizeof (i64_t), alignof (i64_t),
&ffi_type_sint64,
ffi_i64_put, ffi_i64_get, 0, 0));
#endif
ffi_typedef(uchar_s, make_ffi_type_builtin(uchar_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_UINT,
1, 1,
&ffi_type_uchar,
ffi_uchar_put, ffi_uchar_get,
ifbe(ffi_uchar_rput),
ifbe(ffi_uchar_rget)));
ffi_typedef(char_s, make_ffi_type_builtin(char_s, integer_s,
- FFI_KIND_NUM,
+ if3(CHAR_MAX == UCHAR_MAX,
+ FFI_KIND_UINT, FFI_KIND_INT),
1, 1,
ffi_char, ffi_char_put,
ffi_char_get,
ifbe(ffi_char_rput),
ifbe(ffi_char_rget)));
ffi_typedef(zchar_s, make_ffi_type_builtin(zchar_s, integer_s,
- FFI_KIND_NUM,
+ if3(CHAR_MAX == UCHAR_MAX,
+ FFI_KIND_UINT, FFI_KIND_INT),
1, 1,
ffi_char, ffi_char_put,
ffi_char_get,
ifbe(ffi_char_rput),
ifbe(ffi_char_rget)));
ffi_typedef(bchar_s, make_ffi_type_builtin(bchar_s, char_s,
- FFI_KIND_NUM,
+ FFI_KIND_UINT,
1, 1,
&ffi_type_uchar,
ffi_uchar_put, ffi_bchar_get,
ifbe(ffi_uchar_rput),
ifbe(ffi_bchar_rget)));
ffi_typedef(wchar_s, make_ffi_type_builtin(wchar_s, char_s,
- FFI_KIND_NUM,
+ if3(convert(wchar_t, -1) < 0,
+ FFI_KIND_INT, FFI_KIND_UINT),
sizeof (wchar_t),
alignof (wchar_t),
&ffi_type_wchar,
@@ -4603,55 +4917,55 @@ static void ffi_init_types(void)
ifbe(ffi_wchar_rput),
ifbe(ffi_wchar_rget)));
ffi_typedef(ushort_s, make_ffi_type_builtin(ushort_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_UINT,
sizeof (short), alignof (short),
&ffi_type_ushort,
ffi_ushort_put, ffi_ushort_get,
ifbe(ffi_ushort_rput),
ifbe(ffi_ushort_rget)));
ffi_typedef(short_s, make_ffi_type_builtin(short_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_INT,
sizeof (short), alignof (short),
&ffi_type_sshort,
ffi_short_put, ffi_short_get,
ifbe(ffi_short_rput),
ifbe(ffi_short_rget)));
ffi_typedef(int_s, make_ffi_type_builtin(int_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_INT,
sizeof (int), alignof (int),
&ffi_type_sint,
ffi_int_put, ffi_int_get,
ifbe(ffi_int_rput),
ifbe(ffi_int_rget)));
ffi_typedef(uint_s, make_ffi_type_builtin(uint_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_UINT,
sizeof (int), alignof (int),
&ffi_type_uint,
ffi_uint_put, ffi_uint_get,
ifbe(ffi_uint_rput),
ifbe(ffi_uint_rget)));
ffi_typedef(ulong_s, make_ffi_type_builtin(ulong_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_UINT,
sizeof (long), alignof (long),
&ffi_type_ulong,
ffi_ulong_put, ffi_ulong_get,
ifbe(ffi_ulong_rput),
ifbe(ffi_ulong_rget)));
ffi_typedef(long_s, make_ffi_type_builtin(long_s, integer_s,
- FFI_KIND_NUM,
+ FFI_KIND_INT,
sizeof (long), alignof (long),
&ffi_type_slong,
ffi_long_put, ffi_long_get,
ifbe(ffi_long_rput),
ifbe(ffi_long_rget)));
ffi_typedef(float_s, make_ffi_type_builtin(float_s, float_s,
- FFI_KIND_NUM,
+ FFI_KIND_FLO,
sizeof (float), alignof (float),
&ffi_type_float,
ffi_float_put, ffi_float_get,
0, 0));
ffi_typedef(double_s, make_ffi_type_builtin(double_s, float_s,
- FFI_KIND_NUM,
+ FFI_KIND_FLO,
sizeof (double),
alignof (double),
&ffi_type_double,
@@ -4666,152 +4980,168 @@ static void ffi_init_types(void)
0, 0));
#if HAVE_I16
- ffi_typedef(be_uint16_s, make_ffi_type_builtin(be_uint16_s, integer_s,
- FFI_KIND_NUM,
- sizeof (u16_t),
- alignof (u16_t),
- &ffi_type_uint16,
- ffi_be_u16_put,
- ffi_be_u16_get,
- ifbe(ffi_be_u16_rput),
- ifbe(ffi_be_u16_rget)));
- ffi_typedef(be_int16_s, make_ffi_type_builtin(be_int16_s, integer_s,
- FFI_KIND_NUM,
- sizeof (i16_t),
- alignof (i16_t),
- &ffi_type_sint16,
- ffi_be_i16_put,
- ffi_be_i16_get,
- ifbe(ffi_be_i16_rput),
- ifbe(ffi_be_i16_rget)));
+ ffi_typedef(be_uint16_s, make_ffi_type_endian(be_uint16_s, integer_s,
+ FFI_KIND_UINT,
+ sizeof (u16_t),
+ alignof (u16_t),
+ &ffi_type_uint16,
+ ffi_be_u16_put,
+ ffi_be_u16_get,
+ ifbe(ffi_be_u16_rput),
+ ifbe(ffi_be_u16_rget),
+ 1));
+ ffi_typedef(be_int16_s, make_ffi_type_endian(be_int16_s, integer_s,
+ FFI_KIND_INT,
+ sizeof (i16_t),
+ alignof (i16_t),
+ &ffi_type_sint16,
+ ffi_be_i16_put,
+ ffi_be_i16_get,
+ ifbe(ffi_be_i16_rput),
+ ifbe(ffi_be_i16_rget),
+ 1));
#endif
#if HAVE_I32
- ffi_typedef(be_uint32_s, make_ffi_type_builtin(be_uint32_s, integer_s,
- FFI_KIND_NUM,
- sizeof (u32_t),
- alignof (u32_t),
- &ffi_type_uint32,
- ffi_be_u32_put,
- ffi_be_u32_get,
- ifbe(ffi_be_u32_rput),
- ifbe(ffi_be_u32_rget)));
- ffi_typedef(be_int32_s, make_ffi_type_builtin(be_int32_s, integer_s,
- FFI_KIND_NUM,
- sizeof (i32_t),
- alignof (i32_t),
- &ffi_type_sint32,
- ffi_be_i32_put,
- ffi_be_i32_get,
- ifbe(ffi_be_i32_rput),
- ifbe(ffi_be_i32_rget)));
+ ffi_typedef(be_uint32_s, make_ffi_type_endian(be_uint32_s, integer_s,
+ FFI_KIND_UINT,
+ sizeof (u32_t),
+ alignof (u32_t),
+ &ffi_type_uint32,
+ ffi_be_u32_put,
+ ffi_be_u32_get,
+ ifbe(ffi_be_u32_rput),
+ ifbe(ffi_be_u32_rget),
+ 1));
+ ffi_typedef(be_int32_s, make_ffi_type_endian(be_int32_s, integer_s,
+ FFI_KIND_INT,
+ sizeof (i32_t),
+ alignof (i32_t),
+ &ffi_type_sint32,
+ ffi_be_i32_put,
+ ffi_be_i32_get,
+ ifbe(ffi_be_i32_rput),
+ ifbe(ffi_be_i32_rget),
+ 1));
#endif
#if HAVE_I64
- ffi_typedef(be_uint64_s, make_ffi_type_builtin(be_uint64_s, integer_s,
- FFI_KIND_NUM,
- sizeof (u64_t),
- alignof (u64_t),
- &ffi_type_uint64,
- ffi_be_u64_put,
- ffi_be_u64_get, 0, 0));
- ffi_typedef(be_int64_s, make_ffi_type_builtin(be_int64_s, integer_s,
- FFI_KIND_NUM,
- sizeof (i64_t),
- alignof (i64_t),
- &ffi_type_sint64,
- ffi_be_i64_put,
- ffi_be_i64_get, 0, 0));
-#endif
-
- ffi_typedef(be_float_s, make_ffi_type_builtin(be_float_s, float_s,
- FFI_KIND_NUM,
- sizeof (float),
- alignof (float),
- &ffi_type_float,
- ffi_be_float_put,
- ffi_be_float_get, 0, 0));
- ffi_typedef(be_double_s, make_ffi_type_builtin(be_double_s, float_s,
- FFI_KIND_NUM,
- sizeof (double),
- alignof (double),
- &ffi_type_double,
- ffi_be_double_put,
- ffi_be_double_get, 0, 0));
+ ffi_typedef(be_uint64_s, make_ffi_type_endian(be_uint64_s, integer_s,
+ FFI_KIND_UINT,
+ sizeof (u64_t),
+ alignof (u64_t),
+ &ffi_type_uint64,
+ ffi_be_u64_put,
+ ffi_be_u64_get,
+ 0, 0, 1));
+ ffi_typedef(be_int64_s, make_ffi_type_endian(be_int64_s, integer_s,
+ FFI_KIND_INT,
+ sizeof (i64_t),
+ alignof (i64_t),
+ &ffi_type_sint64,
+ ffi_be_i64_put,
+ ffi_be_i64_get,
+ 0, 0, 1));
+#endif
+
+ ffi_typedef(be_float_s, make_ffi_type_endian(be_float_s, float_s,
+ FFI_KIND_FLO,
+ sizeof (float),
+ alignof (float),
+ &ffi_type_float,
+ ffi_be_float_put,
+ ffi_be_float_get,
+ 0, 0, 1));
+ ffi_typedef(be_double_s, make_ffi_type_endian(be_double_s, float_s,
+ FFI_KIND_FLO,
+ sizeof (double),
+ alignof (double),
+ &ffi_type_double,
+ ffi_be_double_put,
+ ffi_be_double_get,
+ 0, 0, 1));
#if HAVE_I16
- ffi_typedef(le_uint16_s, make_ffi_type_builtin(le_uint16_s, integer_s,
- FFI_KIND_NUM,
- sizeof (u16_t),
- alignof (u16_t),
- &ffi_type_uint16,
- ffi_le_u16_put,
- ffi_le_u16_get,
- ifbe(ffi_le_u16_rput),
- ifbe(ffi_le_u16_rget)));
- ffi_typedef(le_int16_s, make_ffi_type_builtin(le_int16_s, integer_s,
- FFI_KIND_NUM,
- sizeof (i16_t),
- alignof (i16_t),
- &ffi_type_sint16,
- ffi_le_i16_put,
- ffi_le_i16_get,
- ifbe(ffi_le_i16_rput),
- ifbe(ffi_le_i16_rget)));
+ ffi_typedef(le_uint16_s, make_ffi_type_endian(le_uint16_s, integer_s,
+ FFI_KIND_UINT,
+ sizeof (u16_t),
+ alignof (u16_t),
+ &ffi_type_uint16,
+ ffi_le_u16_put,
+ ffi_le_u16_get,
+ ifbe(ffi_le_u16_rput),
+ ifbe(ffi_le_u16_rget),
+ 0));
+ ffi_typedef(le_int16_s, make_ffi_type_endian(le_int16_s, integer_s,
+ FFI_KIND_INT,
+ sizeof (i16_t),
+ alignof (i16_t),
+ &ffi_type_sint16,
+ ffi_le_i16_put,
+ ffi_le_i16_get,
+ ifbe(ffi_le_i16_rput),
+ ifbe(ffi_le_i16_rget),
+ 0));
#endif
#if HAVE_I32
- ffi_typedef(le_uint32_s, make_ffi_type_builtin(le_uint32_s, integer_s,
- FFI_KIND_NUM,
- sizeof (u32_t),
- alignof (u32_t),
- &ffi_type_uint32,
- ffi_le_u32_put,
- ffi_le_u32_get,
- ifbe(ffi_le_u32_rput),
- ifbe(ffi_le_u32_rget)));
- ffi_typedef(le_int32_s, make_ffi_type_builtin(le_int32_s, integer_s,
- FFI_KIND_NUM,
- sizeof (i32_t),
- alignof (i32_t),
- &ffi_type_sint32,
- ffi_le_i32_put,
- ffi_le_i32_get,
- ifbe(ffi_le_i32_rput),
- ifbe(ffi_le_i32_rget)));
+ ffi_typedef(le_uint32_s, make_ffi_type_endian(le_uint32_s, integer_s,
+ FFI_KIND_UINT,
+ sizeof (u32_t),
+ alignof (u32_t),
+ &ffi_type_uint32,
+ ffi_le_u32_put,
+ ffi_le_u32_get,
+ ifbe(ffi_le_u32_rput),
+ ifbe(ffi_le_u32_rget),
+ 0));
+ ffi_typedef(le_int32_s, make_ffi_type_endian(le_int32_s, integer_s,
+ FFI_KIND_INT,
+ sizeof (i32_t),
+ alignof (i32_t),
+ &ffi_type_sint32,
+ ffi_le_i32_put,
+ ffi_le_i32_get,
+ ifbe(ffi_le_i32_rput),
+ ifbe(ffi_le_i32_rget),
+ 0));
#endif
#if HAVE_I64
- ffi_typedef(le_uint64_s, make_ffi_type_builtin(le_uint64_s, integer_s,
- FFI_KIND_NUM,
- sizeof (u64_t),
- alignof (u64_t),
- &ffi_type_uint64,
- ffi_le_u64_put,
- ffi_le_u64_get, 0, 0));
- ffi_typedef(le_int64_s, make_ffi_type_builtin(le_int64_s, integer_s,
- FFI_KIND_NUM,
- sizeof (i64_t),
- alignof (i64_t),
- &ffi_type_sint64,
- ffi_le_i64_put,
- ffi_le_i64_get, 0, 0));
-#endif
-
- ffi_typedef(le_float_s, make_ffi_type_builtin(le_float_s, float_s,
- FFI_KIND_NUM,
- sizeof (float),
- alignof (float),
- &ffi_type_float,
- ffi_le_float_put,
- ffi_le_float_get, 0, 0));
- ffi_typedef(le_double_s, make_ffi_type_builtin(le_double_s, float_s,
- FFI_KIND_NUM,
- sizeof (double),
- alignof (double),
- &ffi_type_double,
- ffi_le_double_put,
- ffi_le_double_get, 0, 0));
+ ffi_typedef(le_uint64_s, make_ffi_type_endian(le_uint64_s, integer_s,
+ FFI_KIND_UINT,
+ sizeof (u64_t),
+ alignof (u64_t),
+ &ffi_type_uint64,
+ ffi_le_u64_put,
+ ffi_le_u64_get,
+ 0, 0, 0));
+ ffi_typedef(le_int64_s, make_ffi_type_endian(le_int64_s, integer_s,
+ FFI_KIND_INT,
+ sizeof (i64_t),
+ alignof (i64_t),
+ &ffi_type_sint64,
+ ffi_le_i64_put,
+ ffi_le_i64_get,
+ 0, 0, 0));
+#endif
+
+ ffi_typedef(le_float_s, make_ffi_type_endian(le_float_s, float_s,
+ FFI_KIND_FLO,
+ sizeof (float),
+ alignof (float),
+ &ffi_type_float,
+ ffi_le_float_put,
+ ffi_le_float_get,
+ 0, 0, 0));
+ ffi_typedef(le_double_s, make_ffi_type_endian(le_double_s, float_s,
+ FFI_KIND_FLO,
+ sizeof (double),
+ alignof (double),
+ &ffi_type_double,
+ ffi_le_double_put,
+ ffi_le_double_get,
+ 0, 0, 0));
{
val type = make_ffi_type_builtin(cptr_s, cptr_s, FFI_KIND_PTR,
sizeof (mem_t *), alignof (mem_t *),
diff --git a/txr.1 b/txr.1
index 971a96fc..70904936 100644
--- a/txr.1
+++ b/txr.1
@@ -80867,25 +80867,7 @@ operator is more general than
.code ubit
and
.codn sbit .
-It allows for bitfields based on integer units smaller than or equal to
-.codn uint .
-
-The
-.meta type
-argument may be any of the types
-.codn char ,
-.codn short ,
-.codn int ,
-.codn uchar ,
-.codn ushort ,
-.codn uint ,
-.codn int8 ,
-.codn int16 ,
-.codn int32 ,
-.codn uint8 ,
-.code uint16
-and
-.codn uint32 .
+It allows for bitfields based on on any integer type up to 64 bits wide.
When the character types
.code char
@@ -80895,7 +80877,7 @@ are used as the basis of bitfields, they convert integer values, not
characters.
In the case of
.codn char ,
-the bitfield is signed.
+the bitfield is signed.
All remarks about
.code ubit
@@ -80909,6 +80891,82 @@ Details about the algorithm by which bitfields are allocated within a structure
are given in the paragraph below entitled
.BR "Bitfield Allocation Rules" .
+Under the
+.code bit
+operator, the endian types such as
+.code be-int32
+or
+.code le-int16
+may also be used as the basis for bitfields.
+If
+.meta type
+is an endian type, the bitfield is then allocated in the same way that a
+bitfield of the corresponding ordinary type would be allocated on a target
+machine which has the byte order of that endian type.
+
+When a bitfield member follows a member which has a different byte order,
+the bitfield is placed into a new allocation cell. This is true even if
+the previous member has the same alignment.
+
+Note: the allocation of bits within a bitfield based on a byte storage
+cells also differs between different endian systems. However, the FFI
+type system does not offer one byte endian types such as
+.codn be-uint8 .
+The workaround is to switch to a wider type.
+
+Note: endian bitfields may be used to match the image of a C structure which
+contains bitfields, without having to conditionally define the FFI struct type
+differently based on whether the current machine is big or little endian.
+Conditionally defining a structure for two different byte orders adds
+verbiage to the program and is highly error-prone, since the bitfields
+change order within an allocation unit.
+
+For instance, on a big endian system, the definition of a structure
+representing an IPv4 packet might begin like this:
+
+.verb
+ (struct ipv4-header
+ (ver (bit 4 uint16))
+ (ihl (bit 4 uint16))
+ (dscp (bit 6 uint16))
+ (ecn (bit 2 uint16))
+ (len uint16)
+ ...)
+.brev
+
+to port this to a little endian system, the programmer has to recognize
+that the first pair of fields is packed into one byte, and the next pair
+of fields into a second byte. The bytes stay in the same order, but
+the pairs are reversed:
+
+.verb
+ (struct ipv4-header
+ (ihl (bit 4 uint16)) ;; reversed pair
+ (ver (bit 4 uint16))
+ (ecn (bit 2 uint16)) ;; reversed pair
+ (dscp (bit 6 uint16))
+ (len be-uint16)
+ ...)
+.brev
+
+Endian bitfields allow this to be defined naturally. The IPv4 header
+is based on network byte order, which is big-endian, so big endian types
+are used. The little endian version above already uses
+.code be-uint16
+for the
+.meta len
+field. This just has to be done for the bitfields also:
+
+.verb
+ (struct ipv4-header
+ (ver (bit 4 be-uint16))
+ (ihl (bit 4 be-uint16))
+ (dscp (bit 6 be-uint16))
+ (ecn (bit 2 be-uint16))
+ (len be-uint16)
+ ...)
+.brev
+
.coNP FFI types @ buf and @ buf-d
.synb
.mets ({buf | buf-d} << size )