In the code dealing with folding of structure and union initialization, there is a check that the size of the constructor is the same as the field being read. However, in the case of bitfield this test can be wrong because it relies on TYPE_SIZE to get the size of the field being read but TYPE_SIZE returns the size of the enclosing integer in that case. This patch also check the size parameter which contains the actual size of the field being read.
The patch was tested by running the testsuite with three different builds of GCC: 1) bootstrap of GCC on x86_64-linux-gnu 2) arm-none-eabi cross compiler (defaulting to little endian) with testsuite run under qemu emulqting a Cortex M4 3) arm-none-eabi cross compiler (defaulting to big endian, thanks to patch at [1]) with testsuite run under qemu emulating a Cortex M3. [1] https://sourceware.org/ml/binutils/2014-08/msg00014.html No regression were observed on any of the tests. The ChangeLog is as follows: 2014-08-11 Thomas Preud'homme <thomas.preudho...@arm.com> * gimple-fold.c (fold_ctor_reference): Don't fold in presence of bitfields, that is when size doesn't match the size of type or the size of the constructor. diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 3dcb576..6270c34 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -3099,7 +3099,9 @@ fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset, if (!AGGREGATE_TYPE_P (TREE_TYPE (ctor)) && !offset /* VIEW_CONVERT_EXPR is defined only for matching sizes. */ && operand_equal_p (TYPE_SIZE (type), - TYPE_SIZE (TREE_TYPE (ctor)), 0)) + TYPE_SIZE (TREE_TYPE (ctor)), 0) + && !compare_tree_int (TYPE_SIZE (type), size) + && !compare_tree_int (TYPE_SIZE (TREE_TYPE (ctor)), size)) { ret = canonicalize_constructor_val (unshare_expr (ctor), from_decl); ret = fold_unary (VIEW_CONVERT_EXPR, type, ret); diff --git a/gcc/testsuite/gcc.c-torture/execute/bitfld-6.c b/gcc/testsuite/gcc.c-torture/execute/bitfld-6.c new file mode 100644 index 0000000..50927dc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/bitfld-6.c @@ -0,0 +1,23 @@ +union U +{ + const int a; + unsigned b : 20; +}; + +static union U u = { 0x12345678 }; + +/* Constant folding used to fail to account for endianness when folding a + union. */ + +int +main (void) +{ +#ifdef __BYTE_ORDER__ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return u.b - 0x45678; +#else + return u.b - 0x12345; +#endif +#endif + return 0; +} Is it ok for trunk? Best regards, Thomas