summaryrefslogtreecommitdiffstats
path: root/ffi.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-06-07 06:04:23 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-06-07 06:04:23 -0700
commit032f568f5f0b844db4890a95bd81851a6cb83fd2 (patch)
tree2f2a34ac3aa5722b07a61cae816c4ff006fbdab1 /ffi.c
parent61ee6b198b8fdeb21e259d1c94d92fe1d75a7bd8 (diff)
downloadtxr-032f568f5f0b844db4890a95bd81851a6cb83fd2.tar.gz
txr-032f568f5f0b844db4890a95bd81851a6cb83fd2.tar.bz2
txr-032f568f5f0b844db4890a95bd81851a6cb83fd2.zip
ffi: conform to GCC's bitfield layout algorithm.
The way bitfields are laid out must be changed. The requirements were reverse-engineered by experimentation. * ffi.c (make_ffi_type_struct): Member allocation loop substantially rewritten. * txr.1: Documentation rewritten. Description of the bitfield allocation algorithm moved to a separate paragraph.
Diffstat (limited to 'ffi.c')
-rw-r--r--ffi.c47
1 files changed, 25 insertions, 22 deletions
diff --git a/ffi.c b/ffi.c
index 52627547..3871cd7d 100644
--- a/ffi.c
+++ b/ffi.c
@@ -2695,7 +2695,6 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
ucnum most_align = 0;
int need_out_handler = 0;
int bit_offs = 0;
- int prev_size = 0;
const int bits_int = 8 * sizeof(int);
ft->type = FFI_TYPE_STRUCT;
@@ -2727,53 +2726,55 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
memb[i].mtft = mtft;
if (bitfield_syntax_p(mtft->syntax)) {
- int bits_type = 8 * mtft->size;
- int bits = mtft->nelem;
- int room = bits_type - bit_offs; /* assuming same size, checked below */
+ ucnum size = mtft->size;
+ ucnum bits_type = 8 * size;
+ ucnum bits = mtft->nelem;
+ ucnum offs_mask = size - 1;
+ ucnum align_mask = ~offs_mask;
+ ucnum unit_offs = offs & align_mask;
+ ucnum bits_alloc = 8 * (offs - unit_offs) + bit_offs;
+ ucnum room = bits_type - bits_alloc;
if (bits == 0) {
- if (bit_offs > 0) {
- offs += prev_size;
- bit_offs = 0;
- prev_size = 0;
- }
+ if (offs != unit_offs)
+ offs = unit_offs + size;
+ bit_offs = 0;
nmemb--, i--;
continue;
}
- if ((prev_size && prev_size != mtft->size) || bits > room) {
- offs += prev_size;
+ if (bits > room) {
+ offs = unit_offs + size;
bit_offs = 0;
}
- if (bit_offs == 0) {
- ucnum almask = mtft->align - 1;
- offs = (offs + almask) & ~almask;
+ if (bits_alloc == 0) {
if (most_align < mtft->align)
most_align = mtft->align;
}
- memb[i].offs = offs;
+ memb[i].offs = unit_offs;
#if HAVE_LITTLE_ENDIAN
- mtft->shift = bit_offs;
+ mtft->shift = bits_alloc;
#else
- mtft->shift = bits_int - bit_offs - bits;
+ mtft->shift = bits_int - bits_alloc - bits;
#endif
if (bits == bits_int)
mtft->mask = UINT_MAX;
else
mtft->mask = ((1U << bits) - 1) << mtft->shift;
bit_offs += bits;
- prev_size = mtft->size;
+ offs += bit_offs / 8;
+ bit_offs %= 8;
} else {
ucnum align = mtft->align;
ucnum almask = align - 1;
if (bit_offs > 0) {
- offs += prev_size;
+ bug_unless (bit_offs < 8);
+ offs++;
bit_offs = 0;
- prev_size = 0;
}
offs = (offs + almask) & ~almask;
@@ -2787,8 +2788,10 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
need_out_handler = need_out_handler || mtft->out != 0;
}
- if (bit_offs > 0)
- offs += prev_size;
+ if (bit_offs > 0) {
+ bug_unless (bit_offs < 8);
+ offs++;
+ }
tft->nelem = i;