This patch makes IPA-PTA work during the ltrans stage of LTO.
It basically makes sure to honor the accessed-from-other-ltrans-unit
flags for variables and functions where appropriate.

With this patch, IPA-PTA survives LTO bootstrap (with -fipa-pta
hard-wired to 1 in common.opt).  Before the patch we miscompiled
the stage2 compiler (unsurprisingly).

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

I hope to get to some of the remaining TODOs for IPA-PTA (basically
fixup nonlocal handling throughout the compiler ...) and then maybe
look at compile-time and memory usage issues.

Richard.

2011-06-29  Richard Guenther  <rguent...@suse.de>

        * opts.c (finish_options): Do not disable IPA-PTA during ltrans.
        * tree-ssa-structalias.c (create_variable_info_for): Do not
        add initial constraints for non-var-decls.  Properly handle
        globals in other ltrans partitions.
        (intra_create_variable_infos): Manually create constraints for
        the fake no-alias parameter.
        (ipa_pta_execute): Dump the cgraph, handle ltrans partitions properly
        and assert there are no clones.

Index: gcc/opts.c
===================================================================
*** gcc/opts.c.orig     2011-06-30 15:25:53.000000000 +0200
--- gcc/opts.c  2011-06-30 15:27:47.000000000 +0200
*************** finish_options (struct gcc_options *opts
*** 766,776 ****
        maybe_set_param_value (PARAM_STACK_FRAME_GROWTH, 40,
                             opts->x_param_values, opts_set->x_param_values);
      }
