On Fri, Oct 26, 2018 at 1:29 PM Jan Hubicka <hubi...@ucw.cz> wrote:
>
> Hi,
> this is minimal variant of the patch turning complete to incomplete pointers 
> in
> fields.  We can do more - in particular it would be very function to do same
> for functions types and decls (because they often end up being streamed to
> symtab) and we should also turn pointers to arrays and enums to incomplete
> variants.
>
> I do that in my local tree but i would like to get it into mainline one by
> one and check benefits of each change independently.
>
> Patch bootstraped&regtests x86-64 and I am now re-testing it on firefox.  I
> checked on small testcases that types indeed do get merged.
>
> OK if it survives more testing on firefox and lto bootstrap?

It looks like a hack to do free_lang_data_in_type from free_lang_data_in_decl
walk - I remember you wanted to unify find_* and free_*?  If not doing that
why would first doing the type walk and only then the decl walk not work
to avoid this ugliness?

That we need to have variants of the incomplete types at all for the place
you substitute them (FIELD_DECLs) has what reason?  See also comments below...

We are getting more and more "interesting" in things we free.  _Please_ work on
enabling free-lang-data (portions) for all compilations (with
-fchecking?).  It's disturbing to see
so much differences creep in in the supposedly "shared" part of regular and
LTO compilation.

