From: Richard Biener <rguenther@suse.de>
To: Jan Hubicka <hubicka@ucw.cz>
Cc: Bernd Schmidt <bschmidt@redhat.com>, gcc-patches@gcc.gnu.org
Subject: Re: Enable pointer TBAA for LTO
Date: Mon, 23 Nov 2015 10:39:00 -0000 [thread overview]
Message-ID: <alpine.LSU.2.11.1511231131480.4884@t29.fhfr.qr> (raw)
In-Reply-To: <20151122230025.GA85269@kam.mff.cuni.cz>
On Mon, 23 Nov 2015, Jan Hubicka wrote:
> Hi,
> here is updated patch which I finally comitted today. It addresses all the comments
> and also fixes one nasty bug that really cost me a lot of time to understand.
>
> + /* 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. */
>
> This problem manifested itself only as a lto-bootstrap miscompare on 32bit
> build and I spent a lot of time localizing the wrong code since it reproduces
> only in quite large programs where we get conficts in canonical type merging
> like this.
>
> The patch thus updates record_component_aliases to substitute
> void_ptr_type for all pointer types. I re-did the stats. Now the
> improvement on dealII is 14% that is quite a bit lower than earlier, but
> still substantial. Since we have voidptr globing counter, I know that
> the number of disambiguations would go at least 19% up if we did not do
> it.
Please in future leave patches for review again if you do such
big changes before committing...
I don't understand why we need this (testcase?) because get_alias_set ()
is supposed to do the alias-set of pointer globbing for us.
Thanks,
Richard.
> THere is a lot of low hanging fruit in that area now, but the real
> solution is to track types that needs to be merge by fortran rules and
> don't do all this fancy globing for C/C++ types. I will open branch for
> IPA work and try to prepare this for next stage 1.
>
> bootstrapped/regtested x86_64-linux and ppc64-linux, earlier version tested on i386-linux
> and also on some bigger apps, committed
>
> Note that we still have bootstrap miscompare with LTO build and --disable-checking,
> I am looking for that now. Additoinally after fixing the ICEs preventing us to build
> the gnat1 binary, gnat1 aborts. Both these are independent of the patch.
>
> Honza
> * lto.c (iterative_hash_canonical_type): Always recurse for pointers.
> (gimple_register_canonical_type_1): Check that pointers do not get
> canonical types.
> (gimple_register_canonical_type): Do not register pointers.
>
> * tree.c (build_pointer_type_for_mode,build_reference_type_for_mode):
> In LTO we do not compute TYPE_CANONICAL of pointers.
> (gimple_canonical_types_compatible_p): Improve coments; sanity check
> that pointers do not have canonical type that would make us believe
> they are different.
> * alias.c (get_alias_set): Do structural type equality on pointers;
> enable pointer path for LTO; also glob pointer to vector with pointer
> to vector element; glob pointers and references for LTO; do more strict
> sanity checking about build_pointer_type returning the canonical type
> which is also the main variant.
> (record_component_aliases): When component type is pointer and we
> do LTO; record void_type_node alias set.
> Index: tree.c
> ===================================================================
> --- tree.c (revision 230714)
> +++ tree.c (working copy)
> @@ -7919,7 +7919,8 @@ build_pointer_type_for_mode (tree to_typ
> TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (to_type);
> TYPE_POINTER_TO (to_type) = t;
>
> - if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
> + /* During LTO we do not set TYPE_CANONICAL of pointers and references. */
> + if (TYPE_STRUCTURAL_EQUALITY_P (to_type) || in_lto_p)
> SET_TYPE_STRUCTURAL_EQUALITY (t);
> else if (TYPE_CANONICAL (to_type) != to_type || could_alias)
> TYPE_CANONICAL (t)
> @@ -7987,7 +7988,8 @@ build_reference_type_for_mode (tree to_t
> TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (to_type);
> TYPE_REFERENCE_TO (to_type) = t;
>
> - if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
> + /* During LTO we do not set TYPE_CANONICAL of pointers and references. */
> + if (TYPE_STRUCTURAL_EQUALITY_P (to_type) || in_lto_p)
> SET_TYPE_STRUCTURAL_EQUALITY (t);
> else if (TYPE_CANONICAL (to_type) != to_type || could_alias)
> TYPE_CANONICAL (t)
> @@ -13224,7 +13226,9 @@ type_with_interoperable_signedness (cons
> TBAA is concerned.
> This function is used both by lto.c canonical type merging and by the
> verifier. If TRUST_TYPE_CANONICAL we do not look into structure of types
> - that have TYPE_CANONICAL defined and assume them equivalent. */
> + that have TYPE_CANONICAL defined and assume them equivalent. This is useful
> + only for LTO because only in these cases TYPE_CANONICAL equivalence
> + correspond to one defined by gimple_canonical_types_compatible_p. */
>
> bool
> gimple_canonical_types_compatible_p (const_tree t1, const_tree t2,
> @@ -13265,9 +13269,19 @@ gimple_canonical_types_compatible_p (con
> || (type_with_alias_set_p (t1) && type_with_alias_set_p (t2)));
> /* If the types have been previously registered and found equal
> they still are. */
> +
> if (TYPE_CANONICAL (t1) && TYPE_CANONICAL (t2)
> && trust_type_canonical)
> - return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
> + {
> + /* Do not use TYPE_CANONICAL of pointer types. For LTO streamed types
> + they are always NULL, but they are set to non-NULL for types
> + constructed by build_pointer_type and variants. In this case the
> + TYPE_CANONICAL is more fine grained than the equivalnce we test (where
> + all pointers are considered equal. Be sure to not return false
> + negatives. */
> + gcc_checking_assert (!POINTER_TYPE_P (t1) && !POINTER_TYPE_P (t2));
> + return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
> + }
>
> /* Can't be the same type if the types don't have the same code. */
> enum tree_code code = tree_code_for_canonical_type_merging (TREE_CODE (t1));
> Index: lto/lto.c
> ===================================================================
> --- lto/lto.c (revision 230714)
> +++ lto/lto.c (working copy)
> @@ -388,8 +388,13 @@ iterative_hash_canonical_type (tree type
>
> /* All type variants have same TYPE_CANONICAL. */
> type = TYPE_MAIN_VARIANT (type);
> +
> + /* We do not compute TYPE_CANONICAl of POINTER_TYPE because the aliasing
> + code never use it anyway. */
> + if (POINTER_TYPE_P (type))
> + v = hash_canonical_type (type);
> /* An already processed type. */
> - if (TYPE_CANONICAL (type))
> + else if (TYPE_CANONICAL (type))
> {
> type = TYPE_CANONICAL (type);
> v = gimple_canonical_type_hash (type);
> @@ -437,7 +442,9 @@ gimple_register_canonical_type_1 (tree t
> {
> void **slot;
>
> - gcc_checking_assert (TYPE_P (t) && !TYPE_CANONICAL (t));
> + gcc_checking_assert (TYPE_P (t) && !TYPE_CANONICAL (t)
> + && type_with_alias_set_p (t)
> + && !POINTER_TYPE_P (t));
>
> slot = htab_find_slot_with_hash (gimple_canonical_types, t, hash, INSERT);
> if (*slot)
> @@ -470,7 +477,7 @@ gimple_register_canonical_type_1 (tree t
> static void
> gimple_register_canonical_type (tree t)
> {
> - if (TYPE_CANONICAL (t) || !type_with_alias_set_p (t))
> + if (TYPE_CANONICAL (t) || !type_with_alias_set_p (t) || POINTER_TYPE_P (t))
> return;
>
> /* Canonical types are same among all complete variants. */
> Index: alias.c
> ===================================================================
> --- alias.c (revision 230714)
> +++ alias.c (working copy)
> @@ -869,13 +869,23 @@ get_alias_set (tree t)
> set = lang_hooks.get_alias_set (t);
> if (set != -1)
> return set;
> - return 0;
> + /* Handle structure type equality for pointer types. This is easy
> + to do, because the code bellow ignore canonical types on these anyway.
> + This is important for LTO, where TYPE_CANONICAL for pointers can not
> + be meaningfuly computed by the frotnend. */
> + if (!POINTER_TYPE_P (t))
> + {
> + /* In LTO we set canonical types for all types where it makes
> + sense to do so. Double check we did not miss some type. */
> + gcc_checking_assert (!in_lto_p || !type_with_alias_set_p (t));
> + return 0;
> + }
> + }
> + else
> + {
> + t = TYPE_CANONICAL (t);
> + gcc_checking_assert (!TYPE_STRUCTURAL_EQUALITY_P (t));
> }
> -
> - t = TYPE_CANONICAL (t);
> -
> - /* The canonical type should not require structural equality checks. */
> - gcc_checking_assert (!TYPE_STRUCTURAL_EQUALITY_P (t));
>
> /* If this is a type with a known alias set, return it. */
> if (TYPE_ALIAS_SET_KNOWN_P (t))
> @@ -952,20 +962,23 @@ get_alias_set (tree t)
> ptr_type_node but that is a bad idea, because it prevents disabiguations
> in between pointers. For Firefox this accounts about 20% of all
> disambiguations in the program. */
> - else if (POINTER_TYPE_P (t) && t != ptr_type_node && !in_lto_p)
> + else if (POINTER_TYPE_P (t) && t != ptr_type_node)
> {
> tree p;
> auto_vec <bool, 8> reference;
>
> /* Unnest all pointers and references.
> - We also want to make pointer to array equivalent to pointer to its
> - element. So skip all array types, too. */
> + We also want to make pointer to array/vector equivalent to pointer to
> + its element (see the reasoning above). Skip all those types, too. */
> for (p = t; POINTER_TYPE_P (p)
> - || (TREE_CODE (p) == ARRAY_TYPE && !TYPE_NONALIASED_COMPONENT (p));
> + || (TREE_CODE (p) == ARRAY_TYPE && !TYPE_NONALIASED_COMPONENT (p))
> + || TREE_CODE (p) == VECTOR_TYPE;
> p = TREE_TYPE (p))
> {
> if (TREE_CODE (p) == REFERENCE_TYPE)
> - reference.safe_push (true);
> + /* In LTO we want languages that use references to be compatible
> + with languages that use pointers. */
> + reference.safe_push (true && !in_lto_p);
> if (TREE_CODE (p) == POINTER_TYPE)
> reference.safe_push (false);
> }
> @@ -981,7 +994,7 @@ get_alias_set (tree t)
> set = get_alias_set (ptr_type_node);
> else
> {
> - /* Rebuild pointer type from starting from canonical types using
> + /* Rebuild pointer type starting from canonical types using
> unqualified pointers and references only. This way all such
> pointers will have the same alias set and will conflict with
> each other.
> @@ -998,9 +1011,15 @@ get_alias_set (tree t)
> p = build_reference_type (p);
> else
> p = build_pointer_type (p);
> - p = TYPE_CANONICAL (TYPE_MAIN_VARIANT (p));
> + gcc_checking_assert (p == TYPE_MAIN_VARIANT (p));
> + /* build_pointer_type should always return the canonical type.
> + For LTO TYPE_CANOINCAL may be NULL, because we do not compute
> + them. Be sure that frontends do not glob canonical types of
> + pointers in unexpected way and that p == TYPE_CANONICAL (p)
> + in all other cases. */
> + gcc_checking_assert (!TYPE_CANONICAL (p)
> + || p == TYPE_CANONICAL (p));
> }
> - gcc_checking_assert (TYPE_CANONICAL (p) == p);
>
> /* Assign the alias set to both p and t.
> We can not call get_alias_set (p) here as that would trigger
> @@ -1015,11 +1034,12 @@ get_alias_set (tree t)
> }
> }
> }
> - /* In LTO the rules above needs to be part of canonical type machinery.
> - For now just punt. */
> - else if (POINTER_TYPE_P (t)
> - && t != TYPE_CANONICAL (ptr_type_node) && in_lto_p)
> - set = get_alias_set (TYPE_CANONICAL (ptr_type_node));
> + /* Alias set of ptr_type_node is special and serve as universal pointer which
> + is TBAA compatible with every other pointer type. Be sure we have the
> + alias set built even for LTO which otherwise keeps all TYPE_CANONICAL
> + of pointer types NULL. */
> + else if (t == ptr_type_node)
> + set = new_alias_set ();
>
> /* Otherwise make a new alias set for this type. */
> else
> @@ -1155,7 +1175,42 @@ record_component_aliases (tree 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))
> - record_alias_subset (superset, get_alias_set (TREE_TYPE (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 ((TREE_CODE (t) == ARRAY_TYPE
> + && (!COMPLETE_TYPE_P (t)
> + || TYPE_NONALIASED_COMPONENT (t)))
> + || TREE_CODE (t) == VECTOR_TYPE)
> + t = TREE_TYPE (t);
> + if (POINTER_TYPE_P (t))
> + t = ptr_type_node;
> + }
> +
> + record_alias_subset (superset, get_alias_set (t));
> + }
> break;
>
> case COMPLEX_TYPE:
>
>
--
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)
next prev parent reply other threads:[~2015-11-23 10:36 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-11-08 20:46 Jan Hubicka
2015-11-10 12:27 ` Richard Biener
2015-11-10 18:15 ` Jan Hubicka
2015-11-11 9:21 ` Richard Biener
2015-11-11 12:43 ` Bernd Schmidt
2015-11-11 22:14 ` Jan Hubicka
2015-11-11 22:31 ` Jan Hubicka
2015-11-22 23:19 ` Jan Hubicka
2015-11-22 23:22 ` Eric Botcazou
2015-11-23 1:20 ` Jan Hubicka
2015-11-23 8:34 ` Eric Botcazou
2015-11-23 17:26 ` Jan Hubicka
2015-11-23 10:39 ` Richard Biener [this message]
2015-11-23 17:08 ` Jan Hubicka
2015-11-24 8:34 ` Richard Biener
2015-11-24 19:05 ` Jan Hubicka
2015-11-25 10:49 ` Richard Biener
2015-11-25 18:35 ` Jan Hubicka
2015-11-24 5:01 ` Jan Hubicka
2015-11-23 13:52 ` Martin Jambor
2015-11-23 15:33 ` Richard Biener
2015-11-23 15:35 ` Ilya Verbin
2015-11-27 8:24 ` Thomas Schwinge
2015-11-23 16:52 ` Jan Hubicka
2015-11-23 17:18 ` Richard Biener
2015-11-24 6:23 ` Jan Hubicka
2015-11-24 8:38 ` Richard Biener
2015-11-25 10:10 ` James Greenhalgh
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=alpine.LSU.2.11.1511231131480.4884@t29.fhfr.qr \
--to=rguenther@suse.de \
--cc=bschmidt@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=hubicka@ucw.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).