]> gcc.gnu.org Git - gcc.git/commitdiff
tree-inline.c (remap_ssa_name): New function.
authorJan Hubicka <jh@suse.cz>
Fri, 29 Dec 2006 11:10:31 +0000 (12:10 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Fri, 29 Dec 2006 11:10:31 +0000 (11:10 +0000)
* tree-inline.c (remap_ssa_name): New function.
(remap_decl): Update SSA datastructures for DECLs.
(copy_body_r): Deal with SSA_NAMEs; add referenced global vars.
(copy_bb): Set SSA_NAME def stmts.
(update_ssa_acorss_eh_edges): New function.
(copy_edge_for_bb): Call it; mark new vars for renaming.
(copy_phis_for_bb): New function.
(initialize_cfun): Break out from ...
(copy_cfg_body): ... here; maintain AUX map for both directions;
call SSA updating workers; do not produce copy of cfun to be copied.
(setup_one_parameter): Do propagation across SSA form.
(declare_return_variable): Work on SSA; use return_slot instead of
address of return slot of argument to avoid folding back and forth.
(expand_call_inline): Update SSA from on return values.
(optimize_inline_calls): Do sanity checking, dead blocks removal,
update SSA form.
(tree_function_verioning): Update initialize_cfun.

From-SVN: r120260

gcc/ChangeLog
gcc/tree-inline.c

index 60d763705020387558e03ad2cd6706b68467398c..f4c9b9c14ead555b64a93794f4404f88380262dc 100644 (file)
@@ -1,3 +1,23 @@
+2006-12-29  Jan Hubicka  <jh@suse.cz>
+
+       * tree-inline.c (remap_ssa_name): New function.
+       (remap_decl): Update SSA datastructures for DECLs.
+       (copy_body_r): Deal with SSA_NAMEs; add referenced global vars.
+       (copy_bb): Set SSA_NAME def stmts.
+       (update_ssa_acorss_eh_edges): New function.
+       (copy_edge_for_bb): Call it; mark new vars for renaming.
+       (copy_phis_for_bb): New function.
+       (initialize_cfun): Break out from ...
+       (copy_cfg_body): ... here; maintain AUX map for both directions;
+       call SSA updating workers; do not produce copy of cfun to be copied.
+       (setup_one_parameter): Do propagation across SSA form.
+       (declare_return_variable): Work on SSA; use return_slot instead of
+       address of return slot of argument to avoid folding back and forth.
+       (expand_call_inline): Update SSA from on return values.
+       (optimize_inline_calls): Do sanity checking, dead blocks removal,
+       update SSA form.
+       (tree_function_verioning): Update initialize_cfun.
+
 2006-12-29  Marcin Dalecki  <martin@dalecki.de>
 
        * doc/invoke.texi: Replace no longer supported -fno-strength-reduce
index 39d9f11cc7db67aa5fd92e8d4e864d6131bc0290..8843eb27fde25da88cc4b8d516974f36e241999e 100644 (file)
@@ -50,6 +50,7 @@ Boston, MA 02110-1301, USA.  */
 #include "pointer-set.h"
 #include "ipa-prop.h"
 #include "value-prof.h"
+#include "tree-pass.h"
 
 /* I'm not real happy about this, but we need to handle gimple and
    non-gimple trees.  */
@@ -141,6 +142,50 @@ insert_decl_map (copy_body_data *id, tree key, tree value)
                       (splay_tree_value) value);
 }
 
+/* Construct new SSA name for old NAME. ID is the inline context.  */
+
+static tree
+remap_ssa_name (tree name, copy_body_data *id)
+{
+  tree new;
+  splay_tree_node n;
+
+  gcc_assert (TREE_CODE (name) == SSA_NAME);
+
+  n = splay_tree_lookup (id->decl_map, (splay_tree_key) name);
+  if (n)
+    return (tree) n->value;
+
+  /* Do not set DEF_STMT yet as statement is not copied yet. We do that
+     in copy_bb.  */
+  new = remap_decl (SSA_NAME_VAR (name), id);
+  /* We might've substituted constant or another SSA_NAME for
+     the variable. 
+
+     Replace the SSA name representing RESULT_DECL by variable during
+     inlining:  this saves us from need to introduce PHI node in a case
+     return value is just partly initialized.  */
+  if ((TREE_CODE (new) == VAR_DECL || TREE_CODE (new) == PARM_DECL)
+      && (TREE_CODE (SSA_NAME_VAR (name)) != RESULT_DECL
+         || !id->transform_return_to_modify))
+    {
+      new = make_ssa_name (new, NULL);
+      insert_decl_map (id, name, new);
+      if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (name)))
+       {
+         SSA_NAME_DEF_STMT (new) = build_empty_stmt ();
+         if (gimple_default_def (id->src_cfun, SSA_NAME_VAR (name)) == name)
+           set_default_def (SSA_NAME_VAR (new), new);
+       }
+      SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new)
+       = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name);
+      TREE_TYPE (new) = TREE_TYPE (SSA_NAME_VAR (new));
+    }
+  else
+    insert_decl_map (id, name, new);
+  return new;
+}
+
 /* Remap DECL during the copying of the BLOCK tree for the function.  */
 
 tree
