OSDN Git Service

2010-04-12 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 12 Apr 2010 15:20:48 +0000 (15:20 +0000)
committerMasaki Muranaka <monaka@monami-software.com>
Sun, 23 May 2010 00:56:47 +0000 (09:56 +0900)
* gsstruct.def (GSS_CALL): New.
* gimple.def (GIMPLE_CALL): Change to GSS_CALL.
* gimple.h: Include tree-ssa-alias.h.
(struct gimple_statement_call): New.
(union gimple_statement_struct_d): Add gimple_call member.
(gimple_call_reset_alias_info): Declare.
(gimple_call_use_set): New function.
(gimple_call_clobber_set): Likewise.
* Makefile.in (GIMPLE_H): Add tree-ssa-alias.h.
* gimple.c (gimple_call_reset_alias_info): New function.
(gimple_build_call_1): Call it.
* lto-streamer-in.c (input_gimple_stmt): Likewise.
* tree-inline.c (remap_gimple_stmt): Likewise.
(expand_call_inline): Remove callused handling.
* cfgexpand.c (update_alias_info_with_stack_vars): Likewise.
* tree-dfa.c (dump_variable): Likewise.
* tree-parloops.c (parallelize_loops): Likewise.
* tree-ssa.c (init_tree_ssa): Likewise.
(delete_tree_ssa): Likewise.
* tree-flow-inline.h (is_call_used): Remove.
* tree-flow.h (struct gimple_df): Remove callused member.
* tree-nrv.c (dest_safe_for_nrv_p): Adjust predicate.
* tree-ssa-alias.c (dump_alias_info): Remove callused handling.
(ref_maybe_used_by_call_p_1): Simplify.
(call_may_clobber_ref_p_1): Likewise.
* tree-ssa-structalias.c (compute_points_to_sets): Set
the call stmt used and clobbered sets.
* tree-tailcall.c (suitable_for_tail_opt_p): Adjust predicate.
(find_tail_calls): Verify the tail call.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158226 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/Makefile.in
gcc/gimple.h
gcc/tree-dfa.c
gcc/tree-flow-inline.h
gcc/tree-inline.c
gcc/tree-nrv.c
gcc/tree-ssa-structalias.c
gcc/tree-tailcall.c

index 91a18dc..136ffae 100644 (file)
@@ -1,5 +1,37 @@
 2010-04-12  Richard Guenther  <rguenther@suse.de>
 
+       * gsstruct.def (GSS_CALL): New.
+       * gimple.def (GIMPLE_CALL): Change to GSS_CALL.
+       * gimple.h: Include tree-ssa-alias.h.
+       (struct gimple_statement_call): New.
+       (union gimple_statement_struct_d): Add gimple_call member.
+       (gimple_call_reset_alias_info): Declare.
+       (gimple_call_use_set): New function.
+       (gimple_call_clobber_set): Likewise.
+       * Makefile.in (GIMPLE_H): Add tree-ssa-alias.h.
+       * gimple.c (gimple_call_reset_alias_info): New function.
+       (gimple_build_call_1): Call it.
+       * lto-streamer-in.c (input_gimple_stmt): Likewise.
+       * tree-inline.c (remap_gimple_stmt): Likewise.
+       (expand_call_inline): Remove callused handling.
+       * cfgexpand.c (update_alias_info_with_stack_vars): Likewise.
+       * tree-dfa.c (dump_variable): Likewise.
+       * tree-parloops.c (parallelize_loops): Likewise.
+       * tree-ssa.c (init_tree_ssa): Likewise.
+       (delete_tree_ssa): Likewise.
+       * tree-flow-inline.h (is_call_used): Remove.
+       * tree-flow.h (struct gimple_df): Remove callused member.
+       * tree-nrv.c (dest_safe_for_nrv_p): Adjust predicate.
+       * tree-ssa-alias.c (dump_alias_info): Remove callused handling.
+       (ref_maybe_used_by_call_p_1): Simplify.
+       (call_may_clobber_ref_p_1): Likewise.
+       * tree-ssa-structalias.c (compute_points_to_sets): Set
+       the call stmt used and clobbered sets.
+       * tree-tailcall.c (suitable_for_tail_opt_p): Adjust predicate.
+       (find_tail_calls): Verify the tail call.
+
+2010-04-12  Richard Guenther  <rguenther@suse.de>
+
        * ipa.c (cgraph_postorder): Adjust postorder to guarantee
        single-iteration always-inline inlining.
        * ipa-inline.c (cgraph_mark_inline): Do not return anything.
index 99811e7..c1cec39 100644 (file)
@@ -876,7 +876,8 @@ BASIC_BLOCK_H = basic-block.h $(BITMAP_H) sbitmap.h varray.h $(PARTITION_H) \
           hard-reg-set.h $(PREDICT_H) vec.h $(FUNCTION_H) \
           cfghooks.h $(OBSTACK_H)
 GIMPLE_H = gimple.h gimple.def gsstruct.def pointer-set.h vec.h \
-       $(GGC_H) $(BASIC_BLOCK_H) $(TM_H) $(TARGET_H) tree-ssa-operands.h
+       $(GGC_H) $(BASIC_BLOCK_H) $(TM_H) $(TARGET_H) tree-ssa-operands.h \
+       tree-ssa-alias.h
 GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h
 COVERAGE_H = coverage.h $(GCOV_IO_H)
 DEMANGLE_H = $(srcdir)/../include/demangle.h
index baa839f..9df6e92 100644 (file)
@@ -24,8 +24,6 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "pointer-set.h"
 #include "vec.h"
-#include "vecprim.h"
-#include "vecir.h"
 #include "ggc.h"
 #include "tm.h"
 #include "hard-reg-set.h"
@@ -33,6 +31,18 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-operands.h"
 #include "tree-ssa-alias.h"
 
+DEF_VEC_P(gimple);
+DEF_VEC_ALLOC_P(gimple,heap);
+DEF_VEC_ALLOC_P(gimple,gc);
+
+typedef gimple *gimple_p;
+DEF_VEC_P(gimple_p);
+DEF_VEC_ALLOC_P(gimple_p,heap);
+
+DEF_VEC_P(gimple_seq);
+DEF_VEC_ALLOC_P(gimple_seq,gc);
+DEF_VEC_ALLOC_P(gimple_seq,heap);
+
 /* For each block, the PHI nodes that need to be rewritten are stored into
    these vectors.  */
 typedef VEC(gimple, heap) *gimple_vec;
@@ -96,7 +106,6 @@ enum gf_mask {
     GF_CALL_RETURN_SLOT_OPT    = 1 << 2,
     GF_CALL_TAILCALL           = 1 << 3,
     GF_CALL_VA_ARG_PACK                = 1 << 4,
-    GF_CALL_NOTHROW            = 1 << 5,
     GF_OMP_PARALLEL_COMBINED   = 1 << 0,
 
     /* True on an GIMPLE_OMP_RETURN statement if the return does not require
@@ -212,13 +221,6 @@ gimple_seq_empty_p (const_gimple_seq s)
 
 void gimple_seq_add_stmt (gimple_seq *, gimple);
 
-/* Link gimple statement GS to the end of the sequence *SEQ_P.  If
-   *SEQ_P is NULL, a new sequence is allocated.  This function is
-   similar to gimple_seq_add_stmt, but does not scan the operands.
-   During gimplification, we need to manipulate statement sequences
-   before the def/use vectors have been constructed.  */
-void gimplify_seq_add_stmt (gimple_seq *, gimple);
-
 /* Allocate a new sequence and initialize its first element with STMT.  */
 
 static inline gimple_seq
@@ -855,8 +857,6 @@ void gimple_seq_free (gimple_seq);
 void gimple_seq_add_seq (gimple_seq *, gimple_seq);
 gimple_seq gimple_seq_copy (gimple_seq);
 int gimple_call_flags (const_gimple);
-int gimple_call_return_flags (const_gimple);
-int gimple_call_arg_flags (const_gimple, unsigned);
 void gimple_call_reset_alias_info (gimple);
 bool gimple_assign_copy_p (gimple);
 bool gimple_assign_ssa_name_copy_p (gimple);
@@ -886,8 +886,6 @@ unsigned get_gimple_rhs_num_ops (enum tree_code);
 gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
 const char *gimple_decl_printable_name (tree, int);
 tree gimple_fold_obj_type_ref (tree, tree);
-tree gimple_get_relevant_ref_binfo (tree ref, tree known_binfo);
-tree gimple_fold_obj_type_ref_known_binfo (HOST_WIDE_INT, tree);
 
 /* Returns true iff T is a valid GIMPLE statement.  */
 extern bool is_gimple_stmt (tree);
@@ -944,7 +942,7 @@ extern bool is_gimple_call_addr (tree);
 extern tree get_call_expr_in (tree t);
 
 extern void recalculate_side_effects (tree);
-extern bool gimple_compare_field_offset (tree, tree);
+extern bool compare_field_offset (tree, tree);
 extern tree gimple_register_type (tree);
 extern void print_gimple_types_stats (void);
 extern void free_gimple_type_tables (void);
@@ -966,7 +964,6 @@ extern bool gimple_ior_addresses_taken (bitmap, gimple);
 extern tree create_tmp_var_raw (tree, const char *);
 extern tree create_tmp_var_name (const char *);
 extern tree create_tmp_var (tree, const char *);
-extern tree create_tmp_reg (tree, const char *);
 extern tree get_initialized_tmp_var (tree, gimple_seq *, gimple_seq *);
 extern tree get_formal_tmp_var (tree, gimple_seq *);
 extern void declare_vars (tree, gimple, bool);
@@ -1038,6 +1035,8 @@ extern gimple gimple_current_bind_expr (void);
 extern VEC(gimple, heap) *gimple_bind_expr_stack (void);
 extern tree voidify_wrapper_expr (tree, tree);
 extern tree build_and_jump (tree *);
+extern tree alloc_stmt_list (void);
+extern void free_stmt_list (tree);
 extern tree force_labels_r (tree *, int *, void *);
 extern enum gimplify_status gimplify_va_arg_expr (tree *, gimple_seq *,
                                                  gimple_seq *);
@@ -2202,19 +2201,6 @@ gimple_call_noreturn_p (gimple s)
 }
 
 
-/* If NOTHROW_P is true, GIMPLE_CALL S is a call that is known to not throw
-   even if the called function can throw in other cases.  */
-
-static inline void
-gimple_call_set_nothrow (gimple s, bool nothrow_p)
-{
-  GIMPLE_CHECK (s, GIMPLE_CALL);
-  if (nothrow_p)
-    s->gsbase.subcode |= GF_CALL_NOTHROW;
-  else
-    s->gsbase.subcode &= ~GF_CALL_NOTHROW;
-}
-
 /* Return true if S is a nothrow call.  */
 
 static inline bool
@@ -4801,16 +4787,4 @@ gimple_alloc_kind (enum gimple_code code)
 
 extern void dump_gimple_statistics (void);
 
-/* In gimple-fold.c.  */
-void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
-tree gimple_fold_builtin (gimple);
-bool fold_stmt (gimple_stmt_iterator *);
-bool fold_stmt_inplace (gimple);
-tree maybe_fold_offset_to_reference (location_t, tree, tree, tree);
-tree maybe_fold_offset_to_address (location_t, tree, tree, tree);
-tree maybe_fold_stmt_addition (location_t, tree, tree, tree);
-tree get_symbol_constant_value (tree);
-bool may_propagate_address_into_dereference (tree, tree);
-
-
 #endif  /* GCC_GIMPLE_H */
index ed70d74..bd91e3b 100644 (file)
@@ -1,5 +1,5 @@
 /* Data flow functions for trees.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
@@ -26,7 +26,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "hashtab.h"
 #include "pointer-set.h"
 #include "tree.h"
+#include "rtl.h"
 #include "tm_p.h"
+#include "hard-reg-set.h"
 #include "basic-block.h"
 #include "output.h"
 #include "timevar.h"
@@ -36,7 +38,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "function.h"
 #include "diagnostic.h"
-#include "tree-pretty-print.h"
 #include "tree-dump.h"
 #include "gimple.h"
 #include "tree-flow.h"
@@ -192,7 +193,11 @@ renumber_gimple_stmt_uids_in_blocks (basic_block *blocks, int n_blocks)
 tree
 make_rename_temp (tree type, const char *prefix)
 {
-  tree t = create_tmp_reg (type, prefix);
+  tree t = create_tmp_var (type, prefix);
+
+  if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+      || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+    DECL_GIMPLE_REG_P (t) = 1;
 
   if (gimple_referenced_vars (cfun))
     {
@@ -264,8 +269,6 @@ dump_variable (FILE *file, tree var)
   ann = var_ann (var);
 
   fprintf (file, ", UID D.%u", (unsigned) DECL_UID (var));
-  if (DECL_PT_UID (var) != DECL_UID (var))
-    fprintf (file, ", PT-UID D.%u", (unsigned) DECL_PT_UID (var));
 
   fprintf (file, ", ");
   print_generic_expr (file, TREE_TYPE (var), dump_flags);
@@ -279,6 +282,9 @@ dump_variable (FILE *file, tree var)
   if (TREE_THIS_VOLATILE (var))
     fprintf (file, ", is volatile");
 
+  if (is_call_clobbered (var))
+    fprintf (file, ", call clobbered");
+
   if (ann && ann->noalias_state == NO_ALIAS)
     fprintf (file, ", NO_ALIAS (does not alias other NO_ALIAS symbols)");
   else if (ann && ann->noalias_state == NO_ALIAS_GLOBAL)
index f7609ea..2430f03 100644 (file)
@@ -624,6 +624,15 @@ loop_containing_stmt (gimple stmt)
 }
 
 
+/* Return true if VAR is clobbered by function calls.  */
+static inline bool
+is_call_clobbered (const_tree var)
+{
+  return (is_global_var (var)
+         || (may_be_aliased (var)
+             && pt_solution_includes (&cfun->gimple_df->escaped, var)));
+}
+
 /*  -----------------------------------------------------------------------  */
 
 /* The following set of routines are used to iterator over various type of
index 4c51f3b..922ce52 100644 (file)
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "tree.h"
 #include "tree-inline.h"
+#include "rtl.h"
 #include "expr.h"
 #include "flags.h"
 #include "params.h"
@@ -40,9 +41,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-mudflap.h"
 #include "tree-flow.h"
 #include "function.h"
+#include "ggc.h"
 #include "tree-flow.h"
 #include "diagnostic.h"
-#include "tree-pretty-print.h"
 #include "except.h"
 #include "debug.h"
 #include "pointer-set.h"
@@ -101,6 +102,10 @@ along with GCC; see the file COPYING3.  If not see
      calls?  */
 
 
+/* Weights that estimate_num_insns uses for heuristics in inlining.  */
+
+eni_weights eni_inlining_weights;
+
 /* Weights that estimate_num_insns uses to estimate the size of the
    produced code.  */
 
@@ -206,21 +211,11 @@ remap_ssa_name (tree name, copy_body_data *id)
       && (TREE_CODE (SSA_NAME_VAR (name)) != RESULT_DECL
          || !id->transform_return_to_modify))
     {
-      struct ptr_info_def *pi;
       new_tree = make_ssa_name (new_tree, NULL);
       insert_decl_map (id, name, new_tree);
       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_tree)
        = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name);
       TREE_TYPE (new_tree) = TREE_TYPE (SSA_NAME_VAR (new_tree));
-      /* At least IPA points-to info can be directly transferred.  */
-      if (id->src_cfun->gimple_df
-         && id->src_cfun->gimple_df->ipa_pta
-         && (pi = SSA_NAME_PTR_INFO (name))
-         && !pi->pt.anything)
-       {
-         struct ptr_info_def *new_pi = get_ptr_info (new_tree);
-         new_pi->pt = pi->pt;
-       }
       if (gimple_nop_p (SSA_NAME_DEF_STMT (name)))
        {
          /* By inlining function having uninitialized variable, we might
@@ -665,30 +660,16 @@ copy_bind_expr (tree *tp, int *walk_subtrees, copy_body_data *id)
     }
 
   if (BIND_EXPR_VARS (*tp))
-    {
-      tree t;
-
-      /* This will remap a lot of the same decls again, but this should be
-        harmless.  */
-      BIND_EXPR_VARS (*tp) = remap_decls (BIND_EXPR_VARS (*tp), NULL, id);
-      /* Also copy value-expressions.  */
-      for (t = BIND_EXPR_VARS (*tp); t; t = TREE_CHAIN (t))
-       if (TREE_CODE (t) == VAR_DECL
-           && DECL_HAS_VALUE_EXPR_P (t))
-         {
-           tree tem = DECL_VALUE_EXPR (t);
-           walk_tree (&tem, copy_tree_body_r, id, NULL);
-           SET_DECL_VALUE_EXPR (t, tem);
-         }
-    }
+    /* This will remap a lot of the same decls again, but this should be
+       harmless.  */
+    BIND_EXPR_VARS (*tp) = remap_decls (BIND_EXPR_VARS (*tp), NULL, id);
 }
 
 
 /* Create a new gimple_seq by remapping all the statements in BODY
    using the inlining information in ID.  */
 
