Message ID | 20190716085643.wnqot6j7dkcp2mva@kam.mff.cuni.cz |
---|---|
State | New |
Headers | show |
Series | Make alias sets of ODR types more precise | expand |
On Tue, 16 Jul 2019, Jan Hubicka wrote: > Hi, > this is the hunk we omitted from the original patch enabling TBAA for > ODR types. Currently record_component_aliases record all pointers as > void *. This is because canonical type merging handles them this way > and thus it may merge for example > > strut a { int *ptr;}; > > and > > struct b { short *ptr;}; > > into one canonical type. The alias set of that canonical type then must > conflict with both int * and short * which we do by globing it to void * > which conflict with everything. > > For ODR types where we do canonical types based on their name we however > assign differnt TYPE_CANONICAL to each of them. Thanks to this we can > make alias set to contain int * or short * respectively. > > > Bootstrapped/regtested x86_64-linux, OK? OK. Richard. > Honza > * alias.c (record_component_aliases): Do not simplify pointed-to > types of ODR types > * testsuite/g++.dg/lto/alias-4_0.C > Index: alias.c > =================================================================== > --- alias.c (revision 273478) > +++ alias.c (working copy) > @@ -1202,47 +1202,52 @@ record_component_aliases (tree type) > case RECORD_TYPE: > case UNION_TYPE: > case QUAL_UNION_TYPE: > - for (field = TYPE_FIELDS (type); field != 0; field = DECL_CHAIN (field)) > - if (TREE_CODE (field) == FIELD_DECL && !DECL_NONADDRESSABLE_P (field)) > - { > - /* LTO type merging does not make any difference between > - component pointer types. We may have > - > - struct foo {int *a;}; > - > - as TYPE_CANONICAL of > - > - struct bar {float *a;}; > - > - Because accesses to int * and float * do not alias, we would get > - false negative when accessing the same memory location by > - float ** and bar *. We thus record the canonical type as: > - > - struct {void *a;}; > - > - void * is special cased and works as a universal pointer type. > - Accesses to it conflicts with accesses to any other pointer > - type. */ > - tree t = TREE_TYPE (field); > - if (in_lto_p) > - { > - /* VECTOR_TYPE and ARRAY_TYPE share the alias set with their > - element type and that type has to be normalized to void *, > - too, in the case it is a pointer. */ > - while (!canonical_type_used_p (t) && !POINTER_TYPE_P (t)) > - { > - gcc_checking_assert (TYPE_STRUCTURAL_EQUALITY_P (t)); > - t = TREE_TYPE (t); > - } > - if (POINTER_TYPE_P (t)) > - t = ptr_type_node; > - else if (flag_checking) > - gcc_checking_assert (get_alias_set (t) > - == get_alias_set (TREE_TYPE (field))); > - } > - > - record_alias_subset (superset, get_alias_set (t)); > - } > + { > + /* LTO non-ODR type merging does not make any difference between > + component pointer types. We may have > + > + struct foo {int *a;}; > + > + as TYPE_CANONICAL of > + > + struct bar {float *a;}; > + > + Because accesses to int * and float * do not alias, we would get > + false negative when accessing the same memory location by > + float ** and bar *. We thus record the canonical type as: > + > + struct {void *a;}; > + > + void * is special cased and works as a universal pointer type. > + Accesses to it conflicts with accesses to any other pointer > + type. */ > + bool void_pointers = in_lto_p > + && (!odr_type_p (type) > + || !odr_based_tbaa_p (type)); > + for (field = TYPE_FIELDS (type); field != 0; field = DECL_CHAIN (field)) > + if (TREE_CODE (field) == FIELD_DECL && !DECL_NONADDRESSABLE_P (field)) > + { > + tree t = TREE_TYPE (field); > + if (void_pointers) > + { > + /* VECTOR_TYPE and ARRAY_TYPE share the alias set with their > + element type and that type has to be normalized to void *, > + too, in the case it is a pointer. */ > + while (!canonical_type_used_p (t) && !POINTER_TYPE_P (t)) > + { > + gcc_checking_assert (TYPE_STRUCTURAL_EQUALITY_P (t)); > + t = TREE_TYPE (t); > + } > + if (POINTER_TYPE_P (t)) > + t = ptr_type_node; > + else if (flag_checking) > + gcc_checking_assert (get_alias_set (t) > + == get_alias_set (TREE_TYPE (field))); > + } > + > + record_alias_subset (superset, get_alias_set (t)); > + } > + } > break; > > case COMPLEX_TYPE: > > Index: testsuite/g++.dg/lto/alias-4_0.C > =================================================================== > --- testsuite/g++.dg/lto/alias-4_0.C (nonexistent) > +++ testsuite/g++.dg/lto/alias-4_0.C (working copy) > @@ -0,0 +1,31 @@ > +/* { dg-lto-do run } */ > +/* { dg-lto-options { { -O3 -flto -fno-early-inlining } } } */ > +__attribute__ ((used)) > +short *ptr_init, **ptr=&ptr_init; > + > +__attribute__ ((used)) > +struct a { > + int *aptr; > +} a, *aptr=&a; > + > +void > +write_ptr () > +{ > + *aptr = a; > +} > + > +__attribute__ ((used)) > +void > +test () > +{ > + *ptr = (short int *)0; > + write_ptr (); > + if (!__builtin_constant_p (*ptr == (void *)0)) > + __builtin_abort (); > +} > +int > +main() > +{ > + test (); > + return 0; > +} >
Index: alias.c =================================================================== --- alias.c (revision 273478) +++ alias.c (working copy) @@ -1202,47 +1202,52 @@ record_component_aliases (tree type) case RECORD_TYPE: case UNION_TYPE: case QUAL_UNION_TYPE: - for (field = TYPE_FIELDS (type); field != 0; field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL && !DECL_NONADDRESSABLE_P (field)) - { - /* LTO type merging does not make any difference between - component pointer types. We may have - - struct foo {int *a;}; - - as TYPE_CANONICAL of - - struct bar {float *a;}; - - Because accesses to int * and float * do not alias, we would get - false negative when accessing the same memory location by - float ** and bar *. We thus record the canonical type as: - - struct {void *a;}; - - void * is special cased and works as a universal pointer type. - Accesses to it conflicts with accesses to any other pointer - type. */ - tree t = TREE_TYPE (field); - if (in_lto_p) - { - /* VECTOR_TYPE and ARRAY_TYPE share the alias set with their - element type and that type has to be normalized to void *, - too, in the case it is a pointer. */ - while (!canonical_type_used_p (t) && !POINTER_TYPE_P (t)) - { - gcc_checking_assert (TYPE_STRUCTURAL_EQUALITY_P (t)); - t = TREE_TYPE (t); - } - if (POINTER_TYPE_P (t)) - t = ptr_type_node; - else if (flag_checking) - gcc_checking_assert (get_alias_set (t) - == get_alias_set (TREE_TYPE (field))); - } - - record_alias_subset (superset, get_alias_set (t)); - } + { + /* LTO non-ODR type merging does not make any difference between + component pointer types. We may have + + struct foo {int *a;}; + + as TYPE_CANONICAL of + + struct bar {float *a;}; + + Because accesses to int * and float * do not alias, we would get + false negative when accessing the same memory location by + float ** and bar *. We thus record the canonical type as: + + struct {void *a;}; + + void * is special cased and works as a universal pointer type. + Accesses to it conflicts with accesses to any other pointer + type. */ + bool void_pointers = in_lto_p + && (!odr_type_p (type) + || !odr_based_tbaa_p (type)); + for (field = TYPE_FIELDS (type); field != 0; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL && !DECL_NONADDRESSABLE_P (field)) + { + tree t = TREE_TYPE (field); + if (void_pointers) + { + /* VECTOR_TYPE and ARRAY_TYPE share the alias set with their + element type and that type has to be normalized to void *, + too, in the case it is a pointer. */ + while (!canonical_type_used_p (t) && !POINTER_TYPE_P (t)) + { + gcc_checking_assert (TYPE_STRUCTURAL_EQUALITY_P (t)); + t = TREE_TYPE (t); + } + if (POINTER_TYPE_P (t)) + t = ptr_type_node; + else if (flag_checking) + gcc_checking_assert (get_alias_set (t) + == get_alias_set (TREE_TYPE (field))); + } + + record_alias_subset (superset, get_alias_set (t)); + } + } break; case COMPLEX_TYPE: Index: testsuite/g++.dg/lto/alias-4_0.C =================================================================== --- testsuite/g++.dg/lto/alias-4_0.C (nonexistent) +++ testsuite/g++.dg/lto/alias-4_0.C (working copy) @@ -0,0 +1,31 @@ +/* { dg-lto-do run } */ +/* { dg-lto-options { { -O3 -flto -fno-early-inlining } } } */ +__attribute__ ((used)) +short *ptr_init, **ptr=&ptr_init; + +__attribute__ ((used)) +struct a { + int *aptr; +} a, *aptr=&a; + +void +write_ptr () +{ + *aptr = a; +} + +__attribute__ ((used)) +void +test () +{ + *ptr = (short int *)0; + write_ptr (); + if (!__builtin_constant_p (*ptr == (void *)0)) + __builtin_abort (); +} +int +main() +{ + test (); + return 0; +}