@@ -188,6 +233,22 @@ remap_decl (tree decl, copy_body_data *id)
            walk_tree (&DECL_QUALIFIER (t), copy_body_r, id, NULL);
        }
 
+      if (cfun && gimple_in_ssa_p (cfun)
+         && (TREE_CODE (t) == VAR_DECL
+             || TREE_CODE (t) == RESULT_DECL || TREE_CODE (t) == PARM_DECL))
+       {
+          tree def = gimple_default_def (id->src_cfun, decl);
+         get_var_ann (t);
+         if (TREE_CODE (decl) != PARM_DECL && def)
+           {
+             tree map = remap_ssa_name (def, id);
+             /* Watch out RESULT_DECLs whose SSA names map directly
+                to them.  */
+             if (TREE_CODE (map) == SSA_NAME)
+               set_default_def (t, map);
+           }
+         add_referenced_var (t);
+       }
       return t;
     }
 
@@ -500,6 +561,12 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
          return (tree) (void *)1;
        }
     }
+  else if (TREE_CODE (*tp) == SSA_NAME)
+    {
+      *tp = remap_ssa_name (*tp, id);
+      *walk_subtrees = 0;
+      return NULL;
+    }
 
   /* Local variables and labels need to be replaced by equivalent
      variables.  We don't want to copy static variables; there's only
@@ -621,6 +688,11 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
       /* Here is the "usual case".  Copy this tree node, and then
         tweak some special cases.  */
       copy_tree_r (tp, walk_subtrees, NULL);
+
+      /* Global variables we didn't seen yet needs to go into referenced
+        vars.  */
+      if (gimple_in_ssa_p (cfun) && TREE_CODE (*tp) == VAR_DECL)
+       add_referenced_var (*tp);
        
       /* If EXPR has block defined, map it to newly constructed block.
          When inlining we want EXPRs without block appear in the block
@@ -718,74 +790,132 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
            gimplify_stmt (&stmt);
 
           bsi_insert_after (&copy_bsi, stmt, BSI_NEW_STMT);
-         call = get_call_expr_in (stmt);
-         /* We're duplicating a CALL_EXPR.  Find any corresponding
-            callgraph edges and update or duplicate them.  */
-         if (call && (decl = get_callee_fndecl (call)))
+
+         /* Process new statement.  gimplify_stmt possibly turned statement
+            into multiple statements, we need to process all of them.  */
+         while (!bsi_end_p (copy_bsi))
            {
-             struct cgraph_node *node;
-             struct cgraph_edge *edge;
-            
-             switch (id->transform_call_graph_edges)
+             stmt = bsi_stmt (copy_bsi);
+             call = get_call_expr_in (stmt);
+             /* We're duplicating a CALL_EXPR.  Find any corresponding
+                callgraph edges and update or duplicate them.  */
+             if (call && (decl = get_callee_fndecl (call)))
                {
-               case CB_CGE_DUPLICATE:
-                 edge = cgraph_edge (id->src_node, orig_stmt);
-                 if (edge)
-                   cgraph_clone_edge (edge, id->dst_node, stmt,
-                                      REG_BR_PROB_BASE, 1, true);
-                 break;
-
-               case CB_CGE_MOVE_CLONES:
-                 for (node = id->dst_node->next_clone;
-                      node;
-                      node = node->next_clone)
+                 struct cgraph_node *node;
+                 struct cgraph_edge *edge;
+                
+                 switch (id->transform_call_graph_edges)
                    {
-                     edge = cgraph_edge (node, orig_stmt);
-                     gcc_assert (edge);
-                     cgraph_set_call_stmt (edge, stmt);
+                   case CB_CGE_DUPLICATE:
+                     edge = cgraph_edge (id->src_node, orig_stmt);
+                     if (edge)
+                       cgraph_clone_edge (edge, id->dst_node, stmt,
+                                          REG_BR_PROB_BASE, 1, true);
+                     break;
+
+                   case CB_CGE_MOVE_CLONES:
+                     for (node = id->dst_node->next_clone;
+                          node;
+                          node = node->next_clone)
+                       {
+                         edge = cgraph_edge (node, orig_stmt);
+                         gcc_assert (edge);
+                         cgraph_set_call_stmt (edge, stmt);
+                       }
+                     /* FALLTHRU */
+
+                   case CB_CGE_MOVE:
+                     edge = cgraph_edge (id->dst_node, orig_stmt);
+                     if (edge)
+                       cgraph_set_call_stmt (edge, stmt);
+                     break;
+
+                   default:
+                     gcc_unreachable ();
                    }
-                 /* FALLTHRU */
-
-               case CB_CGE_MOVE:
-                 edge = cgraph_edge (id->dst_node, orig_stmt);
-                 if (edge)
-                   cgraph_set_call_stmt (edge, stmt);
-                 break;
+               }
+             /* If you think we can abort here, you are wrong.
+                There is no region 0 in tree land.  */
+             gcc_assert (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt)
+                         != 0);
 