-static gimple_seq
+gimple_seq
 remap_gimple_seq (gimple_seq body, copy_body_data *id)
 {
   gimple_stmt_iterator si;
@@ -1411,11 +1392,12 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
                    break;
                  }
 
-             /* Reset alias info if we didn't apply measures to
-                keep it valid over inlining by setting DECL_PT_UID.  */
-             if (!id->src_cfun->gimple_df
-                 || !id->src_cfun->gimple_df->ipa_pta)
-               gimple_call_reset_alias_info (copy);
+             /* Reset alias info.
+                ???  By maintaining DECL_PT_UID this should not
+                be necessary, but the plan is to only maintain
+                it when IPA-PTA was run.  It's not too easy to
+                detect this here ...  */
+             gimple_call_reset_alias_info (copy);
            }
            break;
 
@@ -1698,8 +1680,9 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
              /* Constant propagation on argument done during inlining
                 may create new direct call.  Produce an edge for it.  */
              if ((!edge
-                  || (edge->indirect_inlining_edge
+                  || (edge->indirect_call
                       && id->transform_call_graph_edges == CB_CGE_MOVE_CLONES))
+                 && is_gimple_call (stmt)
                  && (fn = gimple_call_fndecl (stmt)) != NULL)
                {
                  struct cgraph_node *dest = cgraph_node (fn);
@@ -1711,7 +1694,6 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
                     other cases we hit a bug (incorrect node sharing is the
                     most common reason for missing edges).  */
                  gcc_assert (dest->needed || !dest->analyzed
-                             || dest->address_taken
                              || !id->src_node->analyzed);
                  if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)
                    cgraph_create_edge_including_clones
@@ -2024,6 +2006,7 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count)
   cfun->last_verified = src_cfun->last_verified;
   cfun->va_list_gpr_size = src_cfun->va_list_gpr_size;
   cfun->va_list_fpr_size = src_cfun->va_list_fpr_size;
+  cfun->function_frequency = src_cfun->function_frequency;
   cfun->has_nonlocal_label = src_cfun->has_nonlocal_label;
   cfun->stdarg = src_cfun->stdarg;
   cfun->dont_save_pending_sizes_p = src_cfun->dont_save_pending_sizes_p;
@@ -3278,93 +3261,22 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
        if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
          switch (DECL_FUNCTION_CODE (decl))
            {
-           /* Builtins that expand to constants.  */
            case BUILT_IN_CONSTANT_P:
+             return 0;
            case BUILT_IN_EXPECT:
-           case BUILT_IN_OBJECT_SIZE:
-           case BUILT_IN_UNREACHABLE:
-           /* Simple register moves or loads from stack.  */
-           case BUILT_IN_RETURN_ADDRESS:
-           case BUILT_IN_EXTRACT_RETURN_ADDR:
-           case BUILT_IN_FROB_RETURN_ADDR:
-           case BUILT_IN_RETURN:
-           case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
-           case BUILT_IN_FRAME_ADDRESS:
-           case BUILT_IN_VA_END:
-           case BUILT_IN_STACK_SAVE:
-           case BUILT_IN_STACK_RESTORE:
-           /* Exception state returns or moves registers around.  */
-           case BUILT_IN_EH_FILTER:
-           case BUILT_IN_EH_POINTER:
-           case BUILT_IN_EH_COPY_VALUES:
              return 0;
 
-           /* builtins that are not expensive (that is they are most probably
-              expanded inline into resonably simple code).  */
-           case BUILT_IN_ABS:
-           case BUILT_IN_ALLOCA:
-           case BUILT_IN_BSWAP32:
-           case BUILT_IN_BSWAP64:
-           case BUILT_IN_CLZ:
-           case BUILT_IN_CLZIMAX:
-           case BUILT_IN_CLZL:
-           case BUILT_IN_CLZLL:
-           case BUILT_IN_CTZ:
-           case BUILT_IN_CTZIMAX:
-           case BUILT_IN_CTZL:
-           case BUILT_IN_CTZLL:
-           case BUILT_IN_FFS:
-           case BUILT_IN_FFSIMAX:
-           case BUILT_IN_FFSL:
-           case BUILT_IN_FFSLL:
-           case BUILT_IN_IMAXABS:
-           case BUILT_IN_FINITE:
-           case BUILT_IN_FINITEF:
-           case BUILT_IN_FINITEL:
-           case BUILT_IN_FINITED32:
-           case BUILT_IN_FINITED64:
-           case BUILT_IN_FINITED128:
-           case BUILT_IN_FPCLASSIFY:
-           case BUILT_IN_ISFINITE:
-           case BUILT_IN_ISINF_SIGN:
-           case BUILT_IN_ISINF:
-           case BUILT_IN_ISINFF:
-           case BUILT_IN_ISINFL:
-           case BUILT_IN_ISINFD32:
-           case BUILT_IN_ISINFD64:
-           case BUILT_IN_ISINFD128:
-           case BUILT_IN_ISNAN:
-           case BUILT_IN_ISNANF:
-           case BUILT_IN_ISNANL:
-           case BUILT_IN_ISNAND32:
-           case BUILT_IN_ISNAND64:
-           case BUILT_IN_ISNAND128:
-           case BUILT_IN_ISNORMAL:
-           case BUILT_IN_ISGREATER:
-           case BUILT_IN_ISGREATEREQUAL:
-           case BUILT_IN_ISLESS:
-           case BUILT_IN_ISLESSEQUAL:
-           case BUILT_IN_ISLESSGREATER:
-           case BUILT_IN_ISUNORDERED:
-           case BUILT_IN_VA_ARG_PACK:
-           case BUILT_IN_VA_ARG_PACK_LEN:
-           case BUILT_IN_VA_COPY:
-           case BUILT_IN_TRAP:
-           case BUILT_IN_SAVEREGS:
-           case BUILT_IN_POPCOUNTL:
-           case BUILT_IN_POPCOUNTLL:
-           case BUILT_IN_POPCOUNTIMAX:
-           case BUILT_IN_POPCOUNT:
-           case BUILT_IN_PARITYL:
-           case BUILT_IN_PARITYLL:
-           case BUILT_IN_PARITYIMAX:
-           case BUILT_IN_PARITY:
-           case BUILT_IN_LABS:
-           case BUILT_IN_LLABS:
+           /* Prefetch instruction is not expensive.  */
            case BUILT_IN_PREFETCH:
              cost = weights->target_builtin_call_cost;
              break;
 
+           /* Exception state returns or moves registers around.  */
+           case BUILT_IN_EH_FILTER:
+           case BUILT_IN_EH_POINTER:
+           case BUILT_IN_EH_COPY_VALUES:
+             return 0;
+
            default:
              break;
            }
@@ -3553,7 +3465,7 @@ get_indirect_callee_fndecl (struct cgraph_node *node, gimple stmt)
   struct cgraph_edge *cs;
 
   cs = cgraph_edge (node, stmt);
-  if (cs && !cs->indirect_unknown_callee)
+  if (cs)
     return cs->callee->decl;
 
   return NULL_TREE;
@@ -3636,7 +3548,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
       /* If this call was originally indirect, we do not want to emit any
         inlining related warnings or sorry messages because there are no
         guarantees regarding those.  */
-      if (cg_edge->indirect_inlining_edge)
+      if (cg_edge->indirect_call)
        goto egress;
 
       if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn))
@@ -4604,8 +4516,6 @@ copy_decl_to_var (tree decl, copy_body_data *id)
 
   copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn),
                     VAR_DECL, DECL_NAME (decl), type);
-  if (DECL_PT_UID_SET_P (decl))
-    SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
   TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
   TREE_READONLY (copy) = TREE_READONLY (decl);
   TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
@@ -4631,8 +4541,6 @@ copy_result_decl_to_var (tree decl, copy_body_data *id)
 
   copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn),
                     VAR_DECL, DECL_NAME (decl), type);
-  if (DECL_PT_UID_SET_P (decl))
-    SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
   TREE_READONLY (copy) = TREE_READONLY (decl);
   TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
   if (!DECL_BY_REFERENCE (decl))
@@ -4925,8 +4833,6 @@ tree_function_versioning (tree old_decl, tree new_decl,
     (DECL_STRUCT_FUNCTION (old_decl));
   initialize_cfun (new_decl, old_decl,
                   old_entry_block->count);
-  DECL_STRUCT_FUNCTION (new_decl)->gimple_df->ipa_pta
-    = id.src_cfun->gimple_df->ipa_pta;
   push_cfun (DECL_STRUCT_FUNCTION (new_decl));
 
   /* Copy the function's static chain.  */
@@ -4945,15 +4851,6 @@ tree_function_versioning (tree old_decl, tree new_decl,
        if (replace_info->replace_p)
          {
            tree op = replace_info->new_tree;
-           if (!replace_info->old_tree)
-             {
-               int i = replace_info->parm_num;
-               tree parm;
-               for (parm = DECL_ARGUMENTS (old_decl); i; parm = TREE_CHAIN (parm))
-                 i --;
-               replace_info->old_tree = parm;
-             }
-               
 
            STRIP_NOPS (op);
 
@@ -5047,8 +4944,6 @@ tree_function_versioning (tree old_decl, tree new_decl,
   pointer_set_destroy (id.statements_to_fold);
   fold_cond_expr_cond ();
   delete_unreachable_blocks_update_callgraph (&id);
-  if (id.dst_node->analyzed)
-    cgraph_rebuild_references ();
   update_ssa (TODO_update_ssa);
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
@@ -5175,7 +5070,7 @@ tree_can_inline_p (struct cgraph_edge *e)
        return false;
     }
 #endif
-  tree caller, callee, lhs;
+  tree caller, callee;
 
   caller = e->caller->decl;
   callee = e->callee->decl;
@@ -5201,16 +5096,8 @@ tree_can_inline_p (struct cgraph_edge *e)
       return false;
     }
 
-  /* Do not inline calls where we cannot triviall work around mismatches
-     in argument or return types.  */
   if (e->call_stmt
-      && ((DECL_RESULT (callee)
-          && !DECL_BY_REFERENCE (DECL_RESULT (callee))
-          && (lhs = gimple_call_lhs (e->call_stmt)) != NULL_TREE
-          && !useless_type_conversion_p (TREE_TYPE (DECL_RESULT (callee)),
-                                         TREE_TYPE (lhs))
-          && !fold_convertible_p (TREE_TYPE (DECL_RESULT (callee)), lhs))
-         || !gimple_check_call_args (e->call_stmt)))
+      && !gimple_check_call_args (e->call_stmt))
     {
       e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
       gimple_call_set_cannot_inline (e->call_stmt, true);
index 06b1351..b85c5a7 100644 (file)
@@ -1,6 +1,5 @@
 /* Language independent return value optimizations
-   Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -23,18 +22,16 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "rtl.h"
 #include "function.h"
 #include "basic-block.h"
+#include "expr.h"
 #include "diagnostic.h"
-#include "tree-pretty-print.h"
 #include "tree-flow.h"
 #include "timevar.h"
 #include "tree-dump.h"
 #include "tree-pass.h"
 #include "langhooks.h"
-#include "flags.h"     /* For "optimize" in gate_pass_return_slot.
-                          FIXME: That should be up to the pass manager,
-                          but pass_nrv is not in pass_all_optimizations.  */
 
 /* This file implements return value optimizations for functions which
    return aggregate types.
@@ -294,21 +291,23 @@ struct gimple_opt_pass pass_nrv =
    optimization, where DEST is expected to be the LHS of a modify
    expression where the RHS is a function returning an aggregate.
 
-   DEST is available if it is not clobbered by the call.  */
+   We search for a base VAR_DECL and look to see if it is call clobbered.
+   Note that we could do better, for example, by
+   attempting to doing points-to analysis on INDIRECT_REFs.  */
 
 static bool
-dest_safe_for_nrv_p (gimple call)
+dest_safe_for_nrv_p (tree dest)
 {
-  tree dest = gimple_call_lhs (call);
+  while (handled_component_p (dest))
+    dest = TREE_OPERAND (dest, 0);
 
-  dest = get_base_address (dest);
-  if (! dest)
+  if (! SSA_VAR_P (dest))
     return false;
 
   if (TREE_CODE (dest) == SSA_NAME)
-    return true;
+    dest = SSA_NAME_VAR (dest);
 
-  if (call_may_clobber_ref_p (call, dest))
+  if (is_call_clobbered (dest))
     return false;
 
   return true;
@@ -347,8 +346,8 @@ execute_return_slot_opt (void)
             )
            {
              /* Check if the location being assigned to is
-                clobbered by the call.  */
-             slot_opt_p = dest_safe_for_nrv_p (stmt);
+                call-clobbered.  */
+             slot_opt_p = dest_safe_for_nrv_p (gimple_call_lhs (stmt));
              gimple_call_set_return_slot_opt (stmt, slot_opt_p);
            }
        }
index a5a9634..e14b97a 100644 (file)
 #include "obstack.h"
 #include "bitmap.h"
 #include "flags.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "hard-reg-set.h"
 #include "basic-block.h"
 #include "output.h"
 #include "tree.h"
 #include "tree-flow.h"
 #include "tree-inline.h"
+#include "varray.h"
 #include "diagnostic.h"
 #include "toplev.h"
 #include "gimple.h"
   TODO: We could handle unions, but to be honest, it's probably not
   worth the pain or slowdown.  */
 
-/* IPA-PTA optimizations possible.
-
-   When the indirect function called is ANYTHING we can add disambiguation
-   based on the function signatures (or simply the parameter count which
-   is the varinfo size).  We also do not need to consider functions that
-   do not have their address taken.
-
-   The is_global_var bit which marks escape points is overly conservative
-   in IPA mode.  Split it to is_escape_point and is_global_var - only
-   externally visible globals are escape points in IPA mode.  This is
-   also needed to fix the pt_solution_includes_global predicate
-   (and thus ptr_deref_may_alias_global_p).
-
-   The way we introduce DECL_PT_UID to avoid fixing up all points-to
-   sets in the translation unit when we copy a DECL during inlining
-   pessimizes precision.  The advantage is that the DECL_PT_UID keeps
-   compile-time and memory usage overhead low - the points-to sets
-   do not grow or get unshared as they would during a fixup phase.
-   An alternative solution is to delay IPA PTA until after all
-   inlining transformations have been applied.
-
-   The way we propagate clobber/use information isn't optimized.
-   It should use a new complex constraint that properly filters
-   out local variables of the callee (though that would make
-   the sets invalid after inlining).  OTOH we might as well
-   admit defeat to WHOPR and simply do all the clobber/use analysis
-   and propagation after PTA finished but before we threw away
-   points-to information for memory variables.  WHOPR and PTA
-   do not play along well anyway - the whole constraint solving
-   would need to be done in WPA phase and it will be very interesting
-   to apply the results to local SSA names during LTRANS phase.
-
-   We probably should compute a per-function unit-ESCAPE solution
-   propagating it simply like the clobber / uses solutions.  The
-   solution can go alongside the non-IPA espaced solution and be
-   used to query which vars escape the unit through a function.
-
-   We never put function decls in points-to sets so we do not
-   keep the set of called functions for indirect calls.
-
-   And probably more.  */
-
 static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
 htab_t heapvar_for_stmt;
 
@@ -271,15 +233,9 @@ struct variable_info
   /* True if this field may contain pointers.  */
   unsigned int may_have_pointers : 1;
 
-  /* True if this field has only restrict qualified pointers.  */
-  unsigned int only_restrict_pointers : 1;
-
   /* True if this represents a global variable.  */
   unsigned int is_global_var : 1;
 
-  /* True if this represents a IPA function info.  */
-  unsigned int is_fn_info : 1;
-
   /* A link to the variable for the next field in this structure.  */
   struct variable_info *next;
 
@@ -332,8 +288,8 @@ get_varinfo (unsigned int n)
 
 /* Static IDs for the special variables.  */
 enum { nothing_id = 0, anything_id = 1, readonly_id = 2,
-       escaped_id = 3, nonlocal_id = 4,
-       storedanything_id = 5, integer_id = 6 };
+       escaped_id = 3, nonlocal_id = 4, callused_id = 5,
+       storedanything_id = 6, integer_id = 7 };
 
 struct GTY(()) heapvar_map {
   struct tree_map map;
@@ -411,102 +367,18 @@ new_var_info (tree t, const char *name)
   ret->is_heap_var = false;
   ret->is_restrict_var = false;
   ret->may_have_pointers = true;
-  ret->only_restrict_pointers = false;
   ret->is_global_var = (t == NULL_TREE);
-  ret->is_fn_info = false;
   if (t && DECL_P (t))
     ret->is_global_var = is_global_var (t);
   ret->solution = BITMAP_ALLOC (&pta_obstack);
   ret->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
   ret->next = NULL;
 
-  stats.total_vars++;
-
   VEC_safe_push (varinfo_t, heap, varmap, ret);
 
   return ret;
 }
 
