Speaking only to my personal opinion – if you are compiling on Windows, and the –mms-bitfields is not set and –no-ms-bitfields is not set, then you should issue
a warning to that effect.
From: Tinycc-devel [mailto:tinycc-devel-bounces+address@hidden
On Behalf Of David Mertens
Sent: Tuesday, November 22, 2016 4:32 PM
To: address@hidden
Subject: [Tinycc-devel] Patch: add option -mms-bitfields
Per previous discussion, here is a patch to implement a command-line option, -mms-bitfields. This would alter tcc's bitfield alignment algorithm in a backwards-incompatible way to be a bit more consistent with
gcc's algorithm. The old behavior is traditionally attributed to MSVC, and so (consistent with gcc) the command-line option to use the old behavior is -mms-bitfields. If this patch gets applied, Windows users would be encouraged to add -mms-bitfields to their
Makefiles.
I would appreciate comments, bug reports, etc. If you care, please give this a spin in the next 24 hours, or please tell me if you need more time. Any tests illustrating discrepancies between gcc and this algorithm would be especially appreciated!
David
diff --git a/libtcc.c b/libtcc.c
index f184502..b824c18 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -752,6 +752,7 @@ LIBTCCAPI TCCState *tcc_new(void)
s->alacarte_link = 1;
s->nocommon = 1;
s->warn_implicit_function_declaration = 1;
+ s->ms_bitfields = 0;
#ifdef CHAR_IS_UNSIGNED
s->char_is_unsigned = 1;
@@ -1508,6 +1509,7 @@ enum {
TCC_OPTION_Wl,
TCC_OPTION_W,
TCC_OPTION_O,
+ TCC_OPTION_mms_bitfields,
TCC_OPTION_m,
TCC_OPTION_f,
TCC_OPTION_isystem,
@@ -1571,6 +1573,7 @@ static const TCCOption tcc_options[] = {
{ "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+ { "mms-bitfields", TCC_OPTION_mms_bitfields, 0}, /* must go before option 'm' */
{ "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG },
{ "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG },
@@ -1854,6 +1857,9 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
if (x > 0)
tcc_define_symbol(s, "__OPTIMIZE__", NULL);
break;
+ case TCC_OPTION_mms_bitfields:
+ s->ms_bitfields = 1;
+ break;
case TCC_OPTION_traditional:
case TCC_OPTION_pedantic:
case TCC_OPTION_pipe:
diff --git a/tcc-doc.texi b/tcc-doc.texi
index 5aab13c..9f136ed 100644
--- a/tcc-doc.texi
+++ b/tcc-doc.texi
@@ -176,6 +176,10 @@ In a script, it gives the following header:
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
@end example
+@item -mms-bitfields
+Use an algorithm for bitfield alignment consistent with MSVC. Default is
+gcc's algorithm.
+
@item -mfloat-abi (ARM only)
Select the float ABI. Possible values: @code{softfp} and @code{hard}
diff --git a/tcc.c b/tcc.c
index 28f3ae9..fbfbffa 100644
--- a/tcc.c
+++ b/tcc.c
@@ -97,6 +97,7 @@ static void help(void)
" -o outfile set output filename\n"
" -run run compiled source\n"
" -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n"
+ " -mms-bitfields use bitfield alignment consistent with MSVC\n"
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n"
" -w disable all warnings\n"
" -v show version\n"
diff --git a/tcc.h b/tcc.h
index 180838d..cbdebd3 100644
--- a/tcc.h
+++ b/tcc.h
@@ -605,6 +605,7 @@ struct TCCState {
int old_struct_init_code; /* use old algorithm to init array in struct when there is no '{' used.
Liuux 2.4.26 can't find initrd when compiled with a new algorithm */
int dollars_in_identifiers; /* allows '$' char in indentifiers */
+ int ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */
/* warning switches */
int warn_write_strings;
diff --git a/tccgen.c b/tccgen.c
index ba1757e..d064024 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -3154,7 +3154,7 @@ static void parse_attribute(AttributeDef *ad)
/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
static void struct_decl(CType *type, AttributeDef *ad, int u)
{
- int a, v, size, align, maxalign, c, offset, flexible;
+ int a, v, size, align, maxalign, c, offset, flexible, extra_bytes;
int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt;
Sym *s, *ss, *ass, **ps;
AttributeDef ad1;
@@ -3235,6 +3235,7 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
while (tok != '}') {
parse_btype(&btype, &ad1);
while (1) {
+ extra_bytes = 0;
if (flexible)
tcc_error("flexible array member '%s' not at the end of struct",
get_tok_str(v, NULL));
@@ -3310,9 +3311,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
/* zero size: means to pad */
bit_pos = 0;
} else {
- /* we do not have enough room ?
- did the type change?
- is it a union? */
+ /* if type change, union, or will overrun
+ * allignment slot, start at a newly
+ * alligned slot */
if ((bit_pos + bit_size) > bsize ||
bt != prevbt || a == TOK_UNION)
bit_pos = 0;
@@ -3322,15 +3323,30 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
(bit_pos << VT_STRUCT_SHIFT) |
(bit_size << (VT_STRUCT_SHIFT + 6));
bit_pos += bit_size;
+ /* without ms-bitfields, allocate the
+ * minimum number of bytes necessary,
+ * adding single bytes as needed */
+ if (!tcc_state->ms_bitfields) {
+ if (lbit_pos == 0)
+ /* minimum bytes for new bitfield */
+ size = (bit_size + 7) / 8;
+ else {
+ /* enough spare bits already allocated? */
+ bit_size = (lbit_pos - 1) % 8 + 1 + bit_size;
+ if (bit_size > 8) /* doesn't fit */
+ extra_bytes = (bit_size - 1) / 8;
+ }
+ }
}
prevbt = bt;
} else {
bit_pos = 0;
}
if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) {
- /* add new memory data only if starting
- bit field */
- if (lbit_pos == 0) {
+ /* add new memory data only if starting bit
+ field or adding bytes to existing bit field */
+ if (extra_bytes) c += extra_bytes;
+ else if (lbit_pos == 0) {
if (a == TOK_STRUCT) {
c = (c + align - 1) & -align;
offset = c;
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 5851fb4..b0fe8f3 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -1634,6 +1634,15 @@ void bitfield_test(void)
st2.f3 = a;
st2.f2++;
printf("%lld %lld %lld\n", st2.f1, st2.f2, st2.f3);
+ struct sbf3 {
+ int f1 : 7;
+ int f2 : 1;
+ char f3;
+ int f4 : 8;
+ int f5 : 1;
+ int f6 : 16;
+ } st3;
+ printf("sizeof(st3) = %d\n", sizeof(st3));
}
#ifdef __x86_64__
|