-               default:
-                 gcc_unreachable ();
+             if (tree_could_throw_p (stmt))
+               {
+                 int region = lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt);
+                 /* Add an entry for the copied tree in the EH hashtable.
+                    When cloning or versioning, use the hashtable in
+                    cfun, and just copy the EH number.  When inlining, use the
+                    hashtable in the caller, and adjust the region number.  */
+                 if (region > 0)
+                   add_stmt_to_eh_region (stmt, region + id->eh_region_offset);
+
+                 /* If this tree doesn't have a region associated with it,
+                    and there is a "current region,"
+                    then associate this tree with the current region
+                    and add edges associated with this region.  */
+                 if ((lookup_stmt_eh_region_fn (id->src_cfun,
+                                                orig_stmt) <= 0
+                      && id->eh_region > 0)
+                     && tree_could_throw_p (stmt))
+                   add_stmt_to_eh_region (stmt, id->eh_region);
                }
-           }
-         /* If you think we can abort here, you are wrong.
-            There is no region 0 in tree land.  */
-         gcc_assert (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt)
-                     != 0);
+             if (gimple_in_ssa_p (cfun))
+               {
+                  ssa_op_iter i;
+                  tree def;
 
-         if (tree_could_throw_p (stmt))
-           {
-             int region = lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt);
-             /* Add an entry for the copied tree in the EH hashtable.
-                When cloning or versioning, use the hashtable in
-                cfun, and just copy the EH number.  When inlining, use the
-                hashtable in the caller, and adjust the region number.  */
-             if (region > 0)
-               add_stmt_to_eh_region (stmt, region + id->eh_region_offset);
-
-             /* If this tree doesn't have a region associated with it,
-                and there is a "current region,"
-                then associate this tree with the current region
-                and add edges associated with this region.  */
-             if ((lookup_stmt_eh_region_fn (id->src_cfun,
-                                            orig_stmt) <= 0
-                  && id->eh_region > 0)
-                 && tree_could_throw_p (stmt))
-               add_stmt_to_eh_region (stmt, id->eh_region);
+                  find_new_referenced_vars (bsi_stmt_ptr (copy_bsi));
+                  FOR_EACH_SSA_TREE_OPERAND (def, stmt, i, SSA_OP_DEF)
+                   if (TREE_CODE (def) == SSA_NAME)
+                     SSA_NAME_DEF_STMT (def) = stmt;
+               }
+             bsi_next (&copy_bsi);
            }
+         copy_bsi = bsi_last (copy_basic_block);
        }
     }
   return copy_basic_block;
 }
 
+/* Inserting Single Entry Multiple Exit region in SSA form into code in SSA
+   form is quite easy, since dominator relationship for old basic blocks does
+   not change.
+
+   There is however exception where inlining might change dominator relation
+   across EH edges from basic block within inlined functions destinating
+   to landging pads in function we inline into.
+
+   The function mark PHI_RESULT of such PHI nodes for renaming; it is
+   safe the EH edges are abnormal and SSA_NAME_OCCURS_IN_ABNORMAL_PHI
+   must be set.  This means, that there will be no overlapping live ranges
+   for the underlying symbol.
+
+   This might change in future if we allow redirecting of EH edges and
+   we might want to change way build CFG pre-inlining to include
+   all the possible edges then.  */
+static void
+update_ssa_across_eh_edges (basic_block bb)
+{
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    if (!e->dest->aux
+       || ((basic_block)e->dest->aux)->index == ENTRY_BLOCK)
+      {
+       tree phi;
+
+       gcc_assert (e->flags & EDGE_EH);
+       for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
+         {
+           gcc_assert (SSA_NAME_OCCURS_IN_ABNORMAL_PHI
+                       (PHI_RESULT (phi)));
+           mark_sym_for_renaming
+             (SSA_NAME_VAR (PHI_RESULT (phi)));
+         }
+      }
+}
+
 /* Copy edges from BB into its copy constructed earlier, scale profile
    accordingly.  Edges will be taken care of later.  Assume aux
    pointers to point to the copies of each BB.  */
@@ -825,6 +955,8 @@ copy_edges_for_bb (basic_block bb, int count_scale)
 
       copy_stmt = bsi_stmt (bsi);
       update_stmt (copy_stmt);
+      if (gimple_in_ssa_p (cfun))
+        mark_symbols_for_renaming (copy_stmt);
       /* Do this before the possible split_block.  */
       bsi_next (&bsi);
 
@@ -847,11 +979,54 @@ copy_edges_for_bb (basic_block bb, int count_scale)
               right at this point; split_block doesn't care.  */
            {
              edge e = split_block (new_bb, copy_stmt);
+
              new_bb = e->dest;
+             new_bb->aux = e->src->aux;
              bsi = bsi_start (new_bb);
            }
 
            make_eh_edges (copy_stmt);