-
-/* A map mapping call statements to per-stmt variables for uses
-   and clobbers specific to the call.  */
-struct pointer_map_t *call_stmt_vars;
-
-/* Lookup or create the variable for the call statement CALL.  */
-
-static varinfo_t
-get_call_vi (gimple call)
-{
-  void **slot_p;
-  varinfo_t vi, vi2;
-
-  slot_p = pointer_map_insert (call_stmt_vars, call);
-  if (*slot_p)
-    return (varinfo_t) *slot_p;
-
-  vi = new_var_info (NULL_TREE, "CALLUSED");
-  vi->offset = 0;
-  vi->size = 1;
-  vi->fullsize = 2;
-  vi->is_full_var = true;
-
-  vi->next = vi2 = new_var_info (NULL_TREE, "CALLCLOBBERED");
-  vi2->offset = 1;
-  vi2->size = 1;
-  vi2->fullsize = 2;
-  vi2->is_full_var = true;
-
-  *slot_p = (void *) vi;
-  return vi;
-}
-
-/* Lookup the variable for the call statement CALL representing
-   the uses.  Returns NULL if there is nothing special about this call.  */
-
-static varinfo_t
-lookup_call_use_vi (gimple call)
-{
-  void **slot_p;
-
-  slot_p = pointer_map_contains (call_stmt_vars, call);
-  if (slot_p)
-    return (varinfo_t) *slot_p;
-
-  return NULL;
-}
-
-/* Lookup the variable for the call statement CALL representing
-   the clobbers.  Returns NULL if there is nothing special about this call.  */
-
-static varinfo_t
-lookup_call_clobber_vi (gimple call)
-{
-  varinfo_t uses = lookup_call_use_vi (call);
-  if (!uses)
-    return NULL;
-
-  return uses->next;
-}
-
-/* Lookup or create the variable for the call statement CALL representing
-   the uses.  */
-
-static varinfo_t
-get_call_use_vi (gimple call)
-{
-  return get_call_vi (call);
-}
-
-/* Lookup or create the variable for the call statement CALL representing
-   the clobbers.  */
-
-static varinfo_t ATTRIBUTE_UNUSED
-get_call_clobber_vi (gimple call)
-{
-  return get_call_vi (call)->next;
-}
-
-
 typedef enum {SCALAR, DEREF, ADDRESSOF} constraint_expr_type;
 
 /* An expression that appears in a constraint.  */
@@ -725,11 +597,11 @@ debug_constraint (constraint_t c)
 /* Print out all constraints to FILE */
 
 static void
-dump_constraints (FILE *file, int from)
+dump_constraints (FILE *file)
 {
   int i;
   constraint_t c;
-  for (i = from; VEC_iterate (constraint_t, constraints, i, c); i++)
+  for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
     dump_constraint (file, c);
 }
 
@@ -738,7 +610,7 @@ dump_constraints (FILE *file, int from)
 void
 debug_constraints (void)
 {
-  dump_constraints (stderr, 0);
+  dump_constraints (stderr);
 }
 
 /* Print out to FILE the edge in the constraint graph that is created by
@@ -789,7 +661,7 @@ dump_constraint_graph (FILE *file)
   /* Print the constraints used to produce the constraint graph. The
      constraints will be printed as comments in the dot file:  */
   fprintf (file, "\n\n/* Constraints used in the constraint graph:\n");
-  dump_constraints (file, 0);
+  dump_constraints (file);
   fprintf (file, "*/\n");
 
   /* Prints the header of the dot file:  */
@@ -1708,8 +1580,7 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
             the set.  Use ESCAPED as representative instead.  */
          else if (v->id == escaped_id)
            flag |= bitmap_set_bit (sol, escaped_id);
-         else if (v->may_have_pointers
-                  && add_graph_edge (graph, lhs, t))
+         else if (add_graph_edge (graph, lhs, t))
            flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
 
          /* If the variable is not exactly at the requested offset
@@ -1748,7 +1619,6 @@ do_ds_constraint (constraint_t c, bitmap delta)
   unsigned int j;
   bitmap_iterator bi;
   HOST_WIDE_INT loff = c->lhs.offset;
-  bool escaped_p = false;
 
   /* Our IL does not allow this.  */
   gcc_assert (c->rhs.offset == 0);
@@ -1795,6 +1665,22 @@ do_ds_constraint (constraint_t c, bitmap delta)
       unsigned int t;
       HOST_WIDE_INT fieldoffset = v->offset + loff;
 
+      /* If v is a global variable then this is an escape point.  */
+      if (v->is_global_var)
+       {
+         t = find (escaped_id);
+         if (add_graph_edge (graph, t, rhs)
+             && bitmap_ior_into (get_varinfo (t)->solution, sol)
+             && !TEST_BIT (changed, t))
+           {
+             SET_BIT (changed, t);
+             changed_count++;
+           }
+       }
+
+      if (v->is_special_var)
+       continue;
+
       if (v->is_full_var)
        fieldoffset = v->offset;
       else if (loff != 0)
@@ -1807,25 +1693,6 @@ do_ds_constraint (constraint_t c, bitmap delta)
        {
          if (v->may_have_pointers)
            {
-             /* If v is a global variable then this is an escape point.  */
-             if (v->is_global_var
-                 && !escaped_p)
-               {
-                 t = find (escaped_id);
-                 if (add_graph_edge (graph, t, rhs)
-                     && bitmap_ior_into (get_varinfo (t)->solution, sol)
-                     && !TEST_BIT (changed, t))
-                   {
-                     SET_BIT (changed, t);
-                     changed_count++;
-                   }
-                 /* Enough to let rhs escape once.  */
-                 escaped_p = true;
-               }
-
-             if (v->is_special_var)
-               break;
-
              t = find (v->id);
              if (add_graph_edge (graph, t, rhs)
                  && bitmap_ior_into (get_varinfo (t)->solution, sol)
@@ -2756,14 +2623,10 @@ lookup_vi_for_tree (tree t)
 static const char *
 alias_get_name (tree decl)
 {
-  const char *res;
+  const char *res = get_name (decl);
   char *temp;
   int num_printed = 0;
 
-  if (DECL_ASSEMBLER_NAME_SET_P (decl))
-    res = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  else
-    res= get_name (decl);
   if (res != NULL)
     return res;
 
@@ -2896,16 +2759,6 @@ process_constraint (constraint_t t)
   /* ADDRESSOF on the lhs is invalid.  */
   gcc_assert (lhs.type != ADDRESSOF);
 
-  /* We shouldn't add constraints from things that cannot have pointers.
-     It's not completely trivial to avoid in the callers, so do it here.  */
-  if (rhs.type != ADDRESSOF
-      && !get_varinfo (rhs.var)->may_have_pointers)
-    return;
-
-  /* Likewise adding to the solution of a non-pointer var isn't useful.  */
-  if (!get_varinfo (lhs.var)->may_have_pointers)
-    return;
-
   /* This can happen in our IR with things like n->a = *p */
   if (rhs.type == DEREF && lhs.type == DEREF && rhs.var != anything_id)
     {
@@ -2941,12 +2794,6 @@ type_could_have_pointers (tree type)
   if (TREE_CODE (type) == ARRAY_TYPE)
     return type_could_have_pointers (TREE_TYPE (type));
 
-  /* A function or method can consume pointers.
-     ???  We could be more precise here.  */
-  if (TREE_CODE (type) == FUNCTION_TYPE
-      || TREE_CODE (type) == METHOD_TYPE)
-    return true;
-
   return AGGREGATE_TYPE_P (type);
 }
 
@@ -2956,11 +2803,7 @@ type_could_have_pointers (tree type)
 static bool
 could_have_pointers (tree t)
 {
-  return (((TREE_CODE (t) == VAR_DECL
-           || TREE_CODE (t) == PARM_DECL
-           || TREE_CODE (t) == RESULT_DECL)
-          && (TREE_PUBLIC (t) || DECL_EXTERNAL (t) || TREE_ADDRESSABLE (t)))
-         || type_could_have_pointers (TREE_TYPE (t)));
+  return type_could_have_pointers (TREE_TYPE (t));
 }
 
 /* Return the position, in bits, of FIELD_DECL from the beginning of its
@@ -3291,18 +3134,14 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
      in that case *NULL does not fail, so it _should_ alias *anything.
      It is not worth adding a new option or renaming the existing one,
      since this case is relatively obscure.  */
-  if ((TREE_CODE (t) == INTEGER_CST
-       && integer_zerop (t))
-      /* The only valid CONSTRUCTORs in gimple with pointer typed
-        elements are zero-initializer.  But in IPA mode we also
-        process global initializers, so verify at least.  */
-      || (TREE_CODE (t) == CONSTRUCTOR
-         && CONSTRUCTOR_NELTS (t) == 0))
-    {
-      if (flag_delete_null_pointer_checks)
-       temp.var = nothing_id;
-      else
-       temp.var = anything_id;
+  if (flag_delete_null_pointer_checks
+      && ((TREE_CODE (t) == INTEGER_CST
+          && integer_zerop (t))
+         /* The only valid CONSTRUCTORs in gimple with pointer typed
+            elements are zero-initializer.  */
+         || TREE_CODE (t) == CONSTRUCTOR))
+    {
+      temp.var = nothing_id;
       temp.type = ADDRESSOF;
       temp.offset = 0;
       VEC_safe_push (ce_s, heap, *results, &temp);
@@ -3364,26 +3203,6 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p)
              get_constraint_for_ssa_var (t, results, address_p);
              return;
            }
-         case CONSTRUCTOR:
-           {
-             unsigned int i;
-             tree val;
-             VEC (ce_s, heap) *tmp = NULL;
-             FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), i, val)
-               {
-                 struct constraint_expr *rhsp;
-                 unsigned j;
-                 get_constraint_for_1 (val, &tmp, address_p);
-                 for (j = 0; VEC_iterate (ce_s, tmp, j, rhsp); ++j)
-                   VEC_safe_push (ce_s, heap, *results, rhsp);
-                 VEC_truncate (ce_s, tmp, 0);
-               }
-             VEC_free (ce_s, heap, tmp);
-             /* We do not know whether the constructor was complete,
-                so technically we have to add &NOTHING or &ANYTHING
-                like we do for an empty constructor as well.  */
-             return;
-           }
          default:;
          }
        break;
@@ -3458,19 +3277,7 @@ do_structure_copy (tree lhsop, tree rhsop)
   if (lhsp->type == DEREF
       || (lhsp->type == ADDRESSOF && lhsp->var == anything_id)
       || rhsp->type == DEREF)
-    {
-      if (lhsp->type == DEREF)
-       {
-         gcc_assert (VEC_length (ce_s, lhsc) == 1);
-         lhsp->offset = UNKNOWN_OFFSET;
-       }
-      if (rhsp->type == DEREF)
-       {
-         gcc_assert (VEC_length (ce_s, rhsc) == 1);
-         rhsp->offset = UNKNOWN_OFFSET;
-       }
-      process_all_all_constraints (lhsc, rhsc);
-    }
+    process_all_all_constraints (lhsc, rhsc);
   else if (lhsp->type == SCALAR
           && (rhsp->type == SCALAR
               || rhsp->type == ADDRESSOF))
@@ -3570,37 +3377,11 @@ make_escape_constraint (tree op)
   make_constraint_to (escaped_id, op);
 }
 
-/* Add constraints to that the solution of VI is transitively closed.  */
-
-static void
-make_transitive_closure_constraints (varinfo_t vi)
-{
-  struct constraint_expr lhs, rhs;
-
-  /* VAR = *VAR;  */
-  lhs.type = SCALAR;
-  lhs.var = vi->id;
-  lhs.offset = 0;
-  rhs.type = DEREF;
-  rhs.var = vi->id;
-  rhs.offset = 0;
-  process_constraint (new_constraint (lhs, rhs));
-
-  /* VAR = VAR + UNKNOWN;  */
-  lhs.type = SCALAR;
-  lhs.var = vi->id;
-  lhs.offset = 0;
-  rhs.type = SCALAR;
-  rhs.var = vi->id;
-  rhs.offset = UNKNOWN_OFFSET;
-  process_constraint (new_constraint (lhs, rhs));
-}
-
-/* Create a new artificial heap variable with NAME.
-   Return the created variable.  */
+/* Create a new artificial heap variable with NAME and make a
+   constraint from it to LHS.  Return the created variable.  */
 
 static varinfo_t
-make_heapvar_for (varinfo_t lhs, const char *name)
+make_constraint_from_heapvar (varinfo_t lhs, const char *name)
 {
   varinfo_t vi;
   tree heapvar = heapvar_lookup (lhs->decl, lhs->offset);
@@ -3619,7 +3400,7 @@ make_heapvar_for (varinfo_t lhs, const char *name)
 
   /* For global vars we need to add a heapvar to the list of referenced
      vars of a different function than it was created for originally.  */
-  if (cfun && gimple_referenced_vars (cfun))
+  if (gimple_referenced_vars (cfun))
     add_referenced_var (heapvar);
 
   vi = new_var_info (heapvar, name);
@@ -3632,16 +3413,6 @@ make_heapvar_for (varinfo_t lhs, const char *name)
   vi->is_full_var = true;
   insert_vi_for_tree (heapvar, vi);
 
-  return vi;
-}
-
-/* Create a new artificial heap variable with NAME and make a
-   constraint from it to LHS.  Return the created variable.  */
-
-static varinfo_t
-make_constraint_from_heapvar (varinfo_t lhs, const char *name)
-{
-  varinfo_t vi = make_heapvar_for (lhs, name);
   make_constraint_from (lhs, vi->id);
 
   return vi;
@@ -3662,52 +3433,6 @@ make_constraint_from_restrict (varinfo_t lhs, const char *name)
   vi->may_have_pointers = 0;
 }
 
-/* In IPA mode there are varinfos for different aspects of reach
-   function designator.  One for the points-to set of the return
-   value, one for the variables that are clobbered by the function,
-   one for its uses and one for each parameter (including a single
-   glob for remaining variadic arguments).  */
-
-enum { fi_clobbers = 1, fi_uses = 2,
-       fi_static_chain = 3, fi_result = 4, fi_parm_base = 5 };
-
-/* Get a constraint for the requested part of a function designator FI
-   when operating in IPA mode.  */
-
-static struct constraint_expr
-get_function_part_constraint (varinfo_t fi, unsigned part)
-{
-  struct constraint_expr c;
-
-  gcc_assert (in_ipa_mode);
-
-  if (fi->id == anything_id)
-    {
-      /* ???  We probably should have a ANYFN special variable.  */
-      c.var = anything_id;
-      c.offset = 0;
-      c.type = SCALAR;
-    }
-  else if (TREE_CODE (fi->decl) == FUNCTION_DECL)
-    {
-      varinfo_t ai = first_vi_for_offset (fi, part);
-      if (ai)
-       c.var = ai->id;
-      else
-       c.var = anything_id;
-      c.offset = 0;
-      c.type = SCALAR;
-    }
-  else
-    {
-      c.var = fi->id;
-      c.offset = part;
-      c.type = DEREF;
-    }
-
-  return c;
-}
-
 /* For non-IPA mode, generate constraints necessary for a call on the
    RHS.  */
 
