Do less generous pointer globbing in alias.c

Martin Liška mliska@suse.cz
Wed Jun 10 11:38:00 GMT 2015


On 05/27/2015 07:28 AM, Jan Hubicka wrote:
> Hi,
> this patch makes it possible for non-LTO alias oracle to TBAA disambiguate
> pointer types. It makes void * conflicting with all of them and does not put it
> to alias set 0. It also preserves the property that qualifiers of pointer-to
> type should not matter to determine the alias set and that pointer to array is
> same as pointer to array element.  Finally it makes pointer void * to be
> equivalent to void ** (and more *) and to types with structural equality only.
> 
> I think those are all globbing rules we discussed for the non-LTO patch.
> 
> It does two things.  First is kind of "canonicalization" where for a given pointer
> it looks for non-pointer pointed-to type and then rebuilds is without qualifiers.
> This is fast, because build_pointer_type will reuse existing types.
> 
> It makes void * to conflict with everyting by making its alias set to be subset
> of alias set of any other pointer.  This means that writes to void * conflict
> with writes to any other pointer without really need to glob all the pointers
> to one equivalence class.
> 
> This patch makes quite some difference on C++.  For example on deal II the TBAA
> stats reports 4344358 disambiguations and 7008576 queries, while with the patch
> we get 5368737 and 5687399 queries (I did not chose deal II for reason, it is
> just random C++ file)
> 
> The patch bootstrap and regtests ppc64le-linux with the following testsuite
> differences:
> @@ -30,7 +30,9 @@
>  FAIL: c-c++-common/asan/null-deref-1.c   -O3 -g  output pattern test, is ASAN:SIGSEGV
>  FAIL: c-c++-common/asan/null-deref-1.c   -Os  output pattern test, is ASAN:SIGSEGV
>  FAIL: gcc.dg/cpp/_Pragma3.c (test for excess errors)
> +XPASS: gcc.dg/alias-8.c  (test for warnings, line 11)
>  FAIL: gcc.dg/loop-8.c scan-rtl-dump-times loop2_invariant "Decided" 1
> +FAIL: gcc.dg/pr62167.c scan-tree-dump-not pre "Removing basic block"
>  FAIL: gcc.dg/sms-4.c scan-rtl-dump-times sms "SMS succeeded" 1
>  XPASS: gcc.dg/guality/example.c   -O0  execution test
>  XPASS: gcc.dg/guality/example.c   -O1  execution test
> @@ -304,6 +306,9 @@
>  FAIL: c-c++-common/asan/null-deref-1.c   -O3 -g  output pattern test, is ASAN:SIGSEGV
>  FAIL: g++.dg/cpp1y/vla-initlist1.C  -std=gnu++11 execution test
>  FAIL: g++.dg/cpp1y/vla-initlist1.C  -std=gnu++14 execution test
> +FAIL: g++.dg/ipa/ipa-icf-4.C  -std=gnu++11  scan-ipa-dump icf "Equal symbols: [67]"
> +FAIL: g++.dg/ipa/ipa-icf-4.C  -std=gnu++14  scan-ipa-dump icf "Equal symbols: [67]"
> +FAIL: g++.dg/ipa/ipa-icf-4.C  -std=gnu++98  scan-ipa-dump icf "Equal symbols: [67]"
> 
> ipa-icf-4 is about alias info now being more perceptive to block the merging.
> pr62167 seems just confused.  The template checks that memory stores are not
> unified.  It looks for BB removal message, but with the patch we get:
>   <bb 2>:
>   node.next = 0B;
>   head.0_4 = head;
>   node.prev = head.0_4;
>   head.0_4->first = &node;
>   k.1_7 = k;
>   h_8 = &heads[k.1_7];
>   heads[2].first = 0B;
>   if (head.0_4 == h_8)
>     goto <bb 3>;
>   else
>     goto <bb 5>;
> 
>   <bb 5>:
>   goto <bb 4>;
> 
>   <bb 3>:
>   p_10 = MEM[(struct head *)&heads][k.1_7].first;
> 
>   <bb 4>:
>   # p_1 = PHI <p_10(3), &node(5)>
>   _11 = p_1 != 0B;
>   _12 = (int) _11;
>   return _12;
> 
> before PR, the message is about the bb 5 sitting at critical edge removed.
> The TBAA incompatible load it looks for is optimized away by FRE:
>   head->first = &node;
> 
>   struct node *n = head->first;
> 
>   struct head *h = &heads[k];
> 
>   heads[2].first = n->next;
> 
>   if ((void*)n->prev == (void *)h)
>     p = h->first;
>   else
>     /* Dead tbaa-unsafe load from ((struct node *)&heads[2])->next.  */
>     p = n->prev->next;
> 
> here n is known to be head->first that is known to be &node.
> The testcase runtime checks that result is Ok and passes.
> 
> Bootstrapped/regtested ppc64le-linux.
> 
> 	* alias.c (get_alias_set): Do not glob all pointer types into one;
> 	just produce euqivalence classes based on canonical type of pointed
> 	type type; make void * equivalent to void **.
> 	(record_component_aliases): Make void * to conflict with all other
> 	pointer types.
> Index: alias.c
> ===================================================================
> --- alias.c	(revision 223633)
> +++ alias.c	(working copy)
> @@ -903,35 +906,79 @@ get_alias_set (tree t)
>       the pointed-to types.  This issue has been reported to the
>       C++ committee.
>  
> -     In addition to the above canonicalization issue, with LTO
> -     we should also canonicalize `T (*)[]' to `T *' avoiding
> -     alias issues with pointer-to element types and pointer-to
> -     array types.
> -
> -     Likewise we need to deal with the situation of incomplete
> -     pointed-to types and make `*(struct X **)&a' and
> -     `*(struct X {} **)&a' alias.  Otherwise we will have to
> -     guarantee that all pointer-to incomplete type variants
> -     will be replaced by pointer-to complete type variants if
> -     they are available.
> -
> -     With LTO the convenient situation of using `void *' to
> -     access and store any pointer type will also become
> -     more apparent (and `void *' is just another pointer-to
> -     incomplete type).  Assigning alias-set zero to `void *'
> -     and all pointer-to incomplete types is a not appealing
> -     solution.  Assigning an effective alias-set zero only
> -     affecting pointers might be - by recording proper subset
> -     relationships of all pointer alias-sets.
> -
> -     Pointer-to function types are another grey area which
> -     needs caution.  Globbing them all into one alias-set
> -     or the above effective zero set would work.
> -
> -     For now just assign the same alias-set to all pointers.
> -     That's simple and avoids all the above problems.  */
> -  else if (POINTER_TYPE_P (t)
> -	   && t != ptr_type_node)
> +     For this reason go to canonical type of the unqalified pointer type.
> +     Until GCC 6 this code set all pointers sets to have alias set of
> +     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)
> +    {
> +      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.  */
> +      for (p = t; POINTER_TYPE_P (p)
> +	   || (TREE_CODE (p) == ARRAY_TYPE && !TYPE_NONALIASED_COMPONENT (p));
> +	   p = TREE_TYPE (p))
> +	{
> +	  if (TREE_CODE (p) == REFERENCE_TYPE)
> +	    reference.safe_push (true);
> +	  if (TREE_CODE (p) == POINTER_TYPE)
> +	    reference.safe_push (false);
> +	}
> +      p = TYPE_MAIN_VARIANT (p);
> +
> +      /* Make void * compatible with char * and also void **.
> +	 Programs are commonly violating TBAA by this.
> +
> +	 We also make void * to conflict with every pointer
> +	 (see record_component_aliases) and thus it is safe it to use it for
> +	 pointers to types with TYPE_STRUCTURAL_EQUALITY_P.  */
> +      if (TREE_CODE (p) == VOID_TYPE || TYPE_STRUCTURAL_EQUALITY_P (p))
> +	set = get_alias_set (ptr_type_node);
> +      else
> +	{
> +	  /* Rebuild pointer type from 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.
> +
> +	     Most of time we already have pointers or references of a given type.
> +	     If not build new one just to be sure that if someone later (probably
> +	     only middle-end can, as we should assign all alias classes only after
> +	     finishing translation unit) builds the pointer type, the canonical type
> +	     will match.  */
> +	  p = TYPE_CANONICAL (p);
> +	  while (!reference.is_empty ())
> +	    {
> +	      if (reference.pop ())
> +		p = build_reference_type (p);
> +	      else
> +		p = build_pointer_type (p);
> +	      p = TYPE_CANONICAL (TYPE_MAIN_VARIANT (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 triger
> +	     infinite recursion when p == t.
> +	     In other cases it would just trigger unnecesary legwork of
> +	     rebuilding the pointer again.  */
> +	  if (TYPE_ALIAS_SET_KNOWN_P (p))
> +	    /* Return early; we do not need to record component aliases.  */
> +	    return TYPE_ALIAS_SET (t) = TYPE_ALIAS_SET (p);
> +	  else
> +	    {
> +	      set = new_alias_set ();
> +	      TYPE_ALIAS_SET (p) = set;
> +	    }
> +	}
> +    }
> +  /* In LTO the rules above needs to be part of canonical type machinery.
> +     For now just punt.  */
> +  else if (POINTER_TYPE_P (t) && t != ptr_type_node && in_lto_p)
>      set = get_alias_set (ptr_type_node);
>  
>    /* Otherwise make a new alias set for this type.  */
> @@ -950,7 +997,8 @@ get_alias_set (tree t)
>  
>    /* If this is an aggregate type or a complex type, we must record any
>       component aliasing information.  */
> -  if (AGGREGATE_TYPE_P (t) || TREE_CODE (t) == COMPLEX_TYPE)
> +  if (AGGREGATE_TYPE_P (t) || TREE_CODE (t) == COMPLEX_TYPE
> +      || TREE_CODE (t) == POINTER_TYPE)
>      record_component_aliases (t);
>  
>    return set;
> @@ -1050,6 +1098,26 @@ record_component_aliases (tree type)
>  
>    switch (TREE_CODE (type))
>      {
> +    /* We want void * to be compatible with any other pointer without really
> +       dropping it to alias set 0. Doing so would make it compatible with
> +       all non-pointer types too.
> +
> +       Make thus ptr_type_node to be a component of every pointer type.
> +       Tus memory operations of type "void *" conflict with operations of type
> +       "T *" without impossing a conflict with memory operations of type "Q *"
> +       in case T and Q do not conflict.
> + 
> +       This is not strictly necessary by the language standards, but avoids
> +       common type punning mistakes.  In addition to that, we need the existence
> +       of such universal pointer to implement Fortran's C_PTR type (which is
> +       defined as type compatible with all C pointers) and we use it in
> +       get_alias_set to give alias set to pointers to types without
> +       canonical types (those are typically nameless incomplete types)
> +       that needs to be also compatible with each other and with pointers to
> +       complete types.  */
> +    case POINTER_TYPE:
> +      record_alias_subset (superset, get_alias_set (ptr_type_node));
> +      break;
>      case RECORD_TYPE:
>      case UNION_TYPE:
>      case QUAL_UNION_TYPE:
> 

Hi.

If I see correctly, ipa-icf-4.C is still broken, I suggest to degrade the number of merge
operations for the test.

Should I apply the patch?

Thanks,
Martin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Fix-IPA-ICF-test-case.patch
Type: text/x-patch
Size: 942 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/gcc-patches/attachments/20150610/00b75854/attachment.bin>


More information about the Gcc-patches mailing list