+
+          if (gimple_in_ssa_p (cfun))
+            update_ssa_across_eh_edges (bb_for_stmt (copy_stmt));
+       }
+    }
+}
+
+/* Copy the PHIs.  All blocks and edges are copied, some blocks
+   was possibly split and new outgoing EH edges inserted.
+   BB points to the block of original function and AUX pointers links
+   the original and newly copied blocks.  */
+
+static void
+copy_phis_for_bb (basic_block bb, copy_body_data *id)
+{
+  basic_block new_bb = bb->aux;
+  edge_iterator ei;
+  tree phi;
+
+  for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+    {
+      tree res = PHI_RESULT (phi);
+      tree new_res = res;
+      tree new_phi;
+      edge new_edge;
+
+      if (is_gimple_reg (res))
+       {
+         walk_tree (&new_res, copy_body_r, id, NULL);
+         SSA_NAME_DEF_STMT (new_res)
+           = new_phi = create_phi_node (new_res, new_bb);
+         FOR_EACH_EDGE (new_edge, ei, new_bb->preds)
+           {
+             edge old_edge = find_edge (new_edge->src->aux, bb);
+             tree arg = PHI_ARG_DEF_FROM_EDGE (phi, old_edge);
+             tree new_arg = arg;
+
+             walk_tree (&new_arg, copy_body_r, id, NULL);
+             gcc_assert (new_arg);
+             add_phi_arg (new_phi, new_arg, new_edge);
+           }
        }
     }
 }
@@ -863,6 +1038,67 @@ remap_decl_1 (tree decl, void *data)
   return remap_decl (decl, (copy_body_data *) data);
 }
 
+/* Build struct function and associated datastructures for the new clone
+   NEW_FNDECL to be build.  CALLEE_FNDECL is the original */
+
+static void
+initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
+                int frequency)
+{
+  struct function *new_cfun
+     = (struct function *) ggc_alloc_cleared (sizeof (struct function));
+  struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
+  int count_scale, frequency_scale;
+
+  if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
+    count_scale = (REG_BR_PROB_BASE * count
+                  / ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count);
+  else
+    count_scale = 1;
+
+  if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency)
+    frequency_scale = (REG_BR_PROB_BASE * frequency
+                      /
+                      ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency);
+  else
+    frequency_scale = count_scale;
+
+  /* Register specific tree functions.  */
+  tree_register_cfg_hooks ();
+  *new_cfun = *DECL_STRUCT_FUNCTION (callee_fndecl);
+  VALUE_HISTOGRAMS (new_cfun) = NULL;
+  new_cfun->unexpanded_var_list = NULL;
+  new_cfun->cfg = NULL;
+  new_cfun->decl = new_fndecl /*= copy_node (callee_fndecl)*/;
+  new_cfun->ib_boundaries_block = NULL;
+  DECL_STRUCT_FUNCTION (new_fndecl) = new_cfun;
+  push_cfun (new_cfun);
+  init_empty_tree_cfg ();
+
+  ENTRY_BLOCK_PTR->count =
+    (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
+     REG_BR_PROB_BASE);
+  ENTRY_BLOCK_PTR->frequency =
+    (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
+     frequency_scale / REG_BR_PROB_BASE);
+  EXIT_BLOCK_PTR->count =
+    (EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
+     REG_BR_PROB_BASE);
+  EXIT_BLOCK_PTR->frequency =
+    (EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
+     frequency_scale / REG_BR_PROB_BASE);
+  if (src_cfun->eh)
+    init_eh_for_function ();
+
+  if (src_cfun->gimple_df)
+    {
+      init_tree_ssa ();
+      cfun->gimple_df->in_ssa_p = true;
+      init_ssa_operands ();
+    }
+  pop_cfun ();
+}
+
 /* Make a copy of the body of FN so that it can be inserted inline in
    another function.  Walks FN via CFG, returns new fndecl.  */
 
@@ -873,15 +1109,11 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
   tree callee_fndecl = id->src_fn;
   /* Original cfun for the callee, doesn't change.  */
   struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
-  /* Copy, built by this function.  */
-  struct function *new_cfun;
-  /* Place to copy from; when a copy of the function was saved off earlier,
-     use that instead of the main copy.  */
-  struct function *cfun_to_copy =
-    (struct function *) ggc_alloc_cleared (sizeof (struct function));
+  struct function *cfun_to_copy;
   basic_block bb;
   tree new_fndecl = NULL;
   int count_scale, frequency_scale;
+  int last;
 
   if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
     count_scale = (REG_BR_PROB_BASE * count
@@ -903,64 +1135,47 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
   gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION
              (DECL_STRUCT_FUNCTION (callee_fndecl)));
 
