diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2022-05-22 09:05:15 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2022-05-22 09:05:15 -0700 |
commit | 16eb3d22a29911981371b98e83008f8741903cc8 (patch) | |
tree | 4f80b90d1026ec44fb06d1359b368589040a69b4 /stdlib/tagbody.tl | |
parent | 663b75b357e77bfc47e31830b4e49cf1b026b141 (diff) | |
download | txr-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.
Diffstat (limited to 'stdlib/tagbody.tl')
0 files changed, 0 insertions, 0 deletions