The following implements Jasons suggestion of using a langhook to return the size of an aggregate without tail padding that might be re-used when it is inherited from.
Using this langhook we can fix the size of the representative for the bitfield properly and thus generate correct code for the testcase. Previously on x86_64 it was main: movl c+4(%rip), %eax andl $-258049, %eax orb $16, %ah movl %eax, c+4(%rip) movb $2, c+7(%rip) xorl %eax, %eax ret while after the patch we see main: movzbl c+5(%rip), %eax andb $-4, c+6(%rip) movb $2, c+7(%rip) andl $15, %eax orl $16, %eax movb %al, c+5(%rip) xorl %eax, %eax ret in particular the store to C::B::d is now properly using a byte store. Bootstrap and regtest in progress on x86_64-unknown-linux-gnu, ok for trunk? Thanks, Richard. 2016-12-14 Richard Biener <rguent...@suse.de> PR c++/71694 * langhooks-def.h (lhd_unit_size_without_reusable_padding): Declare. (LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING): Define. (LANG_HOOKS_FOR_TYPES_INITIALIZER): Adjust. * langhooks.h (struct lang_hooks_for_types): Add unit_size_without_reusable_padding. * langhooks.c (lhd_unit_size_without_reusable_padding): New. * stor-layout.c (finish_bitfield_representative): Use unit_size_without_reusable_padding langhook to decide on the last representatives size. cp/ * cp-objcp-common.h (cp_unit_size_without_reusable_padding): Declare. (LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING): Define. * cp-objcp-common.c (cp_unit_size_without_reusable_padding): New. * g++.dg/pr71694.C: New testcase. Index: gcc/langhooks-def.h =================================================================== *** gcc/langhooks-def.h (revision 243632) --- gcc/langhooks-def.h (working copy) *************** extern tree lhd_make_node (enum tree_cod *** 161,166 **** --- 161,168 ---- /* Types hooks. There are no reasonable defaults for most of them, so we create a compile-time error instead. */ + extern tree lhd_unit_size_without_reusable_padding (tree); + #define LANG_HOOKS_MAKE_TYPE lhd_make_node #define LANG_HOOKS_CLASSIFY_RECORD NULL #define LANG_HOOKS_INCOMPLETE_TYPE_ERROR lhd_incomplete_type_error *************** extern tree lhd_make_node (enum tree_cod *** 189,194 **** --- 191,197 ---- #define LANG_HOOKS_GET_DEBUG_TYPE NULL #define LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO NULL #define LANG_HOOKS_TYPE_DWARF_ATTRIBUTE lhd_type_dwarf_attribute + #define LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING lhd_unit_size_without_reusable_padding #define LANG_HOOKS_FOR_TYPES_INITIALIZER { \ LANG_HOOKS_MAKE_TYPE, \ *************** extern tree lhd_make_node (enum tree_cod *** 212,218 **** LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE, \ LANG_HOOKS_GET_DEBUG_TYPE, \ LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO, \ ! LANG_HOOKS_TYPE_DWARF_ATTRIBUTE \ } /* Declaration hooks. */ --- 215,222 ---- LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE, \ LANG_HOOKS_GET_DEBUG_TYPE, \ LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO, \ ! LANG_HOOKS_TYPE_DWARF_ATTRIBUTE, \ ! LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING \ } /* Declaration hooks. */ Index: gcc/langhooks.h =================================================================== *** gcc/langhooks.h (revision 243632) --- gcc/langhooks.h (working copy) *************** struct lang_hooks_for_types *** 166,171 **** --- 166,175 ---- /* Returns -1 if dwarf ATTR shouldn't be added for TYPE, or the attribute value otherwise. */ int (*type_dwarf_attribute) (const_tree, int); + + /* Returns a tree for the unit size of T excluding tail padding that + might be used by objects inheriting from T. */ + tree (*unit_size_without_reusable_padding) (tree); }; /* Language hooks related to decls and the symbol table. */ Index: gcc/langhooks.c =================================================================== *** gcc/langhooks.c (revision 243632) --- gcc/langhooks.c (working copy) *************** lhd_type_dwarf_attribute (const_tree, in *** 729,734 **** --- 729,743 ---- return -1; } + /* Default implementation of LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING. + Just return TYPE_SIZE_UNIT unadjusted. */ + + tree + lhd_unit_size_without_reusable_padding (tree t) + { + return TYPE_SIZE_UNIT (t); + } + /* Returns true if the current lang_hooks represents the GNU C frontend. */ bool Index: gcc/stor-layout.c =================================================================== *** gcc/stor-layout.c (revision 243632) --- gcc/stor-layout.c (working copy) *************** finish_bitfield_representative (tree rep *** 1864,1876 **** } else { ! /* ??? If you consider that tail-padding of this struct might be ! re-used when deriving from it we cannot really do the following ! and thus need to set maxsize to bitsize? Also we cannot ! generally rely on maxsize to fold to an integer constant, so ! use bitsize as fallback for this case. */ ! tree maxsize = size_diffop (TYPE_SIZE_UNIT (DECL_CONTEXT (field)), ! DECL_FIELD_OFFSET (repr)); if (tree_fits_uhwi_p (maxsize)) maxbitsize = (tree_to_uhwi (maxsize) * BITS_PER_UNIT - tree_to_uhwi (DECL_FIELD_BIT_OFFSET (repr))); --- 1864,1877 ---- } else { ! /* Note that if the C++ FE sets up tail-padding to be re-used it ! creates a as-base variant of the type with TYPE_SIZE adjusted ! accordingly. So it is safe to include tail-padding here. */ ! tree aggsize = lang_hooks.types.unit_size_without_reusable_padding ! (DECL_CONTEXT (field)); ! tree maxsize = size_diffop (aggsize, DECL_FIELD_OFFSET (repr)); ! /* We cannot generally rely on maxsize to fold to an integer constant, ! so use bitsize as fallback for this case. */ if (tree_fits_uhwi_p (maxsize)) maxbitsize = (tree_to_uhwi (maxsize) * BITS_PER_UNIT - tree_to_uhwi (DECL_FIELD_BIT_OFFSET (repr))); Index: gcc/cp/cp-objcp-common.c =================================================================== *** gcc/cp/cp-objcp-common.c (revision 243632) --- gcc/cp/cp-objcp-common.c (working copy) *************** cp_type_dwarf_attribute (const_tree type *** 252,257 **** --- 252,267 ---- return -1; } + /* Return the unit size of TYPE without reusable tail padding. */ + + tree + cp_unit_size_without_reusable_padding (tree type) + { + if (CLASS_TYPE_P (type)) + return CLASSTYPE_SIZE_UNIT (type); + return TYPE_SIZE_UNIT (type); + } + /* Stubs to keep c-opts.c happy. */ void push_file_scope (void) Index: gcc/cp/cp-objcp-common.h =================================================================== *** gcc/cp/cp-objcp-common.h (revision 243632) --- gcc/cp/cp-objcp-common.h (working copy) *************** extern tree objcp_tsubst_copy_and_build *** 30,35 **** --- 30,36 ---- extern int cp_decl_dwarf_attribute (const_tree, int); extern int cp_type_dwarf_attribute (const_tree, int); extern void cp_common_init_ts (void); + extern tree cp_unit_size_without_reusable_padding (tree); /* Lang hooks that are shared between C++ and ObjC++ are defined here. Hooks specific to C++ or ObjC++ go in cp/cp-lang.c and objcp/objcp-lang.c, *************** extern void cp_common_init_ts (void); *** 137,142 **** --- 138,146 ---- #define LANG_HOOKS_DECL_DWARF_ATTRIBUTE cp_decl_dwarf_attribute #undef LANG_HOOKS_TYPE_DWARF_ATTRIBUTE #define LANG_HOOKS_TYPE_DWARF_ATTRIBUTE cp_type_dwarf_attribute + #undef LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING + #define LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING cp_unit_size_without_reusable_padding + #undef LANG_HOOKS_OMP_PREDETERMINED_SHARING #define LANG_HOOKS_OMP_PREDETERMINED_SHARING cxx_omp_predetermined_sharing #undef LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR Index: gcc/testsuite/g++.dg/pr71694.C =================================================================== *** gcc/testsuite/g++.dg/pr71694.C (revision 0) --- gcc/testsuite/g++.dg/pr71694.C (working copy) *************** *** 0 **** --- 1,27 ---- + /* { dg-do compile } */ + /* { dg-options "-O2" } */ + + struct B { + B() {} + int x; + int a : 6; + int b : 6; + int c : 6; + }; + + struct C : B { + char d; + }; + + C c; + + int main() + { + /* We have to make sure to not cause a store data race between + c.c and c.d residing in the tail padding of B. */ + c.c = 1; + c.d = 2; + } + + /* In particular on x86 c.d should not be loaded/stored via movl. */ + /* { dg-final { scan-assembler-not "movl" { target { x86_64-*-* i?86-*-* } } } } */