]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/8781 (Pessimization of C++ (functional) code)
authorRichard Guenther <rguenther@suse.de>
Sat, 4 Apr 2009 09:34:32 +0000 (09:34 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Sat, 4 Apr 2009 09:34:32 +0000 (09:34 +0000)
2009-04-04  Richard Guenther  <rguenther@suse.de>

PR tree-optimization/8781
PR tree-optimization/37892
* tree-ssa-sccvn.h (vn_reference_fold_indirect): Declare.
* tree-ssa-sccvn.c (vn_reference_fold_indirect): New function.
(valueize_refs): Call it for *& valueizations.
(shared_reference_ops_from_ref): Rename to ...
(valueize_shared_reference_ops_from_ref): ... this and valueize.
(shared_reference_ops_from_call): Rename to ...
(valueize_shared_reference_ops_from_call): ... this and valueize.
(vn_reference_lookup): Update.
(visit_reference_op_call): Likewise.
* tree-ssa-pre.c (phi_translate_1): Fold *&.
(eliminate): Value-replace the call address in call statements.

* g++.dg/tree-ssa/pr8781.C: New testcase.
* gcc.dg/tree-ssa/ssa-pre-25.c: Likewise.

From-SVN: r145533

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/tree-ssa/pr8781.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-25.c [new file with mode: 0644]
gcc/tree-ssa-pre.c
gcc/tree-ssa-sccvn.c
gcc/tree-ssa-sccvn.h

index 18fb789461fa9a197ed0234bab20471a886b2943..69fbfd5fe29a6adca08e37f24ec5d5058356d2c0 100644 (file)
@@ -1,3 +1,19 @@
+2009-04-04  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/8781
+       PR tree-optimization/37892
+       * tree-ssa-sccvn.h (vn_reference_fold_indirect): Declare.
+       * tree-ssa-sccvn.c (vn_reference_fold_indirect): New function.
+       (valueize_refs): Call it for *& valueizations.
+       (shared_reference_ops_from_ref): Rename to ...
+       (valueize_shared_reference_ops_from_ref): ... this and valueize.
+       (shared_reference_ops_from_call): Rename to ...
+       (valueize_shared_reference_ops_from_call): ... this and valueize.
+       (vn_reference_lookup): Update.
+       (visit_reference_op_call): Likewise.
+       * tree-ssa-pre.c (phi_translate_1): Fold *&.
+       (eliminate): Value-replace the call address in call statements.
+
 2009-04-04  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/39636
index 3e322f5524d4b6e13a281221c9910426ecc6ccb0..82894528ca54689e2823d937d261a227c8e7a536 100644 (file)
@@ -1,3 +1,10 @@
+2009-04-04  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/8781
+       PR tree-optimization/37892
+       * g++.dg/tree-ssa/pr8781.C: New testcase.
+       * gcc.dg/tree-ssa/ssa-pre-25.c: Likewise.
+
 2009-04-04  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/39636
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr8781.C b/gcc/testsuite/g++.dg/tree-ssa/pr8781.C
new file mode 100644 (file)
index 0000000..a9d279a
--- /dev/null
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-fre-details" } */
+
+int f();
+
+template<typename predicate>
+class noop_t {
+    const predicate &pred;
+public:
+    explicit noop_t(const predicate &p) : pred(p) {}
+
+    int operator()() const { return pred(); }
+};
+
+template<typename predicate>
+inline noop_t<predicate> noop(const predicate pred) {
+    return noop_t<predicate>(pred);
+}
+
+int x()
+{
+  return (noop(noop(noop(noop(noop(noop(noop(noop(noop(f)))))))))());
+}
+
+/* We should optimize this to a direct call.  */
+
+/* { dg-final { scan-tree-dump "Replacing call target with f" "fre" } } */
+/* { dg-final { cleanup-tree-dump "fre" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-25.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-25.c
new file mode 100644 (file)
index 0000000..32b0682
--- /dev/null
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-pre-stats" } */
+
+struct X { int i; };
+
+int foo (int x)
+{
+  struct X a;
+  struct X b;
+  struct X *p;
+  a.i = 1;
+  b.i = 2;
+  if (x)
+    p = &a;
+  else
+    p = &b;
+  return p->i;
+}
+
+/* We should eliminate the load from p for a PHI node with values 1 and 2.  */
+
+/* { dg-final { scan-tree-dump "Eliminated: 1" "pre" } } */
+/* { dg-final { cleanup-tree-dump "pre" } } */
index c1cbe0ca6502be3d22de33f02cb2095f94bf6697..ed326e40303c4b5a060bf9d2aad8fb74ac0be185 100644 (file)
@@ -1563,11 +1563,12 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
        tree newvuse = vuse;
        VEC (vn_reference_op_s, heap) *newoperands = NULL;
        bool changed = false;
-       unsigned int i;
+       unsigned int i, j;
        vn_reference_op_t operand;
        vn_reference_t newref;
 
-       for (i = 0; VEC_iterate (vn_reference_op_s, operands, i, operand); i++)
+       for (i = 0, j = 0;
+            VEC_iterate (vn_reference_op_s, operands, i, operand); i++, j++)
          {
            pre_expr opresult;
            pre_expr leader;
@@ -1642,7 +1643,13 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
            newop.op0 = op0;
            newop.op1 = op1;
            newop.op2 = op2;
-           VEC_replace (vn_reference_op_s, newoperands, i, &newop);
+           VEC_replace (vn_reference_op_s, newoperands, j, &newop);
+           /* If it transforms from an SSA_NAME to an address, fold with
+              a preceding indirect reference.  */
+           if (j > 0 && op0 && TREE_CODE (op0) == ADDR_EXPR
+               && VEC_index (vn_reference_op_s,
+                             newoperands, j - 1)->opcode == INDIRECT_REF)
+             vn_reference_fold_indirect (&newoperands, &j);
          }
        if (i != VEC_length (vn_reference_op_s, operands))
          {
@@ -4098,6 +4105,29 @@ eliminate (void)
                  todo = TODO_cleanup_cfg;
                }
            }
