Currently, Sparse treats 'plain' bitfields as unsigned. However, this is this is inconsistent with how non-bitfield integers are handled and with how GCC & clang handle bitfields. So, teach sparse about '-funsigned-bitfields' and by default treat these bitfields are signed, like done by GCC & clang and like done for non-bitfield integers. Also, avoid plain bitfields in IR related testcases. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> --- options.c | 3 +++ options.h | 1 + sparse.1 | 6 ++++++ symbol.c | 4 ++-- validation/linear/bitfield-sign-default.c | 13 +++++++++++++ validation/linear/bitfield-sign-signed.c | 13 +++++++++++++ validation/linear/bitfield-sign-unsigned.c | 13 +++++++++++++ validation/linear/bitfield-size.c | 10 +++++----- validation/optim/bitfield-size.c | 15 ++------------- validation/optim/bitfield-store-loads.c | 4 ++-- 10 files changed, 60 insertions(+), 22 deletions(-) create mode 100644 validation/linear/bitfield-sign-default.c create mode 100644 validation/linear/bitfield-sign-signed.c create mode 100644 validation/linear/bitfield-sign-unsigned.c diff --git a/options.c b/options.c index 294dfd3be77a..a12d28669e05 100644 --- a/options.c +++ b/options.c @@ -81,6 +81,7 @@ unsigned long fpasses = ~0UL; int fpic = 0; int fpie = 0; int fshort_wchar = 0; +int funsigned_bitfields = 0; int funsigned_char = 0; int Waddress = 0; @@ -524,6 +525,8 @@ static struct flag fflags[] = { { "PIC", &fpic, handle_switch_setval, 2 }, { "pie", &fpie, handle_switch_setval, 1 }, { "PIE", &fpie, handle_switch_setval, 2 }, + { "signed-bitfields", &funsigned_bitfields, NULL, OPT_INVERSE }, + { "unsigned-bitfields", &funsigned_bitfields, NULL, }, { "signed-char", &funsigned_char, NULL, OPT_INVERSE }, { "short-wchar", &fshort_wchar }, { "unsigned-char", &funsigned_char, NULL, }, diff --git a/options.h b/options.h index abdf08645ad2..8e3071a755be 100644 --- a/options.h +++ b/options.h @@ -80,6 +80,7 @@ extern unsigned long fpasses; extern int fpic; extern int fpie; extern int fshort_wchar; +extern int funsigned_bitfields; extern int funsigned_char; extern int Waddress; diff --git a/sparse.1 b/sparse.1 index 48dab7a9a5c1..2a8eb1249da1 100644 --- a/sparse.1 +++ b/sparse.1 @@ -518,6 +518,12 @@ column numbers in warnings or errors. If the value is less than 1 or greater than 100, the option is ignored. The default is 8. . .TP +.B \-f[no-]unsigned-bitfields, \-f[no-]signed-bitfields +Determine the signedness of bitfields declared without an +explicit sign ('signed' or 'unsigned'). +By default such bitfields are signed, like others plain integers. +. +.TP .B \-f[no-]unsigned-char, \-f[no-]signed-char Let plain 'char' be unsigned or signed. By default chars are signed. diff --git a/symbol.c b/symbol.c index 7f0c85580f06..aaeb8c100436 100644 --- a/symbol.c +++ b/symbol.c @@ -286,8 +286,8 @@ static struct symbol *examine_bitfield_type(struct symbol *sym) sym->ctype.alignment = alignment; modifiers = base_type->ctype.modifiers; - /* Bitfields are unsigned, unless the base type was explicitly signed */ - if (!(modifiers & MOD_EXPLICITLY_SIGNED)) + /* use -funsigned-bitfields to determine the sign if not explicit */ + if (!(modifiers & MOD_EXPLICITLY_SIGNED) && funsigned_bitfields) modifiers = (modifiers & ~MOD_SIGNED) | MOD_UNSIGNED; sym->ctype.modifiers |= modifiers & MOD_SIGNEDNESS; return sym; diff --git a/validation/linear/bitfield-sign-default.c b/validation/linear/bitfield-sign-default.c new file mode 100644 index 000000000000..9a2854e63c47 --- /dev/null +++ b/validation/linear/bitfield-sign-default.c @@ -0,0 +1,13 @@ +struct s { + int f:2; +}; + +static int getf(struct s s) { return s.f; } + +/* + * check-name: bitfield-sign-default + * check-command: test-linearize -fdump-ir=linearize $file + * + * check-output-ignore + * check-output-contains: sext\\. + */ diff --git a/validation/linear/bitfield-sign-signed.c b/validation/linear/bitfield-sign-signed.c new file mode 100644 index 000000000000..59a07cebebc7 --- /dev/null +++ b/validation/linear/bitfield-sign-signed.c @@ -0,0 +1,13 @@ +struct s { + int f:2; +}; + +static int getf(struct s s) { return s.f; } + +/* + * check-name: bitfield-sign-signed + * check-command: test-linearize -fdump-ir=linearize -fsigned-bitfields $file + * + * check-output-ignore + * check-output-contains: sext\\. + */ diff --git a/validation/linear/bitfield-sign-unsigned.c b/validation/linear/bitfield-sign-unsigned.c new file mode 100644 index 000000000000..099edaad979a --- /dev/null +++ b/validation/linear/bitfield-sign-unsigned.c @@ -0,0 +1,13 @@ +struct s { + int f:2; +}; + +static int getf(struct s s) { return s.f; } + +/* + * check-name: bitfield-sign-unsigned + * check-command: test-linearize -fdump-ir=linearize -funsigned-bitfields $file + * + * check-output-ignore + * check-output-contains: zext\\. + */ diff --git a/validation/linear/bitfield-size.c b/validation/linear/bitfield-size.c index dcda930dc510..719b0ab85fcc 100644 --- a/validation/linear/bitfield-size.c +++ b/validation/linear/bitfield-size.c @@ -19,7 +19,7 @@ void ucpy(struct u *d, const struct u *s) struct s { - int f:3; + signed int f:3; }; int spostinc(struct s *x) @@ -118,7 +118,7 @@ spostinc: load.64 %r33 <- 0[x] load.32 %r34 <- 0[%r33] trunc.3 %r35 <- (32) %r34 - zext.32 %r36 <- (3) %r35 + sext.32 %r36 <- (3) %r35 add.32 %r37 <- %r36, $1 trunc.3 %r38 <- (32) %r37 load.32 %r39 <- 0[%r33] @@ -126,7 +126,7 @@ spostinc: and.32 %r41 <- %r39, $0xfffffff8 or.32 %r42 <- %r41, %r40 store.32 %r42 -> 0[%r33] - zext.32 %r43 <- (3) %r36 + sext.32 %r43 <- (3) %r36 phisrc.32 %phi3(return) <- %r43 br .L7 @@ -142,7 +142,7 @@ spreinc: load.64 %r45 <- 0[x] load.32 %r46 <- 0[%r45] trunc.3 %r47 <- (32) %r46 - zext.32 %r48 <- (3) %r47 + sext.32 %r48 <- (3) %r47 add.32 %r49 <- %r48, $1 trunc.3 %r50 <- (32) %r49 load.32 %r51 <- 0[%r45] @@ -150,7 +150,7 @@ spreinc: and.32 %r53 <- %r51, $0xfffffff8 or.32 %r54 <- %r53, %r52 store.32 %r54 -> 0[%r45] - zext.32 %r55 <- (3) %r50 + sext.32 %r55 <- (3) %r50 phisrc.32 %phi4(return) <- %r55 br .L9 diff --git a/validation/optim/bitfield-size.c b/validation/optim/bitfield-size.c index 0d2deeeac2dd..ea1ed57fb8fe 100644 --- a/validation/optim/bitfield-size.c +++ b/validation/optim/bitfield-size.c @@ -19,17 +19,6 @@ signed int get__bfs_b(struct bfs bf) { return bf.b; } signed int get_pbfs_a(struct bfs *bf) { return bf->a; } signed int get_pbfs_b(struct bfs *bf) { return bf->b; } - -struct bfi { - int a:4; - int :2; - int b:4; -}; -unsigned int get__bfi_a(struct bfi bf) { return bf.a; } -unsigned int get__bfi_b(struct bfi bf) { return bf.b; } -unsigned int get_pbfi_a(struct bfi *bf) { return bf->a; } -unsigned int get_pbfi_b(struct bfi *bf) { return bf->b; } - /* * check-name: bitfield size * check-command: test-linearize -Wno-decl $file @@ -37,8 +26,8 @@ unsigned int get_pbfi_b(struct bfi *bf) { return bf->b; } * * check-output-excludes: and\\..*\\$960 * check-output-excludes: zext\\. - * check-output-pattern(8): and\\..*\\$15 + * check-output-pattern(4): and\\..*\\$15 * check-output-pattern(4): sext\\. * check-output-pattern(4): trunc\\.4 - * check-output-pattern(6): lsr\\..*\\$6 + * check-output-pattern(4): lsr\\..*\\$6 */ diff --git a/validation/optim/bitfield-store-loads.c b/validation/optim/bitfield-store-loads.c index dc625131e188..f946715bffa3 100644 --- a/validation/optim/bitfield-store-loads.c +++ b/validation/optim/bitfield-store-loads.c @@ -1,6 +1,6 @@ struct s { - char :2; - char f:3; + unsigned char :2; + unsigned char f:3; }; int foo(struct s s, int a) -- 2.28.0