[PATCH] Enable IPA-PTA for ltrans stage

Richard Guenther rguenther@suse.de
Thu Jun 30 14:43:00 GMT 2011


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  <rguenther@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);



More information about the Gcc-patches mailing list