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