@@ -3716,61 +3441,17 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results)
 {
   struct constraint_expr rhsc;
   unsigned i;
-  bool returns_uses = false;
 
   for (i = 0; i < gimple_call_num_args (stmt); ++i)
     {
       tree arg = gimple_call_arg (stmt, i);
-      int flags = gimple_call_arg_flags (stmt, i);
-
-      /* If the argument is not used or it does not contain pointers
-        we can ignore it.  */
-      if ((flags & EAF_UNUSED)
-         || !could_have_pointers (arg))
-       continue;
 
-      /* As we compute ESCAPED context-insensitive we do not gain
-         any precision with just EAF_NOCLOBBER but not EAF_NOESCAPE
-        set.  The argument would still get clobbered through the
-        escape solution.
-        ???  We might get away with less (and more precise) constraints
-        if using a temporary for transitively closing things.  */
-      if ((flags & EAF_NOCLOBBER)
-          && (flags & EAF_NOESCAPE))
-       {
-         varinfo_t uses = get_call_use_vi (stmt);
-         if (!(flags & EAF_DIRECT))
-           make_transitive_closure_constraints (uses);
-         make_constraint_to (uses->id, arg);
-         returns_uses = true;
-       }
-      else if (flags & EAF_NOESCAPE)
-       {
-         varinfo_t uses = get_call_use_vi (stmt);
-         varinfo_t clobbers = get_call_clobber_vi (stmt);
-         if (!(flags & EAF_DIRECT))
-           {
-             make_transitive_closure_constraints (uses);
-             make_transitive_closure_constraints (clobbers);
-           }
-         make_constraint_to (uses->id, arg);
-         make_constraint_to (clobbers->id, arg);
-         returns_uses = true;
-       }
-      else
+      /* Find those pointers being passed, and make sure they end up
+        pointing to anything.  */
+      if (could_have_pointers (arg))
        make_escape_constraint (arg);
     }
 
-  /* If we added to the calls uses solution make sure we account for
-     pointers to it to be returned.  */
-  if (returns_uses)
-    {
-      rhsc.var = get_call_use_vi (stmt)->id;
-      rhsc.offset = 0;
-      rhsc.type = SCALAR;
-      VEC_safe_push (ce_s, heap, *results, &rhsc);
-    }
-
   /* The static chain escapes as well.  */
   if (gimple_call_chain (stmt))
     make_escape_constraint (gimple_call_chain (stmt));
@@ -3803,63 +3484,44 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results)
    the LHS point to global and escaped variables.  */
 
 static void
-handle_lhs_call (gimple stmt, tree lhs, int flags, VEC(ce_s, heap) *rhsc,
-                tree fndecl)
+handle_lhs_call (tree lhs, int flags, VEC(ce_s, heap) *rhsc, tree fndecl)
 {
   VEC(ce_s, heap) *lhsc = NULL;
 
   get_constraint_for (lhs, &lhsc);
-  /* If the store is to a global decl make sure to
-     add proper escape constraints.  */
-  lhs = get_base_address (lhs);
-  if (lhs
-      && DECL_P (lhs)
-      && is_global_var (lhs))
-    {
-      struct constraint_expr tmpc;
-      tmpc.var = escaped_id;
-      tmpc.offset = 0;
-      tmpc.type = SCALAR;
-      VEC_safe_push (ce_s, heap, lhsc, &tmpc);
-    }
 
-  /* If the call returns an argument unmodified override the rhs
-     constraints.  */
-  flags = gimple_call_return_flags (stmt);
-  if (flags & ERF_RETURNS_ARG
-      && (flags & ERF_RETURN_ARG_MASK) < gimple_call_num_args (stmt))
-    {
-      tree arg;
-      rhsc = NULL;
-      arg = gimple_call_arg (stmt, flags & ERF_RETURN_ARG_MASK);
-      get_constraint_for (arg, &rhsc);
-      process_all_all_constraints (lhsc, rhsc);
-      VEC_free (ce_s, heap, rhsc);
-    }
-  else if (flags & ERF_NOALIAS)
+  if (flags & ECF_MALLOC)
     {
       varinfo_t vi;
-      struct constraint_expr tmpc;
-      rhsc = NULL;
-      vi = make_heapvar_for (get_vi_for_tree (lhs), "HEAP");
+      vi = make_constraint_from_heapvar (get_vi_for_tree (lhs), "HEAP");
       /* We delay marking allocated storage global until we know if
          it escapes.  */
       DECL_EXTERNAL (vi->decl) = 0;
       vi->is_global_var = 0;
       /* If this is not a real malloc call assume the memory was
-        initialized and thus may point to global memory.  All
+         initialized and thus may point to global memory.  All
         builtin functions with the malloc attribute behave in a sane way.  */
       if (!fndecl
          || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
        make_constraint_from (vi, nonlocal_id);
-      tmpc.var = vi->id;
-      tmpc.offset = 0;
-      tmpc.type = ADDRESSOF;
-      VEC_safe_push (ce_s, heap, rhsc, &tmpc);
     }
-
-  process_all_all_constraints (lhsc, rhsc);
-
+  else if (VEC_length (ce_s, rhsc) > 0)
+    {
+      /* If the store is to a global decl make sure to
+        add proper escape constraints.  */
+      lhs = get_base_address (lhs);
+      if (lhs
+         && DECL_P (lhs)
+         && is_global_var (lhs))
+       {
+         struct constraint_expr tmpc;
+         tmpc.var = escaped_id;
+         tmpc.offset = 0;
+         tmpc.type = SCALAR;
+         VEC_safe_push (ce_s, heap, lhsc, &tmpc);
+       }
+      process_all_all_constraints (lhsc, rhsc);
+    }
   VEC_free (ce_s, heap, lhsc);
 }
 
@@ -3876,10 +3538,8 @@ handle_const_call (gimple stmt, VEC(ce_s, heap) **results)
      as the static chain is concerned.  */
   if (gimple_call_chain (stmt))
     {
-      varinfo_t uses = get_call_use_vi (stmt);
-      make_transitive_closure_constraints (uses);
-      make_constraint_to (uses->id, gimple_call_chain (stmt));
-      rhsc.var = uses->id;
+      make_constraint_to (callused_id, gimple_call_chain (stmt));
+      rhsc.var = callused_id;
       rhsc.offset = 0;
       rhsc.type = SCALAR;
       VEC_safe_push (ce_s, heap, *results, &rhsc);
@@ -3917,7 +3577,7 @@ handle_pure_call (gimple stmt, VEC(ce_s, heap) **results)
 {
   struct constraint_expr rhsc;
   unsigned i;
-  varinfo_t uses = NULL;
+  bool need_callused = false;
 
   /* Memory reached from pointer arguments is call-used.  */
   for (i = 0; i < gimple_call_num_args (stmt); ++i)
@@ -3926,30 +3586,22 @@ handle_pure_call (gimple stmt, VEC(ce_s, heap) **results)
 
       if (could_have_pointers (arg))
        {
-         if (!uses)
-           {
-             uses = get_call_use_vi (stmt);
-             make_transitive_closure_constraints (uses);
-           }
-         make_constraint_to (uses->id, arg);
+         make_constraint_to (callused_id, arg);
+         need_callused = true;
        }
     }
 
   /* The static chain is used as well.  */
   if (gimple_call_chain (stmt))
     {
-      if (!uses)
-       {
-         uses = get_call_use_vi (stmt);
-         make_transitive_closure_constraints (uses);
-       }
-      make_constraint_to (uses->id, gimple_call_chain (stmt));
+      make_constraint_to (callused_id, gimple_call_chain (stmt));
+      need_callused = true;
     }
 
-  /* Pure functions may return call-used and nonlocal memory.  */
-  if (uses)
+  /* Pure functions may return callused and nonlocal memory.  */
+  if (need_callused)
     {
-      rhsc.var = uses->id;
+      rhsc.var = callused_id;
       rhsc.offset = 0;
       rhsc.type = SCALAR;
       VEC_safe_push (ce_s, heap, *results, &rhsc);
@@ -3960,40 +3612,6 @@ handle_pure_call (gimple stmt, VEC(ce_s, heap) **results)
   VEC_safe_push (ce_s, heap, *results, &rhsc);
 }
 
-
-/* Return the varinfo for the callee of CALL.  */
-
-static varinfo_t
-get_fi_for_callee (gimple call)
-{
-  tree decl;
-
-  /* If we can directly resolve the function being called, do so.
-     Otherwise, it must be some sort of indirect expression that
-     we should still be able to handle.  */
-  decl = gimple_call_fndecl (call);
-  if (decl)
-    return get_vi_for_tree (decl);
-
-  decl = gimple_call_fn (call);
-  /* The function can be either an SSA name pointer or,
-     worse, an OBJ_TYPE_REF.  In this case we have no
-     clue and should be getting ANYFN (well, ANYTHING for now).  */
-  if (TREE_CODE (decl) == SSA_NAME)
-    {
-      if (TREE_CODE (decl) == SSA_NAME
-         && TREE_CODE (SSA_NAME_VAR (decl)) == PARM_DECL
-         && SSA_NAME_IS_DEFAULT_DEF (decl))
-       decl = SSA_NAME_VAR (decl);
-      return get_vi_for_tree (decl);
-    }
-  else if (TREE_CODE (decl) == INTEGER_CST
-          || TREE_CODE (decl) == OBJ_TYPE_REF)
-    return get_varinfo (anything_id);
-  else
-    gcc_unreachable ();
-}
-
 /* Walk statement T setting up aliasing constraints according to the
    references found in T.  This function is the main part of the
    constraint builder.  AI points to auxiliary alias information used
@@ -4006,7 +3624,6 @@ find_func_aliases (gimple origt)
   VEC(ce_s, heap) *lhsc = NULL;
   VEC(ce_s, heap) *rhsc = NULL;
   struct constraint_expr *c;
-  varinfo_t fi;
 
   /* Now build constraints expressions.  */
   if (gimple_code (t) == GIMPLE_PHI)
@@ -4159,88 +3776,6 @@ find_func_aliases (gimple origt)
          case BUILT_IN_REMQUOL:
          case BUILT_IN_FREE:
            return;
-         /* Trampolines are special - they set up passing the static
-            frame.  */
-         case BUILT_IN_INIT_TRAMPOLINE:
-           {
-             tree tramp = gimple_call_arg (t, 0);
-             tree nfunc = gimple_call_arg (t, 1);
-             tree frame = gimple_call_arg (t, 2);
-             unsigned i;
-             struct constraint_expr lhs, *rhsp;
-             if (in_ipa_mode)
-               {
-                 varinfo_t nfi = NULL;
-                 gcc_assert (TREE_CODE (nfunc) == ADDR_EXPR);
-                 nfi = lookup_vi_for_tree (TREE_OPERAND (nfunc, 0));
-                 if (nfi)
-                   {
-                     lhs = get_function_part_constraint (nfi, fi_static_chain);
-                     get_constraint_for (frame, &rhsc);
-                     for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); ++i)
-                       process_constraint (new_constraint (lhs, *rhsp));
-                     VEC_free (ce_s, heap, rhsc);
-
-                     /* Make the frame point to the function for
-                        the trampoline adjustment call.  */
-                     get_constraint_for (tramp, &lhsc);
-                     do_deref (&lhsc);
-                     get_constraint_for (nfunc, &rhsc);
-                     process_all_all_constraints (lhsc, rhsc);
-                     VEC_free (ce_s, heap, rhsc);
-                     VEC_free (ce_s, heap, lhsc);
-
-                     return;
-                   }
-               }
-             /* Else fallthru to generic handling which will let
-                the frame escape.  */
-             break;
-           }
-         case BUILT_IN_ADJUST_TRAMPOLINE:
-           {
-             tree tramp = gimple_call_arg (t, 0);
-             tree res = gimple_call_lhs (t);
-             if (in_ipa_mode && res)
-               {
-                 get_constraint_for (res, &lhsc);
-                 get_constraint_for (tramp, &rhsc);
-                 do_deref (&rhsc);
-                 process_all_all_constraints (lhsc, rhsc);
-                 VEC_free (ce_s, heap, rhsc);
-                 VEC_free (ce_s, heap, lhsc);
-               }
-             return;
-           }
-         /* Variadic argument handling needs to be handled in IPA
-            mode as well.  */
-         case BUILT_IN_VA_START:
-           {
-             if (in_ipa_mode)
-               {
-                 tree valist = gimple_call_arg (t, 0);
-                 struct constraint_expr rhs, *lhsp;
-                 unsigned i;
-                 /* The va_list gets access to pointers in variadic
-                    arguments.  */
-                 fi = lookup_vi_for_tree (cfun->decl);
-                 gcc_assert (fi != NULL);
-                 get_constraint_for (valist, &lhsc);
-                 do_deref (&lhsc);
-                 rhs = get_function_part_constraint (fi, ~0);
-                 rhs.type = ADDRESSOF;
-                 for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); ++i)
-                   process_constraint (new_constraint (*lhsp, rhs));
-                 VEC_free (ce_s, heap, lhsc);
-                 /* va_list is clobbered.  */
-                 make_constraint_to (get_call_clobber_vi (t)->id, valist);
-                 return;
-               }
-             break;
-           }
-         /* va_end doesn't have any effect that matters.  */
-         case BUILT_IN_VA_END:
-           return;
          /* printf-style functions may have hooks to set pointers to
             point to somewhere into the generated string.  Leave them
             for a later excercise...  */
@@ -4249,8 +3784,7 @@ find_func_aliases (gimple origt)
          }
       if (!in_ipa_mode
          || (fndecl
-             && (!(fi = lookup_vi_for_tree (fndecl))
-                 || !fi->is_fn_info)))
+             && !lookup_vi_for_tree (fndecl)))
        {
          VEC(ce_s, heap) *rhsc = NULL;
          int flags = gimple_call_flags (t);
@@ -4272,15 +3806,30 @@ find_func_aliases (gimple origt)
            handle_rhs_call (t, &rhsc);
          if (gimple_call_lhs (t)
              && could_have_pointers (gimple_call_lhs (t)))
-           handle_lhs_call (t, gimple_call_lhs (t), flags, rhsc, fndecl);
+           handle_lhs_call (gimple_call_lhs (t), flags, rhsc, fndecl);
          VEC_free (ce_s, heap, rhsc);
        }
       else
        {
          tree lhsop;
-         unsigned j;
+         varinfo_t fi;
+         int i = 1;
+         size_t j;
+         tree decl;
+
+         lhsop = gimple_call_lhs (t);
+         decl = gimple_call_fndecl (t);
 
-         fi = get_fi_for_callee (t);
+         /* If we can directly resolve the function being called, do so.
+            Otherwise, it must be some sort of indirect expression that
+            we should still be able to handle.  */
+         if (decl)
+           fi = get_vi_for_tree (decl);
+         else
+           {
+             decl = gimple_call_fn (t);
+             fi = get_vi_for_tree (decl);
+           }
 
          /* Assign all the passed arguments to the appropriate incoming
             parameters of the function.  */
@@ -4290,77 +3839,58 @@ find_func_aliases (gimple origt)
              struct constraint_expr *rhsp;
              tree arg = gimple_call_arg (t, j);
 
-             if (!could_have_pointers (arg))
-               continue;
-
              get_constraint_for (arg, &rhsc);
-             lhs = get_function_part_constraint (fi, fi_parm_base + j);
+             if (TREE_CODE (decl) != FUNCTION_DECL)
+               {
+                 lhs.type = DEREF;
+                 lhs.var = fi->id;
+                 lhs.offset = i;
+               }
+             else
+               {
+                 lhs.type = SCALAR;
+                 lhs.var = first_vi_for_offset (fi, i)->id;
+                 lhs.offset = 0;
+               }
              while (VEC_length (ce_s, rhsc) != 0)
                {
                  rhsp = VEC_last (ce_s, rhsc);
                  process_constraint (new_constraint (lhs, *rhsp));
                  VEC_pop (ce_s, rhsc);
                }
+             i++;
            }
 
          /* If we are returning a value, assign it to the result.  */
-         lhsop = gimple_call_lhs (t);
-         if (lhsop
-             && type_could_have_pointers (TREE_TYPE (lhsop)))
+         if (lhsop)
            {
              struct constraint_expr rhs;
              struct constraint_expr *lhsp;
+             unsigned int j = 0;
 
              get_constraint_for (lhsop, &lhsc);
-             rhs = get_function_part_constraint (fi, fi_result);
-             if (fndecl
-                 && DECL_RESULT (fndecl)
-                 && DECL_BY_REFERENCE (DECL_RESULT (fndecl)))
+             if (TREE_CODE (decl) != FUNCTION_DECL)
                {
-                 VEC(ce_s, heap) *tem = NULL;
-                 VEC_safe_push (ce_s, heap, tem, &rhs);
-                 do_deref (&tem);
-                 rhs = *VEC_index (ce_s, tem, 0);
-                 VEC_free(ce_s, heap, tem);
+                 rhs.type = DEREF;
+                 rhs.var = fi->id;
+                 rhs.offset = i;
+               }
+             else
+               {
+                 rhs.type = SCALAR;
+                 rhs.var = first_vi_for_offset (fi, i)->id;
+                 rhs.offset = 0;
                }
              for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
                process_constraint (new_constraint (*lhsp, rhs));
            }
