OSDN Git Service

2006-02-02 Zdenek Dvorak <dvorakz@suse.cz>
authordberlin <dberlin@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 3 Feb 2006 00:24:50 +0000 (00:24 +0000)
committerdberlin <dberlin@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 3 Feb 2006 00:24:50 +0000 (00:24 +0000)
    Daniel Berlin  <dberlin@dberlin.org>

* tree-tailcall.c (arg_needs_copy_p): New function.
(eliminate_tail_call): Use arg_needs_copy_p.
(tree_optimize_tail_calls_1): Ditto. Also call add_virtual_phis.
(add_virtual_phis): New function.

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

gcc/ChangeLog
gcc/testsuite/gcc.c-torture/compile/20060202-1.c [new file with mode: 0644]
gcc/tree-tailcall.c

index ac296e0..7525f4c 100644 (file)
@@ -1,3 +1,11 @@
+2006-02-02  Zdenek Dvorak <dvorakz@suse.cz>
+           Daniel Berlin  <dberlin@dberlin.org>
+
+       * tree-tailcall.c (arg_needs_copy_p): New function.
+       (eliminate_tail_call): Use arg_needs_copy_p.
+       (tree_optimize_tail_calls_1): Ditto. Also call add_virtual_phis.
+       (add_virtual_phis): New function.
+
 2006-02-02  Jakub Jelinek  <jakub@redhat.com>
 
        * config/sparc/sparc.c (sparc_output_scratch_registers): Use
diff --git a/gcc/testsuite/gcc.c-torture/compile/20060202-1.c b/gcc/testsuite/gcc.c-torture/compile/20060202-1.c
new file mode 100644 (file)
index 0000000..9d44074
--- /dev/null
@@ -0,0 +1,54 @@
+typedef unsigned int size_t;
+typedef const struct objc_selector
+{
+  void *sel_id;
+}
+ *SEL;
+typedef struct objc_object
+{
+}
+ *id;
+typedef struct objc_class *Class;
+struct objc_class
+{
+  struct sarray *dtable;
+};
+typedef size_t sidx;
+struct soffset
+{
+  unsigned int boffset:(sizeof (size_t) * 8) / 2;
+  unsigned int eoffset:(sizeof (size_t) * 8) / 2;
+};
+union sofftype
+{
+  struct soffset off;
+  sidx idx;
+};
+struct sarray
+{
+  size_t capacity;
+};
+static __inline__ unsigned int
+soffset_decode (sidx indx)
+{
+  union sofftype x;
+  x.idx = indx;
+  return x.off.eoffset + (x.off.boffset * (1 << 5));
+}
+static __inline__ void *
+sarray_get_safe (struct sarray *array, sidx indx)
+{
+  if (soffset_decode (indx) < array->capacity)
+    return (void *)sarray_get (array, indx);
+}
+void *
+get_imp (Class class, SEL sel)
+{
+  void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
+  if (res == 0)
+    {
+       {
+         res = get_imp (class, sel);
+       }
+    }
+}
index 1a3116e..b0f74ff 100644 (file)
@@ -690,6 +690,25 @@ decrease_profile (basic_block bb, gcov_type count, int frequency)
     e->count = 0;
 }
 
+/* Returns true if argument PARAM of the tail recursive call needs to be copied
+   when the call is eliminated.  */
+
+static bool
+arg_needs_copy_p (tree param)
+{
+  tree def;
+
+  if (!is_gimple_reg (param) || !var_ann (param))
+    return false;
+               
+  /* Parameters that are only defined but never used need not be copied.  */
+  def = default_def (param);
+  if (!def)
+    return false;
+
+  return true;
+}
+
 /* Eliminates tail call described by T.  TMP_VARS is a list of
    temporary variables used to copy the function arguments.  */
 
@@ -701,9 +720,6 @@ eliminate_tail_call (struct tailcall *t)
   edge e;
   tree phi;
   block_stmt_iterator bsi;
-  use_operand_p mayuse;
-  def_operand_p maydef;
-  ssa_op_iter iter;
   tree orig_stmt;
 
   stmt = orig_stmt = bsi_stmt (t->call_bsi);
@@ -751,65 +767,21 @@ eliminate_tail_call (struct tailcall *t)
   gcc_assert (e);
   PENDING_STMT (e) = NULL_TREE;
 