-   if (opts->x_flag_wpa || opts->x_flag_ltrans)
-     {
-       /* These passes are not WHOPR compatible yet.  */
-       opts->x_flag_ipa_pta = 0;
-     }
  
    if (opts->x_flag_lto)
      {
--- 766,771 ----
Index: gcc/tree-ssa-structalias.c
===================================================================
*** gcc/tree-ssa-structalias.c.orig     2011-06-30 15:26:07.000000000 +0200
--- gcc/tree-ssa-structalias.c  2011-06-30 15:55:02.000000000 +0200
*************** create_variable_info_for (tree decl, con
*** 5450,5455 ****
--- 5450,5458 ----
  
    insert_vi_for_tree (decl, vi);
  
+   if (TREE_CODE (decl) != VAR_DECL)
+     return id;
+ 
    /* Create initial constraints for globals.  */
    for (; vi; vi = vi->next)
      {
*************** create_variable_info_for (tree decl, con
*** 5463,5499 ****
          || vi->only_restrict_pointers)
        make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
  
!       /* For escaped variables initialize them from nonlocal.  */
        if (!in_ipa_mode
!         || DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
        make_copy_constraint (vi, nonlocal_id);
  
!       /* If this is a global variable with an initializer and we are in
!        IPA mode generate constraints for it.  In non-IPA mode
!        the initializer from nonlocal is all we need.  */
!       if (in_ipa_mode
!         && DECL_INITIAL (decl))
        {
!         VEC (ce_s, heap) *rhsc = NULL;
!         struct constraint_expr lhs, *rhsp;
!         unsigned i;
!         get_constraint_for_rhs (DECL_INITIAL (decl), &rhsc);
!         lhs.var = vi->id;
!         lhs.offset = 0;
!         lhs.type = SCALAR;
!         FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
!           process_constraint (new_constraint (lhs, *rhsp));
!         /* If this is a variable that escapes from the unit
!            the initializer escapes as well.  */
!         if (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
            {
!             lhs.var = escaped_id;
              lhs.offset = 0;
              lhs.type = SCALAR;
              FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
                process_constraint (new_constraint (lhs, *rhsp));
            }
-         VEC_free (ce_s, heap, rhsc);
        }
      }
  
--- 5466,5509 ----
          || vi->only_restrict_pointers)
        make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
  
!       /* In non-IPA mode the initializer from nonlocal is all we need.  */
        if (!in_ipa_mode
!         || DECL_HARD_REGISTER (decl))
        make_copy_constraint (vi, nonlocal_id);
  
!       else
        {
!         struct varpool_node *vnode = varpool_get_node (decl);
! 
!         /* For escaped variables initialize them from nonlocal.  */
!         if (!varpool_all_refs_explicit_p (vnode))
!           make_copy_constraint (vi, nonlocal_id);
! 
!         /* If this is a global variable with an initializer and we are in
!            IPA mode generate constraints for it.  */
!         if (DECL_INITIAL (decl))
            {
!             VEC (ce_s, heap) *rhsc = NULL;
!             struct constraint_expr lhs, *rhsp;
!             unsigned i;
!             get_constraint_for_rhs (DECL_INITIAL (decl), &rhsc);
!             lhs.var = vi->id;
              lhs.offset = 0;
              lhs.type = SCALAR;
              FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
                process_constraint (new_constraint (lhs, *rhsp));
+             /* If this is a variable that escapes from the unit
+                the initializer escapes as well.  */
+             if (!varpool_all_refs_explicit_p (vnode))
+               {
+                 lhs.var = escaped_id;
+                 lhs.offset = 0;
+                 lhs.type = SCALAR;
+                 FOR_EACH_VEC_ELT (ce_s, rhsc, i, rhsp)
+                   process_constraint (new_constraint (lhs, *rhsp));
+               }
+             VEC_free (ce_s, heap, rhsc);
            }
        }
      }
  
*************** intra_create_variable_infos (void)
*** 5557,5563 ****
          varinfo_t vi;
          tree heapvar = build_fake_var_decl (TREE_TYPE (TREE_TYPE (t)));
          DECL_EXTERNAL (heapvar) = 1;
!         vi = get_varinfo (create_variable_info_for (heapvar, "PARM_NOALIAS"));
          lhsc.var = get_vi_for_tree (t)->id;
          lhsc.type = SCALAR;
          lhsc.offset = 0;
--- 5567,5574 ----
          varinfo_t vi;
          tree heapvar = build_fake_var_decl (TREE_TYPE (TREE_TYPE (t)));
          DECL_EXTERNAL (heapvar) = 1;
!         vi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS");
!         insert_vi_for_tree (heapvar, vi);
          lhsc.var = get_vi_for_tree (t)->id;
          lhsc.type = SCALAR;
          lhsc.offset = 0;
*************** intra_create_variable_infos (void)
*** 5566,5571 ****
--- 5577,5589 ----
          rhsc.offset = 0;
          process_constraint (new_constraint (lhsc, rhsc));
          vi->is_restrict_var = 1;
+         for (; vi; vi = vi->next)
+           if (vi->may_have_pointers)
+             {
+               if (vi->only_restrict_pointers)
+                 make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+               make_copy_constraint (vi, nonlocal_id);
+             }
          continue;
        }
  
*************** ipa_pta_execute (void)
*** 6744,6749 ****
--- 6762,6773 ----
  
    init_alias_vars ();
  
+   if (dump_file && (dump_flags & TDF_DETAILS))
+     {
+       dump_cgraph (dump_file);
+       fprintf (dump_file, "\n");
+     }
+ 
    /* Build the constraints.  */
    for (node = cgraph_nodes; node; node = node->next)
      {
*************** ipa_pta_execute (void)
*** 6751,6760 ****
        /* Nodes without a body are not interesting.  Especially do not
           visit clones at this point for now - we get duplicate decls
         there for inline clones at least.  */
!       if (!cgraph_function_with_gimple_body_p (node)
!         || node->clone_of)
        continue;
  
        vi = create_function_info_for (node->decl,
                                     alias_get_name (node->decl));
        cgraph_for_node_and_aliases (node, associate_varinfo_to_alias, vi, 
true);
--- 6775,6785 ----
        /* Nodes without a body are not interesting.  Especially do not
           visit clones at this point for now - we get duplicate decls
         there for inline clones at least.  */
!       if (!cgraph_function_with_gimple_body_p (node))
        continue;
  
+       gcc_assert (!node->clone_of);
+ 
        vi = create_function_info_for (node->decl,
                                     alias_get_name (node->decl));
        cgraph_for_node_and_aliases (node, associate_varinfo_to_alias, vi, 
true);
*************** ipa_pta_execute (void)
*** 6785,6792 ****
        tree old_func_decl;
  
        /* Nodes without a body are not interesting.  */
!       if (!cgraph_function_with_gimple_body_p (node)
!         || node->clone_of)
        continue;
  
        if (dump_file)
--- 6810,6816 ----
        tree old_func_decl;
  
        /* Nodes without a body are not interesting.  */
!       if (!cgraph_function_with_gimple_body_p (node))
        continue;
  
        if (dump_file)
*************** ipa_pta_execute (void)
*** 6804,6814 ****
        push_cfun (func);
        current_function_decl = node->decl;
  
!       if (node->local.externally_visible)
        {
-         /* For externally visible functions use local constraints for
-            their arguments.  For local functions we see all callers
-            and thus do not need initial constraints for parameters.  */
          intra_create_variable_infos ();
  
          /* We also need to make function return values escape.  Nothing
--- 6828,6841 ----
        push_cfun (func);
        current_function_decl = node->decl;
  
!       /* For externally visible or attribute used annotated functions use
!        local constraints for their arguments.
!        For local functions we see all callers and thus do not need initial
!        constraints for parameters.  */
!       if (node->reachable_from_other_partition
!         || node->local.externally_visible
!         || node->needed)
        {
          intra_create_variable_infos ();
  
          /* We also need to make function return values escape.  Nothing
*************** ipa_pta_execute (void)
*** 6894,6901 ****
        struct cgraph_edge *e;
  
        /* Nodes without a body are not interesting.  */
!       if (!cgraph_function_with_gimple_body_p (node)
!         || node->clone_of)
        continue;
  
        fn = DECL_STRUCT_FUNCTION (node->decl);
--- 6921,6927 ----
        struct cgraph_edge *e;
  
        /* Nodes without a body are not interesting.  */
!       if (!cgraph_function_with_gimple_body_p (node))
        continue;
  
        fn = DECL_STRUCT_FUNCTION (node->decl);

Reply via email to