-
-         /* If we pass the result decl by reference, honor that.  */
-         if (lhsop
-             && fndecl
-             && DECL_RESULT (fndecl)
-             && DECL_BY_REFERENCE (DECL_RESULT (fndecl)))
-           {
-             struct constraint_expr lhs;
-             struct constraint_expr *rhsp;
-
-             get_constraint_for_address_of (lhsop, &rhsc);
-             lhs = get_function_part_constraint (fi, fi_result);
-             for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); j++)
-               process_constraint (new_constraint (lhs, *rhsp));
-             VEC_free (ce_s, heap, rhsc);
-           }
-
-         /* If we use a static chain, pass it along.  */
-         if (gimple_call_chain (t))
-           {
-             struct constraint_expr lhs;
-             struct constraint_expr *rhsp;
-
-             get_constraint_for (gimple_call_chain (t), &rhsc);
-             lhs = get_function_part_constraint (fi, fi_static_chain);
-             for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); j++)
-               process_constraint (new_constraint (lhs, *rhsp));
-           }
        }
     }
   /* Otherwise, just a regular assignment statement.  Only care about
      operations with pointer result, others are dealt with as escape
      points if they have pointer operands.  */
   else if (is_gimple_assign (t)
-          && type_could_have_pointers (TREE_TYPE (gimple_assign_lhs (t))))
+          && could_have_pointers (gimple_assign_lhs (t)))
     {
       /* Otherwise, just a regular assignment statement.  */
       tree lhsop = gimple_assign_lhs (t);
@@ -4393,9 +3923,7 @@ find_func_aliases (gimple origt)
       /* If there is a store to a global variable the rhs escapes.  */
       if ((lhsop = get_base_address (lhsop)) != NULL_TREE
          && DECL_P (lhsop)
-         && is_global_var (lhsop)
-         && (!in_ipa_mode
-             || DECL_EXTERNAL (lhsop) || TREE_PUBLIC (lhsop)))
+         && is_global_var (lhsop))
        make_escape_constraint (rhsop);
       /* If this is a conversion of a non-restrict pointer to a
         restrict pointer track it with a new heapvar.  */
@@ -4419,22 +3947,7 @@ find_func_aliases (gimple origt)
           && gimple_return_retval (t) != NULL_TREE
           && could_have_pointers (gimple_return_retval (t)))
     {
-      fi = NULL;
-      if (!in_ipa_mode
-         || !(fi = get_vi_for_tree (cfun->decl)))
-       make_escape_constraint (gimple_return_retval (t));
-      else if (in_ipa_mode
-              && fi != NULL)
-       {
-         struct constraint_expr lhs ;
-         struct constraint_expr *rhsp;
-         unsigned i;
-
-         lhs = get_function_part_constraint (fi, fi_result);
-         get_constraint_for (gimple_return_retval (t), &rhsc);
-         for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); i++)
-           process_constraint (new_constraint (lhs, *rhsp));
-       }
+      make_escape_constraint (gimple_return_retval (t));
     }
   /* Handle asms conservatively by adding escape constraints to everything.  */
   else if (gimple_code (t) == GIMPLE_ASM)
@@ -4491,8 +4004,8 @@ find_func_aliases (gimple origt)
          if (!allows_reg && allows_mem)
            make_escape_constraint (build_fold_addr_expr (op));
          /* Strictly we'd only need the constraint to ESCAPED if
-            the asm clobbers memory, otherwise using something
-            along the lines of per-call clobbers/uses would be enough.  */
+            the asm clobbers memory, otherwise using CALLUSED
+            would be enough.  */
          else if (op && could_have_pointers (op))
            make_escape_constraint (op);
        }
@@ -4503,297 +4016,20 @@ find_func_aliases (gimple origt)
 }
 
 
-/* Create a constraint adding to the clobber set of FI the memory
-   pointed to by PTR.  */
-
-static void
-process_ipa_clobber (varinfo_t fi, tree ptr)
-{
-  VEC(ce_s, heap) *ptrc = NULL;
-  struct constraint_expr *c, lhs;
-  unsigned i;
-  get_constraint_for (ptr, &ptrc);
-  lhs = get_function_part_constraint (fi, fi_clobbers);
-  for (i = 0; VEC_iterate (ce_s, ptrc, i, c); i++)
-    process_constraint (new_constraint (lhs, *c));
-  VEC_free (ce_s, heap, ptrc);
-}
-
-/* Walk statement T setting up clobber and use constraints according to the
-   references found in T.  This function is a main part of the
-   IPA constraint builder.  */
+/* Find the first varinfo in the same variable as START that overlaps with
+   OFFSET.  Return NULL if we can't find one.  */
 
-static void
-find_func_clobbers (gimple origt)
+static varinfo_t
+first_vi_for_offset (varinfo_t start, unsigned HOST_WIDE_INT offset)
 {
-  gimple t = origt;
-  VEC(ce_s, heap) *lhsc = NULL;
-  VEC(ce_s, heap) *rhsc = NULL;
-  varinfo_t fi;
+  /* If the offset is outside of the variable, bail out.  */
+  if (offset >= start->fullsize)
+    return NULL;
 
-  /* Add constraints for clobbered/used in IPA mode.
-     We are not interested in what automatic variables are clobbered
-     or used as we only use the information in the caller to which
-     they do not escape.  */
-  gcc_assert (in_ipa_mode);
-
-  /* If the stmt refers to memory in any way it better had a VUSE.  */
-  if (gimple_vuse (t) == NULL_TREE)
-    return;
-
-  /* We'd better have function information for the current function.  */
-  fi = lookup_vi_for_tree (cfun->decl);
-  gcc_assert (fi != NULL);
-
-  /* Account for stores in assignments and calls.  */
-  if (gimple_vdef (t) != NULL_TREE
-      && gimple_has_lhs (t))
-    {
-      tree lhs = gimple_get_lhs (t);
-      tree tem = lhs;
-      while (handled_component_p (tem))
-       tem = TREE_OPERAND (tem, 0);
-      if ((DECL_P (tem)
-          && !auto_var_in_fn_p (tem, cfun->decl))
-         || INDIRECT_REF_P (tem))
-       {
-         struct constraint_expr lhsc, *rhsp;
-         unsigned i;
-         lhsc = get_function_part_constraint (fi, fi_clobbers);
-         get_constraint_for_address_of (lhs, &rhsc);
-         for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); i++)
-           process_constraint (new_constraint (lhsc, *rhsp));
-         VEC_free (ce_s, heap, rhsc);
-       }
-    }
-
-  /* Account for uses in assigments and returns.  */
-  if (gimple_assign_single_p (t)
-      || (gimple_code (t) == GIMPLE_RETURN
-         && gimple_return_retval (t) != NULL_TREE))
-    {
-      tree rhs = (gimple_assign_single_p (t)
-                 ? gimple_assign_rhs1 (t) : gimple_return_retval (t));
-      tree tem = rhs;
-      while (handled_component_p (tem))
-       tem = TREE_OPERAND (tem, 0);
-      if ((DECL_P (tem)
-          && !auto_var_in_fn_p (tem, cfun->decl))
-         || INDIRECT_REF_P (tem))
-       {
-         struct constraint_expr lhs, *rhsp;
-         unsigned i;
-         lhs = get_function_part_constraint (fi, fi_uses);
-         get_constraint_for_address_of (rhs, &rhsc);
-         for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); i++)
-           process_constraint (new_constraint (lhs, *rhsp));
-         VEC_free (ce_s, heap, rhsc);
-       }
-    }
-
-  if (is_gimple_call (t))
-    {
-      varinfo_t cfi = NULL;
-      tree decl = gimple_call_fndecl (t);
-      struct constraint_expr lhs, rhs;
-      unsigned i, j;
-
-      /* For builtins we do not have separate function info.  For those
-        we do not generate escapes for we have to generate clobbers/uses.  */
-      if (decl
-         && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
-       switch (DECL_FUNCTION_CODE (decl))
-         {
-         /* The following functions use and clobber memory pointed to
-            by their arguments.  */
-         case BUILT_IN_STRCPY:
-         case BUILT_IN_STRNCPY:
-         case BUILT_IN_BCOPY:
-         case BUILT_IN_MEMCPY:
-         case BUILT_IN_MEMMOVE:
-         case BUILT_IN_MEMPCPY:
-         case BUILT_IN_STPCPY:
-         case BUILT_IN_STPNCPY:
-         case BUILT_IN_STRCAT:
-         case BUILT_IN_STRNCAT:
-           {
-             tree dest = gimple_call_arg (t, (DECL_FUNCTION_CODE (decl)
-                                              == BUILT_IN_BCOPY ? 1 : 0));
-             tree src = gimple_call_arg (t, (DECL_FUNCTION_CODE (decl)
-                                             == BUILT_IN_BCOPY ? 0 : 1));
-             unsigned i;
-             struct constraint_expr *rhsp, *lhsp;
-             get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
-             lhs = get_function_part_constraint (fi, fi_clobbers);
-             for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); i++)
-               process_constraint (new_constraint (lhs, *lhsp));
-             VEC_free (ce_s, heap, lhsc);
-             get_constraint_for_ptr_offset (src, NULL_TREE, &rhsc);
-             lhs = get_function_part_constraint (fi, fi_uses);
-             for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); i++)
-               process_constraint (new_constraint (lhs, *rhsp));
-             VEC_free (ce_s, heap, rhsc);
-             return;
-           }
-         /* The following function clobbers memory pointed to by
-            its argument.  */
-         case BUILT_IN_MEMSET:
-           {
-             tree dest = gimple_call_arg (t, 0);
-             unsigned i;
-             ce_s *lhsp;
-             get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
-             lhs = get_function_part_constraint (fi, fi_clobbers);
-             for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); i++)
-               process_constraint (new_constraint (lhs, *lhsp));
-             VEC_free (ce_s, heap, lhsc);
-             return;
-           }
-         /* The following functions clobber their second and third
-            arguments.  */
-         case BUILT_IN_SINCOS:
-         case BUILT_IN_SINCOSF:
-         case BUILT_IN_SINCOSL:
-           {
-             process_ipa_clobber (fi, gimple_call_arg (t, 1));
-             process_ipa_clobber (fi, gimple_call_arg (t, 2));
-             return;
-           }
-         /* The following functions clobber their second argument.  */
-         case BUILT_IN_FREXP:
-         case BUILT_IN_FREXPF:
-         case BUILT_IN_FREXPL:
-         case BUILT_IN_LGAMMA_R:
-         case BUILT_IN_LGAMMAF_R:
-         case BUILT_IN_LGAMMAL_R:
-         case BUILT_IN_GAMMA_R:
-         case BUILT_IN_GAMMAF_R:
-         case BUILT_IN_GAMMAL_R:
-         case BUILT_IN_MODF:
-         case BUILT_IN_MODFF:
-         case BUILT_IN_MODFL:
-           {
-             process_ipa_clobber (fi, gimple_call_arg (t, 1));
-             return;
-           }
-         /* The following functions clobber their third argument.  */
-         case BUILT_IN_REMQUO:
-         case BUILT_IN_REMQUOF:
-         case BUILT_IN_REMQUOL:
-           {
-             process_ipa_clobber (fi, gimple_call_arg (t, 2));
-             return;
-           }
-         /* The following functions neither read nor clobber memory.  */
-         case BUILT_IN_FREE:
-           return;
-         /* Trampolines are of no interest to us.  */
-         case BUILT_IN_INIT_TRAMPOLINE:
-         case BUILT_IN_ADJUST_TRAMPOLINE:
-           return;
-         case BUILT_IN_VA_START:
-         case BUILT_IN_VA_END:
-           return;
-         /* printf-style functions may have hooks to set pointers to
-            point to somewhere into the generated string.  Leave them
-            for a later excercise...  */
-         default:
-           /* Fallthru to general call handling.  */;
-         }
-
-      /* Parameters passed by value are used.  */
-      lhs = get_function_part_constraint (fi, fi_uses);
-      for (i = 0; i < gimple_call_num_args (t); i++)
-       {
-         struct constraint_expr *rhsp;
-         tree arg = gimple_call_arg (t, i);
-
-         if (TREE_CODE (arg) == SSA_NAME
-             || is_gimple_min_invariant (arg))
-           continue;
-
-         get_constraint_for_address_of (arg, &rhsc);
-         for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); j++)
-           process_constraint (new_constraint (lhs, *rhsp));
-         VEC_free (ce_s, heap, rhsc);
-       }
-
-      /* Build constraints for propagating clobbers/uses along the
-        callgraph edges.  */
-      cfi = get_fi_for_callee (t);
-      if (cfi->id == anything_id)
-       {
-         if (gimple_vdef (t))
-           make_constraint_from (first_vi_for_offset (fi, fi_clobbers),
-                                 anything_id);
-         make_constraint_from (first_vi_for_offset (fi, fi_uses),
-                               anything_id);
-         return;
-       }
-
-      /* For callees without function info (that's external functions),
-        ESCAPED is clobbered and used.  */
-      if (gimple_call_fndecl (t)
-         && !cfi->is_fn_info)
-       {
-         varinfo_t vi;
-
-         if (gimple_vdef (t))
-           make_copy_constraint (first_vi_for_offset (fi, fi_clobbers),
-                                 escaped_id);
-         make_copy_constraint (first_vi_for_offset (fi, fi_uses), escaped_id);
-
-         /* Also honor the call statement use/clobber info.  */
-         if ((vi = lookup_call_clobber_vi (t)) != NULL)
-           make_copy_constraint (first_vi_for_offset (fi, fi_clobbers),
-                                 vi->id);
-         if ((vi = lookup_call_use_vi (t)) != NULL)
-           make_copy_constraint (first_vi_for_offset (fi, fi_uses),
-                                 vi->id);
-         return;
-       }
-
-      /* Otherwise the caller clobbers and uses what the callee does.
-        ???  This should use a new complex constraint that filters
-        local variables of the callee.  */
-      if (gimple_vdef (t))
-       {
-         lhs = get_function_part_constraint (fi, fi_clobbers);
-         rhs = get_function_part_constraint (cfi, fi_clobbers);
-         process_constraint (new_constraint (lhs, rhs));
-       }
-      lhs = get_function_part_constraint (fi, fi_uses);
-      rhs = get_function_part_constraint (cfi, fi_uses);
-      process_constraint (new_constraint (lhs, rhs));
-    }
-  else if (gimple_code (t) == GIMPLE_ASM)
-    {
-      /* ???  Ick.  We can do better.  */
-      if (gimple_vdef (t))
-       make_constraint_from (first_vi_for_offset (fi, fi_clobbers),
-                             anything_id);
-      make_constraint_from (first_vi_for_offset (fi, fi_uses),
-                           anything_id);
-    }
-
-  VEC_free (ce_s, heap, rhsc);
-}
-
-
-/* Find the first varinfo in the same variable as START that overlaps with
-   OFFSET.  Return NULL if we can't find one.  */
-
-static varinfo_t
-first_vi_for_offset (varinfo_t start, unsigned HOST_WIDE_INT offset)
-{
-  /* If the offset is outside of the variable, bail out.  */
-  if (offset >= start->fullsize)
-    return NULL;
-
-  /* If we cannot reach offset from start, lookup the first field
-     and start from there.  */
-  if (start->offset > offset)
-    start = lookup_vi_for_tree (start->decl);
+  /* If we cannot reach offset from start, lookup the first field
+     and start from there.  */
+  if (start->offset > offset)
+    start = lookup_vi_for_tree (start->decl);
 
   while (start)
     {
@@ -4839,6 +4075,47 @@ first_or_preceding_vi_for_offset (varinfo_t start,
 }
 
 
+/* Insert the varinfo FIELD into the field list for BASE, at the front
+   of the list.  */
+
+static void
+insert_into_field_list (varinfo_t base, varinfo_t field)
+{
+  varinfo_t prev = base;
+  varinfo_t curr = base->next;
+
+  field->next = curr;
+  prev->next = field;
+}
+
+/* Insert the varinfo FIELD into the field list for BASE, ordered by
+   offset.  */
+
+static void
+insert_into_field_list_sorted (varinfo_t base, varinfo_t field)
+{
+  varinfo_t prev = base;
+  varinfo_t curr = base->next;
+
+  if (curr == NULL)
+    {
+      prev->next = field;
+      field->next = NULL;
+    }
+  else
+    {
+      while (curr)
+       {
+         if (field->offset <= curr->offset)
+           break;
+         prev = curr;
+         curr = curr->next;
+       }
+      field->next = prev->next;
+      prev->next = field;
+    }
+}
+
 /* This structure is used during pushing fields onto the fieldstack
    to track the offset of the field, since bitpos_of_field gives it
    relative to its immediate containing type, and we want it relative
@@ -4924,38 +4201,37 @@ var_can_have_subvars (const_tree v)
 
    OFFSET is used to keep track of the offset in this entire
    structure, rather than just the immediately containing structure.
-   Returns false if the caller is supposed to handle the field we
-   recursed for.  */
+   Returns the number of fields pushed.  */
 
-static bool
+static int
 push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
-                            HOST_WIDE_INT offset, bool must_have_pointers_p)
+                            HOST_WIDE_INT offset)
 {
   tree field;
-  bool empty_p = true;
+  int count = 0;
 
   if (TREE_CODE (type) != RECORD_TYPE)
-    return false;
+    return 0;
 
   /* If the vector of fields is growing too big, bail out early.
      Callers check for VEC_length <= MAX_FIELDS_FOR_FIELD_SENSITIVE, make
      sure this fails.  */
   if (VEC_length (fieldoff_s, *fieldstack) > MAX_FIELDS_FOR_FIELD_SENSITIVE)
-    return false;
+    return 0;
 
   for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
     if (TREE_CODE (field) == FIELD_DECL)
       {
        bool push = false;
+       int pushed = 0;
        HOST_WIDE_INT foff = bitpos_of_field (field);
 
        if (!var_can_have_subvars (field)
            || TREE_CODE (TREE_TYPE (field)) == QUAL_UNION_TYPE
            || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
          push = true;
-       else if (!push_fields_onto_fieldstack
-                   (TREE_TYPE (field), fieldstack, offset + foff,
-                    must_have_pointers_p)
+       else if (!(pushed = push_fields_onto_fieldstack
+                  (TREE_TYPE (field), fieldstack, offset + foff))
                 && (DECL_SIZE (field)
                     && !integer_zerop (DECL_SIZE (field))))
          /* Empty structures may have actual size, like in C++.  So
@@ -4978,12 +4254,12 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
            /* If adjacent fields do not contain pointers merge them.  */
            if (pair
                && !pair->may_have_pointers
+               && !could_have_pointers (field)
                && !pair->has_unknown_size
                && !has_unknown_size
-               && pair->offset + (HOST_WIDE_INT)pair->size == offset + foff
-               && !must_have_pointers_p
-               && !could_have_pointers (field))
+               && pair->offset + (HOST_WIDE_INT)pair->size == offset + foff)
              {
+               pair = VEC_last (fieldoff_s, *fieldstack);
                pair->size += TREE_INT_CST_LOW (DECL_SIZE (field));
              }
            else
@@ -4995,19 +4271,19 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
                  pair->size = TREE_INT_CST_LOW (DECL_SIZE (field));
                else
                  pair->size = -1;
-               pair->may_have_pointers
-                 = must_have_pointers_p || could_have_pointers (field);
+               pair->may_have_pointers = could_have_pointers (field);
                pair->only_restrict_pointers
                  = (!has_unknown_size
                     && POINTER_TYPE_P (TREE_TYPE (field))
                     && TYPE_RESTRICT (TREE_TYPE (field)));
+               count++;
              }
          }
-
-       empty_p = false;
+       else
+         count += pushed;
       }
 