> Honza
>
>         * tree.c (free_lang_data_in_type): Declare.
>         (types_equal_p): New function.
>         (free_lang_data_type_variant): New function.
>         (incomplete_type_of): New function.
>         (simplified_type): New function.
> Index: tree.c
> ===================================================================
> --- tree.c      (revision 265522)
> +++ tree.c      (working copy)
> @@ -265,6 +265,8 @@ static void print_type_hash_statistics (
>  static void print_debug_expr_statistics (void);
>  static void print_value_expr_statistics (void);
>
> +static void free_lang_data_in_type (tree type);
> +
>  tree global_trees[TI_MAX];
>  tree integer_types[itk_none];
>
> @@ -5038,6 +5041,140 @@ protected_set_expr_location (tree t, loc
>      SET_EXPR_LOCATION (t, loc);
>  }
>
> +/* Do same comparsion as check_qualified_type skipping lang part of type
> +   and be more permissive about type names: we only care that names are
> +   same (for diagnostics) and that ODR names are the same.  */
> +
> +static bool
> +types_equal_p (tree t, tree v)

The function name is of course totally misleading.  Please use sth like
fld_type_variants_equal_p.

Note we already split check_qualified_type - can't you somehow re-use
check_base_type (only)?

> +{
> +  if (t==v)
> +    return true;
> +
> +  if (TYPE_QUALS (t) != TYPE_QUALS (v))
> +    return false;
> +
> +  if (TYPE_NAME (t) != TYPE_NAME (v)
> +      && (!TYPE_NAME (t) || !TYPE_NAME (v)
> +         || TREE_CODE (TYPE_NAME (t)) != TYPE_DECL
> +         || TREE_CODE (TYPE_NAME (v)) != TYPE_DECL
> +         || DECL_ASSEMBLER_NAME_RAW (TYPE_NAME (t))
> +            != DECL_ASSEMBLER_NAME_RAW (TYPE_NAME (v))

I wonder what this is about...

> +         || DECL_NAME (TYPE_NAME (t)) != DECL_NAME (TYPE_NAME (v))))

...or this, given we may end up turning DECL_NAMEs to INDENTIFIER_NODEs so
this will crash.

> +     return false;
> +
> +  if (TYPE_ALIGN (t) != TYPE_ALIGN (v))
> +    return false;
> +
> +  if (!attribute_list_equal (TYPE_ATTRIBUTES (t),
> +                            TYPE_ATTRIBUTES (v)))
> +     return false;
> +
> +  /* Do not replace complete type by incomplete.  */
> +  if ((TREE_CODE (t) == QUAL_UNION_TYPE
> +       || TREE_CODE (t) == UNION_TYPE || TREE_CODE (t) == RECORD_TYPE)
> +      && COMPLETE_TYPE_P (t) != COMPLETE_TYPE_P (v))
> +    return false;

?  It looks like this function is a left-over from another patch and
the incomplete
type building could use sth leaner and more clearer?


> +
> +  gcc_assert (TREE_CODE (t) == TREE_CODE (v));
> +
> +  /* For pointer types and array types we also care about the type they
> +     reffer to.  */
> +  if (TREE_TYPE (t))
> +    return types_equal_p (TREE_TYPE (t), TREE_TYPE (v));
> +
> +  return true;
> +}
> +
> +/* Find variant of FIRST that match T and create new one if necessary.  */
> +
> +static tree
> +free_lang_data_type_variant (tree first, tree t)
> +{
> +  if (first == TYPE_MAIN_VARIANT (t))
> +    return t;
> +  for (tree v = first; v; v = TYPE_NEXT_VARIANT (v))
> +    if (types_equal_p (t, v))
> +      return v;
> +  tree v = build_variant_type_copy (first);
> +  TYPE_READONLY (v) = TYPE_READONLY (t);
> +  TYPE_VOLATILE (v) = TYPE_VOLATILE (t);
> +  TYPE_ATOMIC (v) = TYPE_ATOMIC (t);
> +  TYPE_RESTRICT (v) = TYPE_RESTRICT (t);
> +  TYPE_ADDR_SPACE (v) = TYPE_ADDR_SPACE (t);
> +  TYPE_NAME (v) = TYPE_NAME (t);
> +  TYPE_ATTRIBUTES (v) = TYPE_ATTRIBUTES (t);
> +  return v;
> +}
> +
> +/* Map complete types to incomplete types.  */
> +static hash_map<tree, tree> *incomplete_types;
> +
> +/* See if type T can be turned into incopmlete variant.  */
> +
> +static tree
> +incomplete_type_of (tree t)
> +{
> +  if (!RECORD_OR_UNION_TYPE_P (t))
> +    return t;
> +  if (!COMPLETE_TYPE_P (t))
> +    return t;
> +  if (TYPE_MAIN_VARIANT (t) == t)
> +    {
> +      bool existed;
> +      tree &copy
> +        = incomplete_types->get_or_insert (TYPE_MAIN_VARIANT (t), &existed);
> +
> +      if (!existed)
> +       {
> +         copy = build_distinct_type_copy (t);
> +
> +         /* It is possible type was not seen by free_lang_data yet.  */
> +         free_lang_data_in_type (copy);
> +         TYPE_SIZE (copy) = NULL;
> +         SET_TYPE_MODE (copy, VOIDmode);
> +         SET_TYPE_ALIGN (copy, BITS_PER_UNIT);
> +         TYPE_SIZE_UNIT (copy) = NULL;
> +         if (AGGREGATE_TYPE_P (t))
> +           {
> +             TYPE_FIELDS (copy) = NULL;
> +             TYPE_BINFO (copy) = NULL;
> +           }
> +         else
> +           TYPE_VALUES (copy) = NULL;
> +       }
> +      return copy;
> +   }
> +  return (free_lang_data_type_variant
> +           (incomplete_type_of (TYPE_MAIN_VARIANT (t)), t));
> +}
> +
> +/* Simplify type T for scenarios where we do not need complete pointer
> +   types.  */
> +
> +static tree
> +simplified_type (tree t)
> +{
> +  if (POINTER_TYPE_P (t))
> +    {
> +      tree t2 = POINTER_TYPE_P (TREE_TYPE (t))
> +               ? simplified_type (TREE_TYPE (t))
> +               : incomplete_type_of (TREE_TYPE (t));
> +      if (t2 != TREE_TYPE (t))
> +       {
> +         tree first;
> +         if (TREE_CODE (t) == POINTER_TYPE)
> +           first = build_pointer_type_for_mode (t2, TYPE_MODE (t),
> +                                               TYPE_REF_CAN_ALIAS_ALL (t));
> +         else
> +           first = build_reference_type_for_mode (t2, TYPE_MODE (t),
> +                                               TYPE_REF_CAN_ALIAS_ALL (t));
> +         return free_lang_data_type_variant (first, t);
> +       }
> +    }
> +  return t;
> +}
> +
>  /* Reset the expression *EXPR_P, a size or position.
>
>     ??? We could reset all non-constant sizes or positions.  But it's cheap
> @@ -5354,9 +5492,11 @@ free_lang_data_in_decl (tree decl)
>        DECL_VISIBILITY_SPECIFIED (decl) = 0;
>        DECL_INITIAL (decl) = NULL_TREE;
>        DECL_ORIGINAL_TYPE (decl) = NULL_TREE;
>      }
>    else if (TREE_CODE (decl) == FIELD_DECL)
> -    DECL_INITIAL (decl) = NULL_TREE;
> +    {
> +      TREE_TYPE (decl) = simplified_type (TREE_TYPE (decl));
> +      DECL_INITIAL (decl) = NULL_TREE;
> +    }
>    else if (TREE_CODE (decl) == TRANSLATION_UNIT_DECL
>             && DECL_INITIAL (decl)
>             && TREE_CODE (DECL_INITIAL (decl)) == BLOCK)
> @@ -5866,6 +6011,8 @@ free_lang_data (void)
>        || (!flag_generate_lto && !flag_generate_offload))
>      return 0;
>
> +  incomplete_types = new hash_map<tree, tree>;
> +
>    /* Provide a dummy TRANSLATION_UNIT_DECL if the FE failed to provide one.  
> */
>    if (vec_safe_is_empty (all_translation_units))
>      build_translation_unit_decl (NULL_TREE);

Reply via email to