+         /* Visit indirect calls and turn them into direct calls if
+            possible.  */
+         if (gimple_code (stmt) == GIMPLE_CALL
+             && TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME)
+           {
+             tree fn = VN_INFO (gimple_call_fn (stmt))->valnum;
+             if (TREE_CODE (fn) == ADDR_EXPR
+                 && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL)
+               {
+                 if (dump_file && (dump_flags & TDF_DETAILS))
+                   {
+                     fprintf (dump_file, "Replacing call target with ");
+                     print_generic_expr (dump_file, fn, 0);
+                     fprintf (dump_file, " in ");
+                     print_gimple_stmt (dump_file, stmt, 0, 0);
+                   }
+
+                 gimple_call_set_fn (stmt, fn);
+                 update_stmt (stmt);
+                 if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
+                   gimple_purge_dead_eh_edges (b);
+               }
+           }
        }
     }
 
index 8abc3061a2050d3f6071973ab3656043f5d89283..729787be3f7078479aa8e3c95799c2fdd6b1bc2c 100644 (file)
@@ -744,36 +744,52 @@ create_reference_ops_from_call (gimple call)
   return result;
 }
 
-static VEC(vn_reference_op_s, heap) *shared_lookup_references;
-
-/* Create a vector of vn_reference_op_s structures from REF, a
-   REFERENCE_CLASS_P tree.  The vector is shared among all callers of
-   this function.  */
-
-static VEC(vn_reference_op_s, heap) *
-shared_reference_ops_from_ref (tree ref)
+/* Fold *& at position *I_P in a vn_reference_op_s vector *OPS.  Updates
+   *I_P to point to the last element of the replacement.  */
+void
+vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **ops,
+                           unsigned int *i_p)
 {
-  if (!ref)
-    return NULL;
-  VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
-  copy_reference_ops_from_ref (ref, &shared_lookup_references);
-  return shared_lookup_references;
-}
+  VEC(vn_reference_op_s, heap) *mem = NULL;
+  vn_reference_op_t op;
+  unsigned int i = *i_p;
+  unsigned int j;
 
-/* Create a vector of vn_reference_op_s structures from CALL, a
-   call statement.  The vector is shared among all callers of
-   this function.  */
+  /* Get ops for the addressed object.  */
+  op = VEC_index (vn_reference_op_s, *ops, i);
+  copy_reference_ops_from_ref (TREE_OPERAND (op->op0, 0), &mem);
 
-static VEC(vn_reference_op_s, heap) *
-shared_reference_ops_from_call (gimple call)
-{
-  if (!call)
-    return NULL;
-  VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
-  copy_reference_ops_from_call (call, &shared_lookup_references);
-  return shared_lookup_references;
-}
+  /* Do the replacement - we should have at least one op in mem now.  */
+  if (VEC_length (vn_reference_op_s, mem) == 1)
+    {
+      VEC_replace (vn_reference_op_s, *ops, i - 1,
+                  VEC_index (vn_reference_op_s, mem, 0));
+      VEC_ordered_remove (vn_reference_op_s, *ops, i);
+      i--;
+    }
+  else if (VEC_length (vn_reference_op_s, mem) == 2)
+    {
+      VEC_replace (vn_reference_op_s, *ops, i - 1,
+                  VEC_index (vn_reference_op_s, mem, 0));
+      VEC_replace (vn_reference_op_s, *ops, i,
+                  VEC_index (vn_reference_op_s, mem, 1));
+    }
+  else if (VEC_length (vn_reference_op_s, mem) > 2)
+    {
+      VEC_replace (vn_reference_op_s, *ops, i - 1,
+                  VEC_index (vn_reference_op_s, mem, 0));
+      VEC_replace (vn_reference_op_s, *ops, i,
+                  VEC_index (vn_reference_op_s, mem, 1));
+      /* ???  There is no VEC_splice.  */
+      for (j = 2; VEC_iterate (vn_reference_op_s, mem, j, op); j++)
+       VEC_safe_insert (vn_reference_op_s, heap, *ops, ++i, op);
+    }
+  else
+    gcc_unreachable ();
 