-  *cfun_to_copy = *DECL_STRUCT_FUNCTION (callee_fndecl);
-
-  id->src_cfun = cfun_to_copy;
-
-  /* If requested, create new basic_block_info and label_to_block_maps.
-     Otherwise, insert our new blocks and labels into the existing cfg.  */
-  if (id->transform_new_cfg)
-    {
-      new_cfun =
-       (struct function *) ggc_alloc_cleared (sizeof (struct function));
-      *new_cfun = *DECL_STRUCT_FUNCTION (callee_fndecl);
-      new_cfun->cfg = NULL;
-      new_cfun->decl = new_fndecl = copy_node (callee_fndecl);
-      new_cfun->ib_boundaries_block = NULL;
-      DECL_STRUCT_FUNCTION (new_fndecl) = new_cfun;
-      push_cfun (new_cfun);
-      init_empty_tree_cfg ();
-
-      ENTRY_BLOCK_PTR->count =
-       (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
-        REG_BR_PROB_BASE);
-      ENTRY_BLOCK_PTR->frequency =
-       (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
-        frequency_scale / REG_BR_PROB_BASE);
-      EXIT_BLOCK_PTR->count =
-       (EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
-        REG_BR_PROB_BASE);
-      EXIT_BLOCK_PTR->frequency =
-       (EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
-        frequency_scale / REG_BR_PROB_BASE);
-
-      entry_block_map = ENTRY_BLOCK_PTR;
-      exit_block_map = EXIT_BLOCK_PTR;
-    }
+  cfun_to_copy = id->src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
+
 
   ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = entry_block_map;
   EXIT_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = exit_block_map;
+  entry_block_map->aux = ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy);
+  exit_block_map->aux = EXIT_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy);
 
   /* Duplicate any exception-handling regions.  */
   if (cfun->eh)
     {
-      if (id->transform_new_cfg)
-        init_eh_for_function ();
       id->eh_region_offset
        = duplicate_eh_regions (cfun_to_copy, remap_decl_1, id,
                                0, id->eh_region);
     }
   /* Use aux pointers to map the original blocks to copy.  */
   FOR_EACH_BB_FN (bb, cfun_to_copy)
-    bb->aux = copy_bb (id, bb, frequency_scale, count_scale);
+    {
+      basic_block new = copy_bb (id, bb, frequency_scale, count_scale);
+      bb->aux = new;
+      new->aux = bb;
+    }
+
+  last = n_basic_blocks;
   /* Now that we've duplicated the blocks, duplicate their edges.  */
   FOR_ALL_BB_FN (bb, cfun_to_copy)
     copy_edges_for_bb (bb, count_scale);
+  if (gimple_in_ssa_p (cfun))
+    FOR_ALL_BB_FN (bb, cfun_to_copy)
+      copy_phis_for_bb (bb, id);
   FOR_ALL_BB_FN (bb, cfun_to_copy)
-    bb->aux = NULL;
-
-  if (id->transform_new_cfg)
-    pop_cfun ();
+    {
+      ((basic_block)bb->aux)->aux = NULL;
+      bb->aux = NULL;
+    }
+  /* Zero out AUX fields of newly created block during EH edge
+     insertion. */
+  for (; last < n_basic_blocks; last++)
+    BASIC_BLOCK (last)->aux = NULL;
+  entry_block_map->aux = NULL;
+  exit_block_map->aux = NULL;
 
   return new_fndecl;
 }
@@ -1017,13 +1232,17 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
   tree init_stmt;
   tree var;
   tree var_sub;
+  tree rhs = value ? fold_convert (TREE_TYPE (p), value) : NULL;
+  tree def = (gimple_in_ssa_p (cfun)
+             ? gimple_default_def (id->src_cfun, p) : NULL);
 
