summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-05-24 07:25:24 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-05-24 07:25:24 -0700
commit7b39d691a0fa1cffb2553237318c224d91bb9407 (patch)
treeaf831a63ba71960c3b61cc38c9b0394931313f53
parentfd37633953e63ac317b3dfd663f5cb0659d0aceb (diff)
downloadtxr-7b39d691a0fa1cffb2553237318c224d91bb9407.tar.gz
txr-7b39d691a0fa1cffb2553237318c224d91bb9407.tar.bz2
txr-7b39d691a0fa1cffb2553237318c224d91bb9407.zip
ffi: reproduce odd GNU C behavior for aligned bitfields.
We've already taken care of imitating the situation that GNU C allows __attribute__((aligned(n))) to weaken the alignment of a bitfield, contrary to it being documented that align only strengthens alignment. Even a value of n == 1 is meaningful in that it can cause the bitfield to start allocating from a new byte. This patch corrects a newly discovered nuance: when a bitfield is attributed with a weaker alignment than its underlying type (e.g. uint32_t field marked with 2 byte alignment), the original type's alignment is still in effect for calculating the alignment of the structure, and the padding. * ffi.c (struct txr_ffi_type): New member oalign, for keeping track of the type's original alignment, prior to adjustment. (make_ffi_type_struct): For a named bitfield, take the oalign value into account when determining the most strict member alignment. (ffi_type_compile): When marking a type as aligned, the we remember the original alignment in atft->oalign. * tests/017/bitfields.tl: New test case, struct s16. * txr.1: Documented.
-rw-r--r--ffi.c18
-rw-r--r--tests/017/bitfields.tl7
-rw-r--r--txr.19
3 files changed, 27 insertions, 7 deletions
diff --git a/ffi.c b/ffi.c
index db7a4c38..5a1513a2 100644
--- a/ffi.c
+++ b/ffi.c
@@ -202,7 +202,7 @@ struct txr_ffi_type {
val lt;
val syntax;
val eltype;
- cnum size, align;
+ cnum size, align, oalign;
unsigned shift;
union {
unsigned mask;
@@ -3864,8 +3864,12 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
offs += bit_offs / 8;
bit_offs %= 8;
- if (slot && most_align < align)
- most_align = align;
+ if (slot) {
+ if (align > most_align)
+ most_align = align;
+ if ((ucnum) mtft->oalign > most_align)
+ most_align = mtft->oalign;
+ }
} else {
memb[i].offs = offs;
offs += size;
@@ -4647,11 +4651,15 @@ val ffi_type_compile(val syntax)
} else {
val altype_copy = ffi_type_copy(altype);
struct txr_ffi_type *atft = ffi_type_struct(altype_copy);
- if (al > atft->align || sym == pack_s ||
+ cnum oalign = atft->align;
+ if (al > atft->align || sym == pack_s || atft->bitfield ||
(opt_compat && opt_compat <= 275))
atft->align = al;
- if (al != 1 || sym != pack_s)
+ if (al != 1 || sym != pack_s) {
+ if (!atft->oalign)
+ atft->oalign = oalign;
atft->aligned = 1;
+ }
return altype_copy;
}
}
diff --git a/tests/017/bitfields.tl b/tests/017/bitfields.tl
index 5e8277f1..155a8b95 100644
--- a/tests/017/bitfields.tl
+++ b/tests/017/bitfields.tl
@@ -598,3 +598,10 @@
(b (bit 7 le-uint32)))))
(conv-test #S(s15 x 0 a #x1ff b #x7f) #b'00ffff')
+
+(typedef s16 (struct s16
+ (x uint8)
+ (a (align 2 (bit 9 le-uint32)))
+ (b (align 2 (bit 7 le-uint32)))))
+
+(conv-test #S(s16 x 0 a #x1ff b #x7f) #b'0000ff017f000000')
diff --git a/txr.1 b/txr.1
index 1ac12f9f..ac8f0a69 100644
--- a/txr.1
+++ b/txr.1
@@ -81259,7 +81259,8 @@ That is to say, values of
.meta width
which are less than or equal to
.metn type 's
-existing alignment have no effect.
+existing alignment have no effect on alignment, except when the
+type is used as a bitfield.
The
.code pack
@@ -81315,7 +81316,11 @@ both specified with a
of 1. If the requested alignment for the type of a bitfield is 1, and
the previous member is a bitfield which has left a byte partially filled,
then the new bitfield starts on a fresh byte, even if it would otherwise
-be packed with the previous bitfield.
+be packed with the previous bitfield. If a named bitfield has weakened
+alignment, other than one byte alignment produced by
+.codn pack ,
+the bitfield's original type's alignment is used for the purposes of
+determining its contribution to the alignment of the structure.
When
.meta type