-  return !empty_p;
+  return count;
 }
 
 /* Count the number of arguments DECL has, and set IS_VARARGS to true
@@ -5037,122 +4313,38 @@ count_num_arguments (tree decl, bool *is_varargs)
 /* Creation function node for DECL, using NAME, and return the index
    of the variable we've created for the function.  */
 
-static varinfo_t
+static unsigned int
 create_function_info_for (tree decl, const char *name)
 {
-  struct function *fn = DECL_STRUCT_FUNCTION (decl);
-  varinfo_t vi, prev_vi;
+  varinfo_t vi;
   tree arg;
   unsigned int i;
   bool is_varargs = false;
-  unsigned int num_args = count_num_arguments (decl, &is_varargs);
 
   /* Create the variable info.  */
 
   vi = new_var_info (decl, name);
   vi->offset = 0;
   vi->size = 1;
-  vi->fullsize = fi_parm_base + num_args;
-  vi->is_fn_info = 1;
-  vi->may_have_pointers = false;
-  if (is_varargs)
-    vi->fullsize = ~0;
+  vi->fullsize = count_num_arguments (decl, &is_varargs) + 1;
   insert_vi_for_tree (vi->decl, vi);
 
-  prev_vi = vi;
-
-  /* Create a variable for things the function clobbers and one for
-     things the function uses.  */
-    {
-      varinfo_t clobbervi, usevi;
-      const char *newname;
-      char *tempname;
-
-      asprintf (&tempname, "%s.clobber", name);
-      newname = ggc_strdup (tempname);
-      free (tempname);
-
-      clobbervi = new_var_info (NULL, newname);
-      clobbervi->offset = fi_clobbers;
-      clobbervi->size = 1;
-      clobbervi->fullsize = vi->fullsize;
-      clobbervi->is_full_var = true;
-      clobbervi->is_global_var = false;
-      gcc_assert (prev_vi->offset < clobbervi->offset);
-      prev_vi->next = clobbervi;
-      prev_vi = clobbervi;
-
-      asprintf (&tempname, "%s.use", name);
-      newname = ggc_strdup (tempname);
-      free (tempname);
-
-      usevi = new_var_info (NULL, newname);
-      usevi->offset = fi_uses;
-      usevi->size = 1;
-      usevi->fullsize = vi->fullsize;
-      usevi->is_full_var = true;
-      usevi->is_global_var = false;
-      gcc_assert (prev_vi->offset < usevi->offset);
-      prev_vi->next = usevi;
-      prev_vi = usevi;
-    }
+  stats.total_vars++;
 
-  /* And one for the static chain.  */
-  if (fn->static_chain_decl != NULL_TREE)
+  /* If it's varargs, we don't know how many arguments it has, so we
+     can't do much.  */
+  if (is_varargs)
     {
-      varinfo_t chainvi;
-      const char *newname;
-      char *tempname;
-
-      asprintf (&tempname, "%s.chain", name);
-      newname = ggc_strdup (tempname);
-      free (tempname);
-
-      chainvi = new_var_info (fn->static_chain_decl, newname);
-      chainvi->offset = fi_static_chain;
-      chainvi->size = 1;
-      chainvi->fullsize = vi->fullsize;
-      chainvi->is_full_var = true;
-      chainvi->is_global_var = false;
-      gcc_assert (prev_vi->offset < chainvi->offset);
-      prev_vi->next = chainvi;
-      prev_vi = chainvi;
-      insert_vi_for_tree (fn->static_chain_decl, chainvi);
+      vi->fullsize = ~0;
+      vi->size = ~0;
+      vi->is_unknown_size_var = true;
+      return vi->id;
     }
 
-  /* Create a variable for the return var.  */
-  if (DECL_RESULT (decl) != NULL
-      || !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
-    {
-      varinfo_t resultvi;
-      const char *newname;
-      char *tempname;
-      tree resultdecl = decl;
-
-      if (DECL_RESULT (decl))
-       resultdecl = DECL_RESULT (decl);
-
-      asprintf (&tempname, "%s.result", name);
-      newname = ggc_strdup (tempname);
-      free (tempname);
-
-      resultvi = new_var_info (resultdecl, newname);
-      resultvi->offset = fi_result;
-      resultvi->size = 1;
-      resultvi->fullsize = vi->fullsize;
-      resultvi->is_full_var = true;
-      if (DECL_RESULT (decl))
-       resultvi->may_have_pointers = could_have_pointers (DECL_RESULT (decl));
-      gcc_assert (prev_vi->offset < resultvi->offset);
-      prev_vi->next = resultvi;
-      prev_vi = resultvi;
-      if (DECL_RESULT (decl))
-       insert_vi_for_tree (DECL_RESULT (decl), resultvi);
-    }
+  arg = DECL_ARGUMENTS (decl);
 
   /* Set up variables for each argument.  */
-  arg = DECL_ARGUMENTS (decl);
-  for (i = 0; i < num_args; i++)
+  for (i = 1; i < vi->fullsize; i++)
     {
       varinfo_t argvi;
       const char *newname;
@@ -5162,20 +4354,17 @@ create_function_info_for (tree decl, const char *name)
       if (arg)
        argdecl = arg;
 
-      asprintf (&tempname, "%s.arg%d", name, i);
+      asprintf (&tempname, "%s.arg%d", name, i-1);
       newname = ggc_strdup (tempname);
       free (tempname);
 
       argvi = new_var_info (argdecl, newname);
-      argvi->offset = fi_parm_base + i;
+      argvi->offset = i;
       argvi->size = 1;
       argvi->is_full_var = true;
       argvi->fullsize = vi->fullsize;
-      if (arg)
-       argvi->may_have_pointers = could_have_pointers (arg);
-      gcc_assert (prev_vi->offset < argvi->offset);
-      prev_vi->next = argvi;
-      prev_vi = argvi;
+      insert_into_field_list_sorted (vi, argvi);
+      stats.total_vars ++;
       if (arg)
        {
          insert_vi_for_tree (arg, argvi);
@@ -5183,34 +4372,36 @@ create_function_info_for (tree decl, const char *name)
        }
     }
 
-  /* Add one representative for all further args.  */
-  if (is_varargs)
+  /* Create a variable for the return var.  */
+  if (DECL_RESULT (decl) != NULL
+      || !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
     {
-      varinfo_t argvi;
+      varinfo_t resultvi;
       const char *newname;
       char *tempname;
-      tree decl;
+      tree resultdecl = decl;
+
+      vi->fullsize ++;
 
-      asprintf (&tempname, "%s.varargs", name);
+      if (DECL_RESULT (decl))
+       resultdecl = DECL_RESULT (decl);
+
+      asprintf (&tempname, "%s.result", name);
       newname = ggc_strdup (tempname);
       free (tempname);
 
-      /* We need sth that can be pointed to for va_start.  */
-      decl = create_tmp_var_raw (ptr_type_node, name);
-      get_var_ann (decl);
-
-      argvi = new_var_info (decl, newname);
-      argvi->offset = fi_parm_base + num_args;
-      argvi->size = ~0;
-      argvi->is_full_var = true;
-      argvi->is_heap_var = true;
-      argvi->fullsize = vi->fullsize;
-      gcc_assert (prev_vi->offset < argvi->offset);
-      prev_vi->next = argvi;
-      prev_vi = argvi;
+      resultvi = new_var_info (resultdecl, newname);
+      resultvi->offset = i;
+      resultvi->size = 1;
+      resultvi->fullsize = vi->fullsize;
+      resultvi->is_full_var = true;
+      insert_into_field_list_sorted (vi, resultvi);
+      stats.total_vars ++;
+      if (DECL_RESULT (decl))
+       insert_vi_for_tree (DECL_RESULT (decl), resultvi);
     }
 
-  return vi;
+  return vi->id;
 }
 
 
@@ -5237,54 +4428,67 @@ check_for_overlaps (VEC (fieldoff_s,heap) *fieldstack)
    This will also create any varinfo structures necessary for fields
    of DECL.  */
 
-static varinfo_t
-create_variable_info_for_1 (tree decl, const char *name)
+static unsigned int
+create_variable_info_for (tree decl, const char *name)
 {
-  varinfo_t vi, newvi;
+  varinfo_t vi;
   tree decl_type = TREE_TYPE (decl);
   tree declsize = DECL_P (decl) ? DECL_SIZE (decl) : TYPE_SIZE (decl_type);
   VEC (fieldoff_s,heap) *fieldstack = NULL;
-  fieldoff_s *fo;
-  unsigned int i;
 
+  if (var_can_have_subvars (decl) && use_field_sensitive)
+    push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
+
+  /* If the variable doesn't have subvars, we may end up needing to
+     sort the field list and create fake variables for all the
+     fields.  */
+  vi = new_var_info (decl, name);
+  vi->offset = 0;
+  vi->may_have_pointers = could_have_pointers (decl);
   if (!declsize
       || !host_integerp (declsize, 1))
     {
-      vi = new_var_info (decl, name);
-      vi->offset = 0;
-      vi->size = ~0;
-      vi->fullsize = ~0;
       vi->is_unknown_size_var = true;
-      vi->is_full_var = true;
-      vi->may_have_pointers = could_have_pointers (decl);
-      return vi;
+      vi->fullsize = ~0;
+      vi->size = ~0;
+    }
+  else
+    {
+      vi->fullsize = TREE_INT_CST_LOW (declsize);
+      vi->size = vi->fullsize;
+    }
+
+  insert_vi_for_tree (vi->decl, vi);
+  if (vi->is_global_var
+      && (!flag_whole_program || !in_ipa_mode)
+      && vi->may_have_pointers)
+    {
+      if (POINTER_TYPE_P (TREE_TYPE (decl))
+         && TYPE_RESTRICT (TREE_TYPE (decl)))
+       make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+      make_copy_constraint (vi, nonlocal_id);
     }
 
-  /* Collect field information.  */
+  stats.total_vars++;
   if (use_field_sensitive
+      && !vi->is_unknown_size_var
       && var_can_have_subvars (decl)
-      /* ???  Force us to not use subfields for global initializers
-        in IPA mode.  Else we'd have to parse arbitrary initializers.  */
-      && !(in_ipa_mode
-          && is_global_var (decl)
-          && DECL_INITIAL (decl)))
+      && VEC_length (fieldoff_s, fieldstack) > 1
+      && VEC_length (fieldoff_s, fieldstack) <= MAX_FIELDS_FOR_FIELD_SENSITIVE)
     {
       fieldoff_s *fo = NULL;
       bool notokay = false;
       unsigned int i;
 
-      push_fields_onto_fieldstack (decl_type, &fieldstack, 0,
-                                  TREE_PUBLIC (decl)
-                                  || DECL_EXTERNAL (decl)
-                                  || TREE_ADDRESSABLE (decl));
-
       for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
-       if (fo->has_unknown_size
-           || fo->offset < 0)
-         {
-           notokay = true;
-           break;
-         }
+       {
+         if (fo->has_unknown_size
+             || fo->offset < 0)
+           {
+             notokay = true;
+             break;
+           }
+       }
 
       /* We can't sort them if we have a field with a variable sized type,
         which will make notokay = true.  In that case, we are going to return
@@ -5300,112 +4504,70 @@ create_variable_info_for_1 (tree decl, const char *name)
          notokay = check_for_overlaps (fieldstack);
        }
 
-      if (notokay)
-       VEC_free (fieldoff_s, heap, fieldstack);
-    }
 
-  /* If we didn't end up collecting sub-variables create a full
-     variable for the decl.  */
-  if (VEC_length (fieldoff_s, fieldstack) <= 1
-      || VEC_length (fieldoff_s, fieldstack) > MAX_FIELDS_FOR_FIELD_SENSITIVE)
-    {
-      vi = new_var_info (decl, name);
-      vi->offset = 0;
-      vi->may_have_pointers = could_have_pointers (decl);
-      vi->fullsize = TREE_INT_CST_LOW (declsize);
-      vi->size = vi->fullsize;
-      vi->is_full_var = true;
-      VEC_free (fieldoff_s, heap, fieldstack);
-      return vi;
-    }
+      if (VEC_length (fieldoff_s, fieldstack) != 0)
+       fo = VEC_index (fieldoff_s, fieldstack, 0);
 
-  vi = new_var_info (decl, name);
-  vi->fullsize = TREE_INT_CST_LOW (declsize);
-  for (i = 0, newvi = vi;
-       VEC_iterate (fieldoff_s, fieldstack, i, fo);
-       ++i, newvi = newvi->next)
-    {
-      const char *newname = "NULL";
-      char *tempname;
-
-      if (dump_file)
+      if (fo == NULL || notokay)
        {
-         asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
-                   "+" HOST_WIDE_INT_PRINT_DEC, name, fo->offset, fo->size);
-         newname = ggc_strdup (tempname);
-         free (tempname);
+         vi->is_unknown_size_var = 1;
+         vi->fullsize = ~0;
+         vi->size = ~0;
+         vi->is_full_var = true;
+         VEC_free (fieldoff_s, heap, fieldstack);
+         return vi->id;
        }
-      newvi->name = newname;
-      newvi->offset = fo->offset;
-      newvi->size = fo->size;
-      newvi->fullsize = vi->fullsize;
-      newvi->may_have_pointers = fo->may_have_pointers;
-      newvi->only_restrict_pointers = fo->only_restrict_pointers;
-      if (i + 1 < VEC_length (fieldoff_s, fieldstack))
-       newvi->next = new_var_info (decl, name);
-    }
 
-  VEC_free (fieldoff_s, heap, fieldstack);
-
-  return vi;
-}
-
-static unsigned int
-create_variable_info_for (tree decl, const char *name)
-{
-  varinfo_t vi = create_variable_info_for_1 (decl, name);
-  unsigned int id = vi->id;
-
-  insert_vi_for_tree (decl, vi);
-
-  /* Create initial constraints for globals.  */
-  for (; vi; vi = vi->next)
-    {
-      if (!vi->may_have_pointers
-         || !vi->is_global_var)
-       continue;
-
-      /* Mark global restrict qualified pointers.  */
-      if ((POINTER_TYPE_P (TREE_TYPE (decl))
-          && TYPE_RESTRICT (TREE_TYPE (decl)))
-         || 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))
+      vi->size = fo->size;
+      vi->offset = fo->offset;
+      vi->may_have_pointers = fo->may_have_pointers;
+      if (vi->is_global_var
+         && (!flag_whole_program || !in_ipa_mode)
+         && vi->may_have_pointers)
        {
-         VEC (ce_s, heap) *rhsc = NULL;
-         struct constraint_expr lhs, *rhsp;
-         unsigned i;
-         get_constraint_for (DECL_INITIAL (decl), &rhsc);
-         lhs.var = vi->id;
-         lhs.offset = 0;
-         lhs.type = SCALAR;
-         for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); ++i)
-           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))
+         if (fo->only_restrict_pointers)
+           make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+       }
+      for (i = VEC_length (fieldoff_s, fieldstack) - 1;
+          i >= 1 && VEC_iterate (fieldoff_s, fieldstack, i, fo);
+          i--)
+       {
+         varinfo_t newvi;
+         const char *newname = "NULL";
+         char *tempname;
+
+         if (dump_file)
            {
-             lhs.var = escaped_id;
-             lhs.offset = 0;
-             lhs.type = SCALAR;
-             for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); ++i)
-               process_constraint (new_constraint (lhs, *rhsp));
+             asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
+                       "+" HOST_WIDE_INT_PRINT_DEC,
+                       vi->name, fo->offset, fo->size);
+             newname = ggc_strdup (tempname);
+             free (tempname);
            }