-  /* If the parameter is never assigned to, we may not need to
-     create a new variable here at all.  Instead, we may be able
-     to just use the argument value.  */
+  /* If the parameter is never assigned to, has no SSA_NAMEs created,
+     we may not need to create a new variable here at all.  Instead, we may
+     be able to just use the argument value.  */
   if (TREE_READONLY (p)
       && !TREE_ADDRESSABLE (p)
-      && value && !TREE_SIDE_EFFECTS (value))
+      && value && !TREE_SIDE_EFFECTS (value)
+      && !def)
     {
       /* We may produce non-gimple trees by adding NOPs or introduce
         invalid sharing when operand is not really constant.
@@ -1047,6 +1266,11 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
      here since the type of this decl must be visible to the calling
      function.  */
   var = copy_decl_to_var (p, id);
+  if (gimple_in_ssa_p (cfun) && TREE_CODE (var) == VAR_DECL)
+    {
+      get_var_ann (var);
+      add_referenced_var (var);
+    }
 
   /* See if the frontend wants to pass this by invisible reference.  If
      so, our new VAR_DECL will have REFERENCE_TYPE, and we need to
@@ -1085,21 +1309,54 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
   if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
     TREE_READONLY (var) = 0;
 
+  /* If there is no setup required and we are in SSA, take the easy route
+     replacing all SSA names representing the function parameter by the
+     SSA name passed to function.
+
+     We need to construct map for the variable anyway as it might be used
+     in different SSA names when parameter is set in function.
+
+     FIXME: This usually kills the last connection in between inlined
+     function parameter and the actual value in debug info.  Can we do
+     better here?  If we just inserted the statement, copy propagation
+     would kill it anyway as it always did in older versions of GCC.
+
+     We might want to introduce a notion that single SSA_NAME might
+     represent multiple variables for purposes of debugging. */
+  if (gimple_in_ssa_p (cfun) && rhs && def && is_gimple_reg (p)
+      && (TREE_CODE (rhs) == SSA_NAME
+         || is_gimple_min_invariant (rhs)))
+    {
+      insert_decl_map (id, def, rhs);
+      return;
+    }
+
   /* Initialize this VAR_DECL from the equivalent argument.  Convert
      the argument to the proper type in case it was promoted.  */
   if (value)
     {
-      tree rhs = fold_convert (TREE_TYPE (var), value);
       block_stmt_iterator bsi = bsi_last (bb);
 
       if (rhs == error_mark_node)
-       return;
+       {
+         insert_decl_map (id, p, var_sub);
+         return;
+       }
 
       STRIP_USELESS_TYPE_CONVERSION (rhs);
 
       /* We want to use GIMPLE_MODIFY_STMT, not INIT_EXPR here so that we
         keep our trees in gimple form.  */
-      init_stmt = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (var), var, rhs);
+      if (def && gimple_in_ssa_p (cfun) && is_gimple_reg (p))
+       {
+         def = remap_ssa_name (def, id);
+          init_stmt = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (var), def, rhs);
+         SSA_NAME_DEF_STMT (def) = init_stmt;
+         SSA_NAME_IS_DEFAULT_DEF (def) = 0;
+         set_default_def (var, NULL);
+       }
+      else
+        init_stmt = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (var), var, rhs);
 
       /* If we did not create a gimple value and we did not create a gimple
         cast of a gimple value, then we will need to gimplify INIT_STMTS
@@ -1110,12 +1367,29 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
          && (!is_gimple_cast (rhs)
              || !is_gimple_val (TREE_OPERAND (rhs, 0))))
          || !is_gimple_reg (var))
-       gimplify_stmt (&init_stmt);
+       {
+          tree_stmt_iterator i;
+
+         push_gimplify_context ();
+         gimplify_stmt (&init_stmt);
+         if (gimple_in_ssa_p (cfun)
+              && init_stmt && TREE_CODE (init_stmt) == STATEMENT_LIST)
+           {
+             /* The replacement can expose previously unreferenced
+                variables.  */
+             for (i = tsi_start (init_stmt); !tsi_end_p (i); tsi_next (&i))
+               find_new_referenced_vars (tsi_stmt_ptr (i));
+            }
+         pop_gimplify_context (NULL);
+       }
 
       /* If VAR represents a zero-sized variable, it's possible that the
         assignment statment may result in no gimple statements.  */
       if (init_stmt)
         bsi_insert_after (&bsi, init_stmt, BSI_NEW_STMT);
+      if (gimple_in_ssa_p (cfun))
+       for (;!bsi_end_p (bsi); bsi_next (&bsi))
+         mark_symbols_for_renaming (bsi_stmt (bsi));
     }
 }
 
