From 312166cc7e31ba6a45babcf49a9e22e892ddfd45 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Thu, 19 May 2022 18:49:49 -0700 Subject: ffi: bitfield handling when storage cells are packed. In gcc, bitfields can be declared with overridden alignment; for instance when the entire structure is packed. We must modify the algorithm to make this work. Firstly, we must must pretend that we are filling from the start of the containing alignment unit, not size based unit. For instance, if the cell is an 8 byte type, but the alignment is 1, then we are just filling the current byte, not the current 8 byte multiple. However, the number of bits left (room) is still calculated from the size: so if the byte has been filled with 3 bits, we have 4 left in that byte, and then 7 more bytes, and so 61 bits. Secondly, the case of the zero-bit field is special: it does perform an alignment calculation in terms of multiples of the size, ignoring the declared alignment of the field. Thirdly, when the bits do not fit into the existing room, the offset does not move by the size of the bitfield, but by the alignment unit. For instance, if we have 63 bits left in an 8 byte field that has alignment 1, and we want to place 64 bits into another 8 byte field, then we will just move to the next byte, not to the next 64 bit cell. Starting at the next byte, we pretend we have a fres 64 bit cell, albeit misaligned. * ffi.c (make_ffi_type_struct): Make the above adjustments to the algorithm. Some common values size, alignment, mask) are declared in a wider scope and adjustments made. --- ffi.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/ffi.c b/ffi.c index 79d59a8b..364fa25a 100644 --- a/ffi.c +++ b/ffi.c @@ -3514,7 +3514,9 @@ static val make_ffi_type_struct(val syntax, val lisp_type, val slot = car(slot_syntax); val type = ffi_memb_compile(slot_syntax, i == nmemb - 1, &flexp, self); struct txr_ffi_type *mtft = ffi_type_struct(type); - cnum size = mtft->size; + ucnum size = mtft->size; + ucnum align = mtft->align; + ucnum almask = align - 1; tft->nelem = i + 1; @@ -3526,17 +3528,15 @@ static val make_ffi_type_struct(val syntax, val lisp_type, setcheck(obj, type); if (mtft->bitfield) { - 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 unit_offs = offs & ~almask; ucnum bits_alloc = 8 * (offs - unit_offs) + bit_offs; ucnum room = bits_type - bits_alloc; - ucnum align = if3(slot, mtft->align, 1); if (bits == 0) { + ucnum szmask = size - 1; + ucnum unit_offs = offs & ~szmask; if (offs != unit_offs || bit_offs > 0) offs = unit_offs + size; bit_offs = 0; @@ -3545,7 +3545,7 @@ static val make_ffi_type_struct(val syntax, val lisp_type, } if (bits > room) { - offs = unit_offs + size; + offs = unit_offs + align; bit_offs = bits_alloc = 0; } @@ -3576,12 +3576,9 @@ static val make_ffi_type_struct(val syntax, val lisp_type, offs += bit_offs / 8; bit_offs %= 8; - if (most_align < align) + if (slot && most_align < align) most_align = align; } else { - ucnum align = mtft->align; - ucnum almask = align - 1; - if (bit_offs > 0) { bug_unless (bit_offs < 8); offs++; -- cgit v1.2.3