-         VEC_free (ce_s, heap, rhsc);
+         newvi = new_var_info (decl, newname);
+         newvi->offset = fo->offset;
+         newvi->size = fo->size;
+         newvi->fullsize = vi->fullsize;
+         newvi->may_have_pointers = fo->may_have_pointers;
+         insert_into_field_list (vi, newvi);
+         if ((newvi->is_global_var || TREE_CODE (decl) == PARM_DECL)
+             && newvi->may_have_pointers)
+           {
+              if (fo->only_restrict_pointers)
+                make_constraint_from_restrict (newvi, "GLOBAL_RESTRICT");
+              if (newvi->is_global_var && !in_ipa_mode)
+                make_copy_constraint (newvi, nonlocal_id);
+           }
+
+         stats.total_vars++;
        }
     }
+  else
+    vi->is_full_var = true;
+
+  VEC_free (fieldoff_s, heap, fieldstack);
 
-  return id;
+  return vi->id;
 }
 
 /* Print out the points-to solution for VAR to FILE.  */
@@ -5417,19 +4579,20 @@ dump_solution_for_var (FILE *file, unsigned int var)
   unsigned int i;
   bitmap_iterator bi;
 
-  /* Dump the solution for unified vars anyway, this avoids difficulties
-     in scanning dumps in the testsuite.  */
-  fprintf (file, "%s = { ", vi->name);
-  vi = get_varinfo (find (var));
-  EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
-    fprintf (file, "%s ", get_varinfo (i)->name);
-  fprintf (file, "}");
-
-  /* But note when the variable was unified.  */
-  if (vi->id != var)
-    fprintf (file, " same as %s", vi->name);
-
-  fprintf (file, "\n");
+  if (find (var) != var)
+    {
+      varinfo_t vipt = get_varinfo (find (var));
+      fprintf (file, "%s = same as %s\n", vi->name, vipt->name);
+    }
+  else
+    {
+      fprintf (file, "%s = { ", vi->name);
+      EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
+       {
+         fprintf (file, "%s ", get_varinfo (i)->name);
+       }
+      fprintf (file, "}\n");
+    }
 }
 
 /* Print the points-to solution for VAR to stdout.  */
@@ -5491,12 +4654,8 @@ intra_create_variable_infos (void)
        }
 
       for (p = get_vi_for_tree (t); p; p = p->next)
-       {
-         if (p->may_have_pointers)
-           make_constraint_from (p, nonlocal_id);
-         if (p->only_restrict_pointers)
-           make_constraint_from_restrict (p, "PARM_RESTRICT");
-       }
+       if (p->may_have_pointers)
+         make_constraint_from (p, nonlocal_id);
       if (POINTER_TYPE_P (TREE_TYPE (t))
          && TYPE_RESTRICT (TREE_TYPE (t)))
        make_constraint_from_restrict (get_vi_for_tree (t), "PARM_RESTRICT");
@@ -5613,15 +4772,9 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt)
          || TREE_CODE (vi->decl) == PARM_DECL
          || TREE_CODE (vi->decl) == RESULT_DECL)
        {
-         /* If we are in IPA mode we will not recompute points-to
-            sets after inlining so make sure they stay valid.  */
-         if (in_ipa_mode
-             && !DECL_PT_UID_SET_P (vi->decl))
-           SET_DECL_PT_UID (vi->decl, DECL_UID (vi->decl));
-
          /* Add the decl to the points-to set.  Note that the points-to
             set contains global variables.  */
-         bitmap_set_bit (into, DECL_PT_UID (vi->decl));
+         bitmap_set_bit (into, DECL_UID (vi->decl));
          if (vi->is_global_var)
            pt->vars_contains_global = true;
        }
@@ -5657,12 +4810,9 @@ find_what_var_points_to (varinfo_t orig_vi, struct pt_solution *pt)
          if (vi->id == nothing_id)
            pt->null = 1;
          else if (vi->id == escaped_id)
-           {
-             if (in_ipa_mode)
-               pt->ipa_escaped = 1;
-             else
-               pt->escaped = 1;
-           }
+           pt->escaped = 1;
+         else if (vi->id == callused_id)
+           gcc_unreachable ();
          else if (vi->id == nonlocal_id)
            pt->nonlocal = 1;
          else if (vi->is_heap_var)
@@ -5768,53 +4918,30 @@ pt_solution_reset (struct pt_solution *pt)
 }
 
 /* Set the points-to solution *PT to point only to the variables
-   in VARS.  VARS_CONTAINS_GLOBAL specifies whether that contains
-   global variables and VARS_CONTAINS_RESTRICT specifies whether
-   it contains restrict tag variables.  */
+   in VARS.  */
 
 void
-pt_solution_set (struct pt_solution *pt, bitmap vars,
-                bool vars_contains_global, bool vars_contains_restrict)
+pt_solution_set (struct pt_solution *pt, bitmap vars)
 {
+  bitmap_iterator bi;
+  unsigned i;
+
   memset (pt, 0, sizeof (struct pt_solution));
   pt->vars = vars;
-  pt->vars_contains_global = vars_contains_global;
-  pt->vars_contains_restrict = vars_contains_restrict;
-}
-
-/* Computes the union of the points-to solutions *DEST and *SRC and
-   stores the result in *DEST.  This changes the points-to bitmap
-   of *DEST and thus may not be used if that might be shared.
-   The points-to bitmap of *SRC and *DEST will not be shared after
-   this function if they were not before.  */
-
-static void
-pt_solution_ior_into (struct pt_solution *dest, struct pt_solution *src)
-{
-  dest->anything |= src->anything;
-  if (dest->anything)
+  EXECUTE_IF_SET_IN_BITMAP (vars, 0, i, bi)
     {
-      pt_solution_reset (dest);
-      return;
+      tree var = referenced_var_lookup (i);
+      if (is_global_var (var))
+       {
+         pt->vars_contains_global = true;
+         break;
+       }
     }
-
-  dest->nonlocal |= src->nonlocal;
-  dest->escaped |= src->escaped;
-  dest->ipa_escaped |= src->ipa_escaped;
-  dest->null |= src->null;
-  dest->vars_contains_global |= src->vars_contains_global;
-  dest->vars_contains_restrict |= src->vars_contains_restrict;
-  if (!src->vars)
-    return;
-
-  if (!dest->vars)
-    dest->vars = BITMAP_GGC_ALLOC ();
-  bitmap_ior_into (dest->vars, src->vars);
 }
 
 /* Return true if the points-to solution *PT is empty.  */
 
-bool
+static bool
 pt_solution_empty_p (struct pt_solution *pt)
 {
   if (pt->anything
@@ -5830,11 +4957,6 @@ pt_solution_empty_p (struct pt_solution *pt)
       && !pt_solution_empty_p (&cfun->gimple_df->escaped))
     return false;
 
-  /* If the solution includes ESCAPED, check if that is empty.  */
-  if (pt->ipa_escaped
-      && !pt_solution_empty_p (&ipa_escaped_pt))
-    return false;
-
   return true;
 }
 
@@ -5851,15 +4973,6 @@ pt_solution_includes_global (struct pt_solution *pt)
   if (pt->escaped)
     return pt_solution_includes_global (&cfun->gimple_df->escaped);
 
-  if (pt->ipa_escaped)
-    return pt_solution_includes_global (&ipa_escaped_pt);
-
-  /* ???  This predicate is not correct for the IPA-PTA solution
-     as we do not properly distinguish between unit escape points
-     and global variables.  */
-  if (cfun->gimple_df->ipa_pta)
-    return true;
-
   return false;
 }
 
@@ -5877,7 +4990,7 @@ pt_solution_includes_1 (struct pt_solution *pt, const_tree decl)
     return true;
 
   if (pt->vars
-      && bitmap_bit_p (pt->vars, DECL_PT_UID (decl)))
+      && bitmap_bit_p (pt->vars, DECL_UID (decl)))
     return true;
 
   /* If the solution includes ESCAPED, check it.  */
@@ -5885,11 +4998,6 @@ pt_solution_includes_1 (struct pt_solution *pt, const_tree decl)
       && pt_solution_includes_1 (&cfun->gimple_df->escaped, decl))
     return true;
 
-  /* If the solution includes ESCAPED, check it.  */
-  if (pt->ipa_escaped
-      && pt_solution_includes_1 (&ipa_escaped_pt, decl))
-    return true;
-
   return false;
 }
 
@@ -5940,25 +5048,6 @@ pt_solutions_intersect_1 (struct pt_solution *pt1, struct pt_solution *pt2)
        return true;
     }
 
-  /* Check the escaped solution if required.
-     ???  Do we need to check the local against the IPA escaped sets?  */
-  if ((pt1->ipa_escaped || pt2->ipa_escaped)
-      && !pt_solution_empty_p (&ipa_escaped_pt))
-    {
-      /* If both point to escaped memory and that solution
-        is not empty they alias.  */
-      if (pt1->ipa_escaped && pt2->ipa_escaped)
-       return true;
-
-      /* If either points to escaped memory see if the escaped solution
-        intersects with the other.  */
-      if ((pt1->ipa_escaped
-          && pt_solutions_intersect_1 (&ipa_escaped_pt, pt2))
-         || (pt2->ipa_escaped
-             && pt_solutions_intersect_1 (&ipa_escaped_pt, pt1)))
-       return true;
-    }
-
   /* Now both pointers alias if their points-to solution intersects.  */
   return (pt1->vars
          && pt2->vars
@@ -6024,12 +5113,7 @@ dump_sa_points_to_info (FILE *outfile)
     }
 
   for (i = 0; i < VEC_length (varinfo_t, varmap); i++)
-    {
-      varinfo_t vi = get_varinfo (i);
-      if (!vi->may_have_pointers)
-       continue;
-      dump_solution_for_var (outfile, i);
-    }
+    dump_solution_for_var (outfile, i);
 }
 
 
@@ -6054,6 +5138,7 @@ init_base_vars (void)
   varinfo_t var_readonly;
   varinfo_t var_escaped;
   varinfo_t var_nonlocal;
+  varinfo_t var_callused;
   varinfo_t var_storedanything;
   varinfo_t var_integer;
 
@@ -6066,8 +5151,6 @@ init_base_vars (void)
   var_nothing->size = ~0;
   var_nothing->fullsize = ~0;
   var_nothing->is_special_var = 1;
-  var_nothing->may_have_pointers = 0;
-  var_nothing->is_global_var = 0;
 
   /* Create the ANYTHING variable, used to represent that a variable
      points to some unknown piece of memory.  */
@@ -6182,6 +5265,35 @@ init_base_vars (void)
   rhs.offset = 0;
   process_constraint (new_constraint (lhs, rhs));
 
+  /* Create the CALLUSED variable, used to represent the set of call-used
+     memory.  */
+  var_callused = new_var_info (NULL_TREE, "CALLUSED");
+  gcc_assert (var_callused->id == callused_id);
+  var_callused->is_artificial_var = 1;
+  var_callused->offset = 0;
+  var_callused->size = ~0;
+  var_callused->fullsize = ~0;
+  var_callused->is_special_var = 0;
+
+  /* CALLUSED = *CALLUSED, because call-used is may-deref'd at calls, etc.  */
+  lhs.type = SCALAR;
+  lhs.var = callused_id;
+  lhs.offset = 0;
+  rhs.type = DEREF;
+  rhs.var = callused_id;
+  rhs.offset = 0;
+  process_constraint (new_constraint (lhs, rhs));
+
+  /* CALLUSED = CALLUSED + UNKNOWN, because if a sub-field is call-used the
+     whole variable is call-used.  */
+  lhs.type = SCALAR;
+  lhs.var = callused_id;
+  lhs.offset = 0;
+  rhs.type = SCALAR;
+  rhs.var = callused_id;
+  rhs.offset = UNKNOWN_OFFSET;
+  process_constraint (new_constraint (lhs, rhs));
+
   /* Create the STOREDANYTHING variable, used to represent the set of
      variables stored to *ANYTHING.  */
   var_storedanything = new_var_info (NULL_TREE, "STOREDANYTHING");
@@ -6232,7 +5344,6 @@ init_alias_vars (void)
   constraints = VEC_alloc (constraint_t, heap, 8);
   varmap = VEC_alloc (varinfo_t, heap, 8);
   vi_for_tree = pointer_map_create ();
-  call_stmt_vars = pointer_map_create ();
 
   memset (&stats, 0, sizeof (stats));
   shared_bitmap_table = htab_create (511, shared_bitmap_hash,
@@ -6304,6 +5415,12 @@ solve_constraints (void)
   struct scc_info *si;
 
   if (dump_file)
+    {
+      fprintf (dump_file, "Points-to analysis\n\nConstraints:\n\n");
+      dump_constraints (dump_file);
+    }
+
+  if (dump_file)
     fprintf (dump_file,
             "\nCollapsing static cycles and doing variable "
             "substitution\n");
@@ -6363,6 +5480,7 @@ compute_points_to_sets (void)
   basic_block bb;
   unsigned i;
   varinfo_t vi;
+  struct pt_solution callused;
 
   timevar_push (TV_TREE_PTA);
 
@@ -6371,7 +5489,7 @@ compute_points_to_sets (void)
 
   intra_create_variable_infos ();
 
-  /* Now walk all statements and build the constraint set.  */
+  /* Now walk all statements and derive aliases.  */
   FOR_EACH_BB (bb)
     {
       gimple_stmt_iterator gsi;
@@ -6392,18 +5510,14 @@ compute_points_to_sets (void)
        }
     }
 
-  if (dump_file)
-    {
-      fprintf (dump_file, "Points-to analysis\n\nConstraints:\n\n");
-      dump_constraints (dump_file, 0);
-    }
-
   /* From the constraints compute the points-to sets.  */
   solve_constraints ();
 
-  /* Compute the points-to set for ESCAPED used for call-clobber analysis.  */
+  /* Compute the points-to sets for ESCAPED and CALLUSED used for
+     call-clobber analysis.  */
   find_what_var_points_to (get_varinfo (escaped_id),
                           &cfun->gimple_df->escaped);
+  find_what_var_points_to (get_varinfo (callused_id), &callused);
 
   /* Make sure the ESCAPED solution (which is used as placeholder in
      other solutions) does not reference itself.  This simplifies
@@ -6442,11 +5556,11 @@ compute_points_to_sets (void)
          pt = gimple_call_use_set (stmt);
          if (gimple_call_flags (stmt) & ECF_CONST)
            memset (pt, 0, sizeof (struct pt_solution));
-         else if ((vi = lookup_call_use_vi (stmt)) != NULL)
+         else if (gimple_call_flags (stmt) & ECF_PURE)
            {
-             find_what_var_points_to (vi, pt);
-             /* Escaped (and thus nonlocal) variables are always
-                implicitly used by calls.  */
+             /* For const calls we should now be able to compute the
+                call-used set per function.  */
+             *pt = callused;
              /* ???  ESCAPED can be empty even though NONLOCAL
                 always escaped.  */
              pt->nonlocal = 1;