@@ -1170,17 +1444,17 @@ initialize_inlined_parameters (copy_body_data *id, tree args, tree static_chain,
    The USE_STMT is filled to contain a use of the declaration to
    indicate the return value of the function.
 
-   RETURN_SLOT_ADDR, if non-null, was a fake parameter that
-   took the address of the result.  MODIFY_DEST, if non-null, was the LHS of
-   the GIMPLE_MODIFY_STMT to which this call is the RHS.
+   RETURN_SLOT, if non-null is place where to store the result.  It
+   is set only for CALL_EXPR_RETURN_SLOT_OPT.  MODIFY_DEST, if non-null,
+   was the LHS of the GIMPLE_MODIFY_STMT to which this call is the RHS.
 
    The return value is a (possibly null) value that is the result of the
    function as seen by the callee.  *USE_P is a (possibly null) value that
    holds the result as seen by the caller.  */
 
 static tree
-declare_return_variable (copy_body_data *id, tree return_slot_addr,
-                        tree modify_dest, tree *use_p)
+declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
+                        tree *use_p)
 {
   tree callee = id->src_fn;
   tree caller = id->dst_fn;
@@ -1199,15 +1473,49 @@ declare_return_variable (copy_body_data *id, tree return_slot_addr,
 
   /* If there was a return slot, then the return value is the
      dereferenced address of that object.  */
-  if (return_slot_addr)
+  if (return_slot)
     {
-      /* The front end shouldn't have used both return_slot_addr and
+      /* The front end shouldn't have used both return_slot and
         a modify expression.  */
       gcc_assert (!modify_dest);
       if (DECL_BY_REFERENCE (result))
-       var = return_slot_addr;
+       {
+         tree return_slot_addr = build_fold_addr_expr (return_slot);
+         STRIP_USELESS_TYPE_CONVERSION (return_slot_addr);
+
+         /* We are going to construct *&return_slot and we can't do that
+            for variables believed to be not addressable. 
+
+            FIXME: This check possibly can match, because values returned
+            via return slot optimization are not believed to have address
+            taken by alias analysis.  */
+         gcc_assert (TREE_CODE (return_slot) != SSA_NAME);
+         if (gimple_in_ssa_p (cfun))
+           {
+             HOST_WIDE_INT bitsize;
+             HOST_WIDE_INT bitpos;
+             tree offset;
+             enum machine_mode mode;
+             int unsignedp;
+             int volatilep;
+             tree base;
+             base = get_inner_reference (return_slot, &bitsize, &bitpos,
+                                         &offset,
+                                         &mode, &unsignedp, &volatilep,
+                                         false);
+             if (TREE_CODE (base) == INDIRECT_REF)
+               base = TREE_OPERAND (base, 0);
+             if (TREE_CODE (base) == SSA_NAME)
+               base = SSA_NAME_VAR (base);
+             mark_sym_for_renaming (base);
+           }
+         var = return_slot_addr;
+       }
       else
-       var = build_fold_indirect_ref (return_slot_addr);
+       {
+         var = return_slot;
+         gcc_assert (TREE_CODE (var) != SSA_NAME);
+       }
       if ((TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE
            || TREE_CODE (TREE_TYPE (result)) == VECTOR_TYPE)
          && !DECL_GIMPLE_REG_P (result)
@@ -1221,7 +1529,8 @@ declare_return_variable (copy_body_data *id, tree return_slot_addr,
   gcc_assert (!TREE_ADDRESSABLE (callee_type));
 
   /* Attempt to avoid creating a new temporary variable.  */
-  if (modify_dest)
+  if (modify_dest
+      && TREE_CODE (modify_dest) != SSA_NAME)
     {
       bool use_it = false;
 
@@ -1270,6 +1579,11 @@ declare_return_variable (copy_body_data *id, tree return_slot_addr,
   gcc_assert (TREE_CODE (TYPE_SIZE_UNIT (callee_type)) == INTEGER_CST);
 
   var = copy_result_decl_to_var (result, id);
+  if (gimple_in_ssa_p (cfun))
+    {
+      get_var_ann (var);
+      add_referenced_var (var);
+    }
 
   DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
   DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list
@@ -1938,7 +2252,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   tree fn;
   splay_tree st;
   tree args;
-  tree return_slot_addr;
+  tree return_slot;
   tree modify_dest;
   location_t saved_location;
   struct cgraph_edge *cg_edge;
@@ -2095,6 +2409,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   /* Record the function we are about to inline.  */
   id->src_fn = fn;
   id->src_node = cg_edge->callee;
+  id->src_cfun = DECL_STRUCT_FUNCTION (fn);
 
   initialize_inlined_parameters (id, args, TREE_OPERAND (t, 2), fn, bb);
 
@@ -2108,7 +2423,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   gcc_assert (TREE_CODE (DECL_INITIAL (fn)) == BLOCK);
 
   /* Find the lhs to which the result of this call is assigned.  */
-  return_slot_addr = NULL;
+  return_slot = NULL;
   if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
     {
       modify_dest = GIMPLE_STMT_OPERAND (stmt, 0);
@@ -2123,8 +2438,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
        TREE_NO_WARNING (modify_dest) = 1;
       if (CALL_EXPR_RETURN_SLOT_OPT (t))
        {
-         return_slot_addr = build_fold_addr_expr (modify_dest);
-         STRIP_USELESS_TYPE_CONVERSION (return_slot_addr);
+         return_slot = modify_dest;
          modify_dest = NULL;
        }
     }
@@ -2132,7 +2446,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
     modify_dest = NULL;
 
   /* Declare the return variable for the function.  */
-  declare_return_variable (id, return_slot_addr,
+  declare_return_variable (id, return_slot,
                           modify_dest, &use_retvar);
 
   /* This is it.  Duplicate the callee body.  Assume callee is
@@ -2164,12 +2478,44 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   if (use_retvar && (TREE_CODE (bsi_stmt (stmt_bsi)) != CALL_EXPR))
     {
       *tp = use_retvar;
+      if (gimple_in_ssa_p (cfun))
+       {
+          update_stmt (stmt);
+          mark_symbols_for_renaming (stmt);
+       }
       maybe_clean_or_replace_eh_stmt (stmt, stmt);
     }
   else
     /* We're modifying a TSI owned by gimple_expand_calls_inline();
        tsi_delink() will leave the iterator in a sane state.  */
-    bsi_remove (&stmt_bsi, true);
+    {
+      /* Handle case of inlining function that miss return statement so 
+         return value becomes undefined.  */
+      if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
+         && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) == SSA_NAME)
+       {
+         tree name = TREE_OPERAND (stmt, 0);
+         tree var = SSA_NAME_VAR (TREE_OPERAND (stmt, 0));
+         tree def = gimple_default_def (cfun, var);
+
+         /* If the variable is used undefined, make this name undefined via
+            move.  */
+         if (def)
+           {
+             TREE_OPERAND (stmt, 1) = def;
+             update_stmt (stmt);
+           }
+         /* Otherwise make this variable undefined.  */
+         else
+           {
+             bsi_remove (&stmt_bsi, true);
+             set_default_def (var, name);
+             SSA_NAME_DEF_STMT (name) = build_empty_stmt ();
+           }
+       }
+      else
+        bsi_remove (&stmt_bsi, true);
+    }
 
   if (purge_dead_abnormal_edges)
     tree_purge_dead_abnormal_call_edges (return_block);
@@ -2290,7 +2636,23 @@ optimize_inline_calls (tree fn)
      as inlining loops might increase the maximum.  */
   if (ENTRY_BLOCK_PTR->count)
     counts_to_freqs ();
-  fold_cond_expr_cond ();
+  if (gimple_in_ssa_p (cfun))
+    {
+      /* We make no attempts to keep dominance info up-to-date.  */
+      free_dominance_info (CDI_DOMINATORS);
+      free_dominance_info (CDI_POST_DOMINATORS);
+      delete_unreachable_blocks ();
+      update_ssa (TODO_update_ssa);
+      fold_cond_expr_cond ();
+      if (need_ssa_update_p ())
+        update_ssa (TODO_update_ssa);
+    }
+  else
+    fold_cond_expr_cond ();
+  /* It would be nice to check SSA/CFG/statement consistency here, but it is
+     not possible yet - the IPA passes might make various functions to not
+     throw and they don't care to proactively update local EH info.  This is
+     done later in fixup_cfg pass that also execute the verification.  */
 }
 
 /* FN is a function that has a complete body, and CLONE is a function whose
@@ -2782,7 +3144,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   struct cgraph_node *old_version_node;
   struct cgraph_node *new_version_node;
   copy_body_data id;
-  tree p, new_fndecl;
+  tree p;
   unsigned i;
   struct ipa_replace_map *replace_info;
   basic_block old_entry_block;
@@ -2828,6 +3190,12 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   id.transform_lang_insert_block = false;
 
   current_function_decl = new_decl;
+  old_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION
+    (DECL_STRUCT_FUNCTION (old_decl));
+  initialize_cfun (new_decl, old_decl,
+                  old_entry_block->count,
+                  old_entry_block->frequency);
+  push_cfun (DECL_STRUCT_FUNCTION (new_decl));
   
   /* Copy the function's static chain.  */
   p = DECL_STRUCT_FUNCTION (old_decl)->static_chain_decl;
@@ -2871,22 +3239,8 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
       }
   
   /* Copy the Function's body.  */
-  old_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION
-    (DECL_STRUCT_FUNCTION (old_decl));
-  new_fndecl = copy_body (&id,
-                         old_entry_block->count,
-                         old_entry_block->frequency, NULL, NULL);
+  copy_body (&id, old_entry_block->count, old_entry_block->frequency, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR);
   
-  DECL_SAVED_TREE (new_decl) = DECL_SAVED_TREE (new_fndecl);
-
-  DECL_STRUCT_FUNCTION (new_decl)->cfg =
-    DECL_STRUCT_FUNCTION (new_fndecl)->cfg;
-  DECL_STRUCT_FUNCTION (new_decl)->eh = DECL_STRUCT_FUNCTION (new_fndecl)->eh;
-  DECL_STRUCT_FUNCTION (new_decl)->ib_boundaries_block =
-    DECL_STRUCT_FUNCTION (new_fndecl)->ib_boundaries_block;
-  DECL_STRUCT_FUNCTION (new_decl)->last_label_uid =
-    DECL_STRUCT_FUNCTION (new_fndecl)->last_label_uid;
-
   if (DECL_RESULT (old_decl) != NULL_TREE)
     {
       tree *res_decl = &DECL_RESULT (old_decl);
@@ -2894,13 +3248,20 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
       lang_hooks.dup_lang_specific_decl (DECL_RESULT (new_decl));
     }
   
-  current_function_decl = NULL;
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (new_decl);
 
   /* Clean up.  */
   splay_tree_delete (id.decl_map);
   fold_cond_expr_cond ();
+  if (gimple_in_ssa_p (cfun))
+    {
+      update_ssa (TODO_update_ssa);
+    }
+  free_dominance_info (CDI_DOMINATORS);
+  free_dominance_info (CDI_POST_DOMINATORS);
+  pop_cfun ();
+  current_function_decl = NULL;
   return;
 }
 
This page took 0.107525 seconds and 5 git commands to generate.