+  VEC_free (vn_reference_op_s, heap, mem);
+  *i_p = i;
+}
 
 /* Transform any SSA_NAME's in a vector of vn_reference_op_s
    structures into their value numbers.  This is done in-place, and
@@ -783,7 +799,7 @@ static VEC (vn_reference_op_s, heap) *
 valueize_refs (VEC (vn_reference_op_s, heap) *orig)
 {
   vn_reference_op_t vro;
-  int i;
+  unsigned int i;
 
   for (i = 0; VEC_iterate (vn_reference_op_s, orig, i, vro); i++)
     {
@@ -795,15 +811,54 @@ valueize_refs (VEC (vn_reference_op_s, heap) *orig)
             the opcode.  */
          if (TREE_CODE (vro->op0) != SSA_NAME && vro->opcode == SSA_NAME)
            vro->opcode = TREE_CODE (vro->op0);
+         /* If it transforms from an SSA_NAME to an address, fold with
+            a preceding indirect reference.  */
+         if (i > 0 && TREE_CODE (vro->op0) == ADDR_EXPR
+             && VEC_index (vn_reference_op_s,
+                           orig, i - 1)->opcode == INDIRECT_REF)
+           vn_reference_fold_indirect (&orig, &i);
        }
-      /* TODO: Do we want to valueize op2 and op1 of
-        ARRAY_REF/COMPONENT_REF for Ada */
-      
+      if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
+       vro->op1 = SSA_VAL (vro->op1);
+      if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME)
+       vro->op2 = SSA_VAL (vro->op2);
     }
 
   return orig;
 }
 
+static VEC(vn_reference_op_s, heap) *shared_lookup_references;
+
+/* Create a vector of vn_reference_op_s structures from REF, a
+   REFERENCE_CLASS_P tree.  The vector is shared among all callers of
+   this function.  */
+
+static VEC(vn_reference_op_s, heap) *
+valueize_shared_reference_ops_from_ref (tree ref)
+{
+  if (!ref)
+    return NULL;
+  VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
+  copy_reference_ops_from_ref (ref, &shared_lookup_references);
+  shared_lookup_references = valueize_refs (shared_lookup_references);
+  return shared_lookup_references;
+}
+
+/* Create a vector of vn_reference_op_s structures from CALL, a
+   call statement.  The vector is shared among all callers of
+   this function.  */
+
+static VEC(vn_reference_op_s, heap) *
+valueize_shared_reference_ops_from_call (gimple call)
+{
+  if (!call)
+    return NULL;
+  VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
+  copy_reference_ops_from_call (call, &shared_lookup_references);
+  shared_lookup_references = valueize_refs (shared_lookup_references);
+  return shared_lookup_references;
+}
+
 /* Lookup a SCCVN reference operation VR in the current hash table.
    Returns the resulting value number if it exists in the hash table,
    NULL_TREE otherwise.  VNRESULT will be filled in with the actual
@@ -914,7 +969,7 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk,
     *vnresult = NULL;
 
   vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
-  vr1.operands = valueize_refs (shared_reference_ops_from_ref (op));
+  vr1.operands = valueize_shared_reference_ops_from_ref (op);
   vr1.hashcode = vn_reference_compute_hash (&vr1);
 
   if (maywalk
@@ -1585,7 +1640,7 @@ visit_reference_op_call (tree lhs, gimple stmt)
   tree vuse = gimple_vuse (stmt);
 
   vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
-  vr1.operands = valueize_refs (shared_reference_ops_from_call (stmt));
+  vr1.operands = valueize_shared_reference_ops_from_call (stmt);
   vr1.hashcode = vn_reference_compute_hash (&vr1);
   result = vn_reference_lookup_1 (&vr1, NULL);
   if (result)
index 644bc127f7829a69fe498d502950fc48ef76b8a0..c8171c227104c279cf230e654778e8606eebd512 100644 (file)
@@ -173,6 +173,8 @@ vn_nary_op_t vn_nary_op_insert_stmt (gimple, tree);
 vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
                                       tree, tree, tree, tree,
                                       tree, tree, unsigned int);
+void vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **,
+                                unsigned int *);
 void copy_reference_ops_from_ref (tree, VEC(vn_reference_op_s, heap) **);
 void copy_reference_ops_from_call (gimple, VEC(vn_reference_op_s, heap) **);
 tree get_ref_from_reference_ops (VEC(vn_reference_op_s, heap) *ops);