@@ -6454,8 +5568,6 @@ compute_points_to_sets (void)
            }
          else
            {
-             /* If there is nothing special about this call then
-                we have made everything that is used also escape.  */
              *pt = cfun->gimple_df->escaped;
              pt->nonlocal = 1;
            }
@@ -6463,20 +5575,8 @@ compute_points_to_sets (void)
          pt = gimple_call_clobber_set (stmt);
          if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
            memset (pt, 0, sizeof (struct pt_solution));
-         else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
-           {
-             find_what_var_points_to (vi, pt);
-             /* Escaped (and thus nonlocal) variables are always
-                implicitly clobbered by calls.  */
-             /* ???  ESCAPED can be empty even though NONLOCAL
-                always escaped.  */
-             pt->nonlocal = 1;
-             pt->escaped = 1;
-           }
          else
            {
-             /* If there is nothing special about this call then
-                we have made everything that is used also escape.  */
              *pt = cfun->gimple_df->escaped;
              pt->nonlocal = 1;
            }
@@ -6500,7 +5600,6 @@ delete_points_to_sets (void)
             stats.points_to_sets_created);
 
   pointer_map_destroy (vi_for_tree);
-  pointer_map_destroy (call_stmt_vars);
   bitmap_obstack_release (&pta_obstack);
   VEC_free (constraint_t, heap, constraints);
 
@@ -6528,23 +5627,6 @@ delete_points_to_sets (void)
 unsigned int
 compute_may_aliases (void)
 {
-  if (cfun->gimple_df->ipa_pta)
-    {
-      if (dump_file)
-       {
-         fprintf (dump_file, "\nNot re-computing points-to information "
-                  "because IPA points-to information is available.\n\n");
-
-         /* But still dump what we have remaining it.  */
-         dump_alias_info (dump_file);
-
-         if (dump_flags & TDF_DETAILS)
-           dump_referenced_vars (dump_file);
-       }
-
-      return 0;
-    }
-
   /* For each pointer P_i, determine the sets of variables that P_i may
      point-to.  Compute the reachability set of escaped and call-used
      variables.  */
@@ -6629,17 +5711,11 @@ gate_ipa_pta (void)
          && !(errorcount || sorrycount));
 }
 
-/* IPA PTA solutions for ESCAPED.  */
-struct pt_solution ipa_escaped_pt
-  = { true, false, false, false, false, false, false, NULL };
-
 /* Execute the driver for IPA PTA.  */
 static unsigned int
 ipa_pta_execute (void)
 {
   struct cgraph_node *node;
-  struct varpool_node *var;
-  int from;
 
   in_ipa_mode = 1;
 
@@ -6649,9 +5725,6 @@ ipa_pta_execute (void)
   /* Build the constraints.  */
   for (node = cgraph_nodes; node; node = node->next)
     {
-      struct cgraph_node *alias;
-      varinfo_t vi;
-
       /* 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.  */
@@ -6659,35 +5732,15 @@ ipa_pta_execute (void)
          || node->clone_of)
        continue;
 
-      vi = create_function_info_for (node->decl,
-                                    alias_get_name (node->decl));
-
-      /* Associate the varinfo node with all aliases.  */
-      for (alias = node->same_body; alias; alias = alias->next)
-       insert_vi_for_tree (alias->decl, vi);
-    }
-
-  /* Create constraints for global variables and their initializers.  */
-  for (var = varpool_nodes; var; var = var->next)
-    {
-      struct varpool_node *alias;
-      varinfo_t vi;
-
-      vi = get_vi_for_tree (var->decl);
-
-      /* Associate the varinfo node with all aliases.  */
-      for (alias = var->extra_name; alias; alias = alias->next)
-       insert_vi_for_tree (alias->decl, vi);
-    }
+      /* It does not make sense to have graph edges into or out of
+         externally visible functions.  There is no extra information
+        we can gather from them.  */
+      if (node->local.externally_visible)
+       continue;
 
-  if (dump_file)
-    {
-      fprintf (dump_file,
-              "Generating constraints for global initializers\n\n");
-      dump_constraints (dump_file, 0);
-      fprintf (dump_file, "\n");
+      create_function_info_for (node->decl,
+                               cgraph_node_name (node));
     }
-  from = VEC_length (constraint_t, constraints);
 
   for (node = cgraph_nodes; node; node = node->next)
     {
@@ -6701,14 +5754,9 @@ ipa_pta_execute (void)
        continue;
 
       if (dump_file)
-       {
-         fprintf (dump_file,
-                  "Generating constraints for %s", cgraph_node_name (node));
-         if (DECL_ASSEMBLER_NAME_SET_P (node->decl))
-           fprintf (dump_file, " (%s)",
-                    IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)));
-         fprintf (dump_file, "\n");
-       }
+       fprintf (dump_file,
+                "Generating constraints for %s\n",
+                cgraph_node_name (node));
 
       func = DECL_STRUCT_FUNCTION (node->decl);
       old_func_decl = current_function_decl;
@@ -6740,204 +5788,16 @@ ipa_pta_execute (void)
              gimple stmt = gsi_stmt (gsi);
 
              find_func_aliases (stmt);
-             find_func_clobbers (stmt);
            }
        }
 
       current_function_decl = old_func_decl;
       pop_cfun ();
-
-      if (dump_file)
-       {
-         fprintf (dump_file, "\n");
-         dump_constraints (dump_file, from);
-         fprintf (dump_file, "\n");
-       }
-      from = VEC_length (constraint_t, constraints);
     }
 
   /* From the constraints compute the points-to sets.  */
   solve_constraints ();
 
-  /* Compute the global points-to sets for ESCAPED.
-     ???  Note that the computed escape set is not correct
-     for the whole unit as we fail to consider graph edges to
-     externally visible functions.  */
-  find_what_var_points_to (get_varinfo (escaped_id), &ipa_escaped_pt);
-
-  /* Make sure the ESCAPED solution (which is used as placeholder in
-     other solutions) does not reference itself.  This simplifies
-     points-to solution queries.  */
-  ipa_escaped_pt.ipa_escaped = 0;
-
-  /* Assign the points-to sets to the SSA names in the unit.  */
-  for (node = cgraph_nodes; node; node = node->next)
-    {
-      tree ptr;
-      struct function *fn;
-      unsigned i;
-      varinfo_t fi;
-      basic_block bb;
-      struct pt_solution uses, clobbers;
-      struct cgraph_edge *e;
-
-      /* Nodes without a body are not interesting.  */
-      if (!gimple_has_body_p (node->decl)
-         || node->clone_of)
-       continue;
-
-      fn = DECL_STRUCT_FUNCTION (node->decl);
-
-      /* Compute the points-to sets for pointer SSA_NAMEs.  */
-      for (i = 0; VEC_iterate (tree, fn->gimple_df->ssa_names, i, ptr); ++i)
-       {
-         if (ptr
-             && POINTER_TYPE_P (TREE_TYPE (ptr)))
-           find_what_p_points_to (ptr);
-       }
-
-      /* Compute the call-use and call-clobber sets for all direct calls.  */
-      fi = lookup_vi_for_tree (node->decl);
-      gcc_assert (fi->is_fn_info);
-      find_what_var_points_to (first_vi_for_offset (fi, fi_clobbers),
-                              &clobbers);
-      find_what_var_points_to (first_vi_for_offset (fi, fi_uses), &uses);
-      for (e = node->callers; e; e = e->next_caller)
-       {
-         if (!e->call_stmt)
-           continue;
-
-         *gimple_call_clobber_set (e->call_stmt) = clobbers;
-         *gimple_call_use_set (e->call_stmt) = uses;
-       }
-
-      /* Compute the call-use and call-clobber sets for indirect calls
-        and calls to external functions.  */
-      FOR_EACH_BB_FN (bb, fn)
-       {
-         gimple_stmt_iterator gsi;
-
-         for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-           {
-             gimple stmt = gsi_stmt (gsi);
-             struct pt_solution *pt;
-             varinfo_t vi;
-             tree decl;
-
-             if (!is_gimple_call (stmt))
-               continue;
-
-             /* Handle direct calls to external functions.  */
-             decl = gimple_call_fndecl (stmt);
-             if (decl
-                 && (!(fi = lookup_vi_for_tree (decl))
-                     || !fi->is_fn_info))
-               {
-                 pt = gimple_call_use_set (stmt);
-                 if (gimple_call_flags (stmt) & ECF_CONST)
-                   memset (pt, 0, sizeof (struct pt_solution));
-                 else if ((vi = lookup_call_use_vi (stmt)) != NULL)
-                   {
-                     find_what_var_points_to (vi, pt);
-                     /* Escaped (and thus nonlocal) variables are always
-                        implicitly used by calls.  */
-                     /* ???  ESCAPED can be empty even though NONLOCAL
-                        always escaped.  */
-                     pt->nonlocal = 1;
-                     pt->ipa_escaped = 1;
-                   }
-                 else
-                   {
-                     /* If there is nothing special about this call then
-                        we have made everything that is used also escape.  */
-                     *pt = ipa_escaped_pt;
-                     pt->nonlocal = 1;
-                   }
-
-                 pt = gimple_call_clobber_set (stmt);
-                 if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
-                   memset (pt, 0, sizeof (struct pt_solution));
-                 else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
-                   {
-                     find_what_var_points_to (vi, pt);
-                     /* Escaped (and thus nonlocal) variables are always
-                        implicitly clobbered by calls.  */
-                     /* ???  ESCAPED can be empty even though NONLOCAL
-                        always escaped.  */
-                     pt->nonlocal = 1;
-                     pt->ipa_escaped = 1;
-                   }
-                 else
-                   {
-                     /* If there is nothing special about this call then
-                        we have made everything that is used also escape.  */
-                     *pt = ipa_escaped_pt;
-                     pt->nonlocal = 1;
-                   }
-               }
-
-             /* Handle indirect calls.  */
-             if (!decl
-                 && (fi = get_fi_for_callee (stmt)))
-               {
-                 /* We need to accumulate all clobbers/uses of all possible
-                    callees.  */
-                 fi = get_varinfo (find (fi->id));
-                 /* If we cannot constrain the set of functions we'll end up
-                    calling we end up using/clobbering everything.  */
-                 if (bitmap_bit_p (fi->solution, anything_id)
-                     || bitmap_bit_p (fi->solution, nonlocal_id)
-                     || bitmap_bit_p (fi->solution, escaped_id))
-                   {
-                     pt_solution_reset (gimple_call_clobber_set (stmt));
-                     pt_solution_reset (gimple_call_use_set (stmt));
-                   }
-                 else
-                   {
-                     bitmap_iterator bi;
-                     unsigned i;
-                     struct pt_solution *uses, *clobbers;
-
-                     uses = gimple_call_use_set (stmt);
-                     clobbers = gimple_call_clobber_set (stmt);
-                     memset (uses, 0, sizeof (struct pt_solution));
-                     memset (clobbers, 0, sizeof (struct pt_solution));
-                     EXECUTE_IF_SET_IN_BITMAP (fi->solution, 0, i, bi)
-                       {
-                         struct pt_solution sol;
-
-                         vi = get_varinfo (i);
-                         if (!vi->is_fn_info)
-                           {
-                             /* ???  We could be more precise here?  */
-                             uses->nonlocal = 1;
-                             uses->ipa_escaped = 1;
-                             clobbers->nonlocal = 1;
-                             clobbers->ipa_escaped = 1;
-                             continue;
-                           }
-
-                         if (!uses->anything)
-                           {
-                             find_what_var_points_to
-                                 (first_vi_for_offset (vi, fi_uses), &sol);
-                             pt_solution_ior_into (uses, &sol);
-                           }
-                         if (!clobbers->anything)
-                           {
-                             find_what_var_points_to
-                                 (first_vi_for_offset (vi, fi_clobbers), &sol);
-                             pt_solution_ior_into (clobbers, &sol);
-                           }
-                       }
-                   }
-               }
-           }
-       }
-
-      fn->gimple_df->ipa_pta = true;
-    }
-
   delete_points_to_sets ();
 
   in_ipa_mode = 0;
index e67f580..e0d3f48 100644 (file)
@@ -23,13 +23,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "rtl.h"
 #include "tm_p.h"
+#include "hard-reg-set.h"
 #include "basic-block.h"
 #include "function.h"
 #include "tree-flow.h"
 #include "tree-dump.h"
 #include "diagnostic.h"
-#include "gimple-pretty-print.h"
 #include "except.h"
 #include "tree-pass.h"
 #include "flags.h"
@@ -129,9 +130,32 @@ static void find_tail_calls (basic_block, struct tailcall **);
 static bool
 suitable_for_tail_opt_p (void)
 {
+  referenced_var_iterator rvi;
+  tree var;
+
   if (cfun->stdarg)
     return false;
 
+  /* No local variable nor structure field should escape to callees.  */
+  FOR_EACH_REFERENCED_VAR (var, rvi)
+    {
+      if (!is_global_var (var)
+         /* ???  We do not have a suitable predicate for escaping to
+            callees.  With IPA-PTA the following might be incorrect.
+            We want to catch
+              foo {
+                int i;
+                bar (&i);
+                foo ();
+              }
+            where bar might store &i somewhere and in the next
+            recursion should not be able to tell if it got the
+            same (with tail-recursion applied) or a different
+            address.  */
+         && is_call_clobbered (var))
+       return false;
+    }
+
   return true;
 }
 /* Returns false when the function is not suitable for tail call optimization
@@ -363,8 +387,6 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
   tree m, a;
   basic_block abb;
   size_t idx;
-  tree var;
-  referenced_var_iterator rvi;
 
   if (!single_succ_p (bb))
     return;
@@ -420,7 +442,8 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
   func = gimple_call_fndecl (call);
   if (func == current_function_decl)
     {
-      tree arg;
+      tree arg, var;
+      referenced_var_iterator rvi;
 
       for (param = DECL_ARGUMENTS (func), idx = 0;
           param && idx < gimple_call_num_args (call);
@@ -451,17 +474,15 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
        }
       if (idx == gimple_call_num_args (call) && !param)
        tail_recursion = true;
-    }
 
-  /* Make sure the tail invocation of this function does not refer
-     to local variables.  */
-  FOR_EACH_REFERENCED_VAR (var, rvi)
-    {
-      if (TREE_CODE (var) != PARM_DECL
-         && auto_var_in_fn_p (var, cfun->decl)
-         && (ref_maybe_used_by_stmt_p (call, var)
-             || call_may_clobber_ref_p (call, var)))
-       return;
+      /* Make sure the tail invocation of this function does not refer
+        to local variables.  */
+      FOR_EACH_REFERENCED_VAR (var, rvi)
+       {
+         if (!is_global_var (var)
+             && ref_maybe_used_by_stmt_p (call, var))
+           return;
+       }
     }
 
   /* Now check the statements after the call.  None of them has virtual
@@ -576,10 +597,13 @@ adjust_return_value_with_ops (enum tree_code code, const char *label,
 {
 
   tree ret_type = TREE_TYPE (DECL_RESULT (current_function_decl));
-  tree tmp = create_tmp_reg (ret_type, label);
+  tree tmp = create_tmp_var (ret_type, label);
   gimple stmt;
   tree result;
 
+  if (TREE_CODE (ret_type) == COMPLEX_TYPE
+      || TREE_CODE (ret_type) == VECTOR_TYPE)
+    DECL_GIMPLE_REG_P (tmp) = 1;
   add_referenced_var (tmp);
 
   if (types_compatible_p (TREE_TYPE (acc), TREE_TYPE (op1)))
@@ -906,9 +930,12 @@ static tree
 create_tailcall_accumulator (const char *label, basic_block bb, tree init)
 {
   tree ret_type = TREE_TYPE (DECL_RESULT (current_function_decl));
-  tree tmp = create_tmp_reg (ret_type, label);
+  tree tmp = create_tmp_var (ret_type, label);
   gimple phi;
 
+  if (TREE_CODE (ret_type) == COMPLEX_TYPE
+      || TREE_CODE (ret_type) == VECTOR_TYPE)
+    DECL_GIMPLE_REG_P (tmp) = 1;
   add_referenced_var (tmp);
   phi = create_phi_node (tmp, bb);
   /* RET_TYPE can be a float when -ffast-maths is enabled.  */