-  /* Add phi node entries for arguments.  Not every PHI node corresponds to
-     a function argument (there may be PHI nodes for virtual definitions of the
-     eliminated calls), so we search for a PHI corresponding to each argument
-     rather than searching for which argument a PHI node corresponds to.  */
-  
+  /* Add phi node entries for arguments.  The ordering of the phi nodes should
+     be the same as the ordering of the arguments.  */
   for (param = DECL_ARGUMENTS (current_function_decl),
-       args = TREE_OPERAND (stmt, 1);
+       args = TREE_OPERAND (stmt, 1),
+       phi = phi_nodes (first);
        param;
        param = TREE_CHAIN (param),
        args = TREE_CHAIN (args))
     {
-      
-      for (phi = phi_nodes (first); phi; phi = PHI_CHAIN (phi))
-       if (param == SSA_NAME_VAR (PHI_RESULT (phi)))
-         break;
-
-      /* The phi node indeed does not have to be there, in case the operand is
-        invariant in the function.  */
-      if (!phi)
+      if (!arg_needs_copy_p (param))
        continue;
+      gcc_assert (param == SSA_NAME_VAR (PHI_RESULT (phi)));
 
       add_phi_arg (phi, TREE_VALUE (args), e);
-    }
-
-  /* Add phi nodes for the call clobbered variables.  */
-  FOR_EACH_SSA_MAYDEF_OPERAND (maydef, mayuse, orig_stmt, iter)
-    {
-      param = SSA_NAME_VAR (DEF_FROM_PTR (maydef));
-      for (phi = phi_nodes (first); phi; phi = PHI_CHAIN (phi))
-       if (param == SSA_NAME_VAR (PHI_RESULT (phi)))
-         break;
-
-      if (!phi)
-       {
-         tree name = default_def (param);
-         tree new_name;
-
-         if (!name)
-           {
-             /* It may happen that the tag does not have a default_def in case
-                when all uses of it are dominated by a MUST_DEF.  This however
-                means that it is not necessary to add a phi node for this
-                tag.  */
-             continue;
-           }
-         new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name));
-
-         set_default_def (param, new_name);
-         phi = create_phi_node (name, first);
-         SSA_NAME_DEF_STMT (name) = phi;
-         add_phi_arg (phi, new_name, single_succ_edge (ENTRY_BLOCK_PTR));
-
-         /* For all calls the same set of variables should be clobbered.  This
-            means that there always should be the appropriate phi node except
-            for the first time we eliminate the call.  */
-         gcc_assert (EDGE_COUNT (first->preds) <= 2);
-       }
-
-      add_phi_arg (phi, USE_FROM_PTR (mayuse), e);
+      phi = PHI_CHAIN (phi);
     }
 
   /* Update the values of accumulators.  */
@@ -829,6 +801,38 @@ eliminate_tail_call (struct tailcall *t)
   release_defs (call);
 }
 
+/* Add phi nodes for the virtual operands defined in the function to the
+   header of the loop created by tail recursion elimination.
+
+   Originally, we used to add phi nodes only for call clobbered variables,
+   as the value of the non-call clobbered ones obviously cannot be used
+   or changed within the recursive call.  However, the local variables
+   from multiple calls now share the same location, so the virtual ssa form
+   requires us to say that the location dies on further iterations of the loop,
+   which requires adding phi nodes.
+*/
+static void
+add_virtual_phis (void)
+{
+  referenced_var_iterator rvi;
+  tree var;
+
+  /* The problematic part is that there is no way how to know what
+     to put into phi nodes (there in fact does not have to be such
+     ssa name available).  A solution would be to have an artificial
+     use/kill for all virtual operands in EXIT node.  Unless we have
+     this, we cannot do much better than to rebuild the ssa form for
+     possibly affected virtual ssa names from scratch.  */
+
+  FOR_EACH_REFERENCED_VAR (var, rvi)
+    {
+      if (!is_gimple_reg (var) && default_def (var) != NULL_TREE)
+       mark_sym_for_renaming (var);
+    }
+
+  update_ssa (TODO_update_ssa_only_virtuals);
+}
+
 /* Optimizes the tailcall described by T.  If OPT_TAILCALLS is true, also
    mark the tailcalls for the sibcall optimization.  */
 
@@ -897,7 +901,6 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
 
       if (!phis_constructed)
        {
-         tree name;
          /* Ensure that there is only one predecessor of the block.  */
          if (!single_pred_p (first))
            first = split_edge (single_succ_edge (ENTRY_BLOCK_PTR));
@@ -906,21 +909,17 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
          for (param = DECL_ARGUMENTS (current_function_decl);
               param;
               param = TREE_CHAIN (param))
-           if (is_gimple_reg (param)
-               && var_ann (param)
-               /* Also parameters that are only defined but never used need not
-                  be copied.  */
-               && ((name = default_def (param))
-                   && TREE_CODE (name) == SSA_NAME))
-           {
-             tree new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name));
-             tree phi;
-
-             set_default_def (param, new_name);
-             phi = create_phi_node (name, first);
-             SSA_NAME_DEF_STMT (name) = phi;
-             add_phi_arg (phi, new_name, single_pred_edge (first));
-           }
+           if (arg_needs_copy_p (param))
+             {
+               tree name = default_def (param);
+               tree new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name));
+               tree phi;
+
+               set_default_def (param, new_name);
+               phi = create_phi_node (name, first);
+               SSA_NAME_DEF_STMT (name) = phi;
+               add_phi_arg (phi, new_name, single_pred_edge (first));
+             }
          phis_constructed = true;
        }
 
@@ -957,6 +956,14 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
        }
     }
 
+
+  if (phis_constructed)
+    {
+      /* Reverse the order of the phi nodes, so that it matches the order
+        of operands of the function, as assumed by eliminate_tail_call.  */
+      set_phi_nodes (first, phi_reverse (phi_nodes (first)));
+    }
+
   for (; tailcalls; tailcalls = next)
     {
       next = tailcalls->next;
@@ -982,6 +989,9 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
       free_dominance_info (CDI_DOMINATORS);
       cleanup_tree_cfg ();
     }
+
+  if (phis_constructed)
+    add_virtual_phis ();
 }
 
 static void