OSDN Git Service

2010-05-13 Martin Jambor <mjambor@suse.cz>
authorjamborm <jamborm@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 13 May 2010 12:19:02 +0000 (12:19 +0000)
committerMasaki Muranaka <monaka@monami-software.com>
Sun, 23 May 2010 05:07:42 +0000 (14:07 +0900)
* gimple.c (gimple_fold_obj_type_ref): Removed (a replacement moved to
gimple-fold.c).
* gimple-fold.c (get_base_binfo_for_type): New function.
(gimple_get_relevant_ref_binfo): Likewise.
(gimple_fold_obj_type_ref_known_binfo): Likewise.
(gimple_fold_obj_type_ref): Likewise.
(fold_gimple_call): Simplify condition for folding virtual calls
and call gimple_fold_obj_type_ref.
* gimple.h (gimple_get_relevant_ref_binfo): Declare.
(gimple_fold_obj_type_ref_known_binfo): Likewise.

* testsuite/g++.dg/otr-fold-1.C: New test.
* testsuite/g++.dg/otr-fold-2.C: New test.

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

gcc/ChangeLog
gcc/gimple-fold.c
gcc/gimple.h
gcc/testsuite/ChangeLog

index 4cc9d9d..116ef8e 100644 (file)
@@ -1,3 +1,16 @@
+2010-05-13  Martin Jambor  <mjambor@suse.cz>
+
+       * gimple.c (gimple_fold_obj_type_ref): Removed (a replacement moved to
+       gimple-fold.c).
+       * gimple-fold.c (get_base_binfo_for_type): New function.
+       (gimple_get_relevant_ref_binfo): Likewise.
+       (gimple_fold_obj_type_ref_known_binfo): Likewise.
+       (gimple_fold_obj_type_ref): Likewise.
+       (fold_gimple_call): Simplify condition for folding virtual calls
+       and call gimple_fold_obj_type_ref.
+       * gimple.h (gimple_get_relevant_ref_binfo): Declare.
+       (gimple_fold_obj_type_ref_known_binfo): Likewise.
+
 2010-05-13  Andreas Schwab  <schwab@linux-m68k.org>
 
        * config/rs6000/rs6000-protos.h
index ab07634..4fb1b3f 100644 (file)
@@ -1401,6 +1401,137 @@ gimple_fold_builtin (gimple stmt)
   return result;
 }
 
+/* Search for a base binfo of BINFO that corresponds to TYPE and return it if
+   it is found or NULL_TREE if it is not.  */
+
+static tree
+get_base_binfo_for_type (tree binfo, tree type)
+{
+  int i;
+  tree base_binfo;
+  tree res = NULL_TREE;
+
+  for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+    if (TREE_TYPE (base_binfo) == type)
+      {
+       gcc_assert (!res);
+       res = base_binfo;
+      }
+
+  return res;
+}
+
+/* Return a binfo describing the part of object referenced by expression REF.
+   Return NULL_TREE if it cannot be determined.  REF can consist of a series of
+   COMPONENT_REFs of a declaration or of an INDIRECT_REF or it can also be just
+   a simple declaration, indirect reference or an SSA_NAME.  If the function
+   discovers an INDIRECT_REF or an SSA_NAME, it will assume that the
+   encapsulating type is described by KNOWN_BINFO, if it is not NULL_TREE.
+   Otherwise the first non-artificial field declaration or the base declaration
+   will be examined to get the encapsulating type. */
+
+tree
+gimple_get_relevant_ref_binfo (tree ref, tree known_binfo)
+{
+  while (true)
+    {
+      if (TREE_CODE (ref) == COMPONENT_REF)
+       {
+         tree par_type;
+         tree binfo, base_binfo;
+         tree field = TREE_OPERAND (ref, 1);
+
+         if (!DECL_ARTIFICIAL (field))
+           {
+             tree type = TREE_TYPE (field);
+             if (TREE_CODE (type) == RECORD_TYPE)
+               return TYPE_BINFO (type);
+             else
+               return NULL_TREE;
+           }
+
+         par_type = TREE_TYPE (TREE_OPERAND (ref, 0));
+         binfo = TYPE_BINFO (par_type);
+         if (!binfo
+             || BINFO_N_BASE_BINFOS (binfo) == 0)
+           return NULL_TREE;
+
+         base_binfo = BINFO_BASE_BINFO (binfo, 0);
+         if (BINFO_TYPE (base_binfo) != TREE_TYPE (field))
+           {
+             tree d_binfo;
+
+             d_binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (ref, 0),
+                                                      known_binfo);
+             /* Get descendant binfo. */
+             if (!d_binfo)
+               return NULL_TREE;
+             return get_base_binfo_for_type (d_binfo, TREE_TYPE (field));
+           }
+
+         ref = TREE_OPERAND (ref, 0);
+       }
+      else if (DECL_P (ref) && TREE_CODE (TREE_TYPE (ref)) == RECORD_TYPE)
+       return TYPE_BINFO (TREE_TYPE (ref));
+      else if (known_binfo
+              && (TREE_CODE (ref) == SSA_NAME
+                  || TREE_CODE (ref) == INDIRECT_REF))
+       return known_binfo;
+      else
+       return NULL_TREE;
+    }
+}
+
+/* Fold a OBJ_TYPE_REF expression to the address of a function. TOKEN is
+   integer form of OBJ_TYPE_REF_TOKEN of the reference expression.  KNOWN_BINFO
+   carries the binfo describing the true type of OBJ_TYPE_REF_OBJECT(REF).  */
+
+tree
+gimple_fold_obj_type_ref_known_binfo (HOST_WIDE_INT token, tree known_binfo)
+{
+  HOST_WIDE_INT i;
+  tree v, fndecl;
+
+  v = BINFO_VIRTUALS (known_binfo);
+  i = 0;
+  while (i != token)
+    {
+      i += (TARGET_VTABLE_USES_DESCRIPTORS
+           ? TARGET_VTABLE_USES_DESCRIPTORS : 1);
+      v = TREE_CHAIN (v);
+    }
+
+  fndecl = TREE_VALUE (v);
+  return build_fold_addr_expr (fndecl);
+}
+
+
+/* Fold a OBJ_TYPE_REF expression to the address of a function.  If KNOWN_TYPE
+   is not NULL_TREE, it is the true type of the outmost encapsulating object if
+   that comes from a pointer SSA_NAME.  If the true outmost encapsulating type
+   can be determined from a declaration OBJ_TYPE_REF_OBJECT(REF), it is used
+   regardless of KNOWN_TYPE (which thus can be NULL_TREE).  */
+
+tree
+gimple_fold_obj_type_ref (tree ref, tree known_type)
+{
+  tree obj = OBJ_TYPE_REF_OBJECT (ref);
+  tree known_binfo = known_type ? TYPE_BINFO (known_type) : NULL_TREE;
+  tree binfo;
+
+  if (TREE_CODE (obj) == ADDR_EXPR)
+    obj = TREE_OPERAND (obj, 0);
+
+  binfo = gimple_get_relevant_ref_binfo (obj, known_binfo);
+  if (binfo)
+    {
+      HOST_WIDE_INT token = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1);
+      return gimple_fold_obj_type_ref_known_binfo (token, binfo);
+    }
+  else
+    return NULL_TREE;
+}
+
 /* Attempt to fold a call statement referenced by the statement iterator GSI.
    The statement may be replaced by another statement, e.g., if the call
    simplifies to a constant value. Return true if any changes were made.
@@ -1428,9 +1559,6 @@ fold_gimple_call (gimple_stmt_iterator *gsi)
     }
   else
     {
-      /* Check for resolvable OBJ_TYPE_REF.  The only sorts we can resolve
-         here are when we've propagated the address of a decl into the
-         object slot.  */
       /* ??? Should perhaps do this in fold proper.  However, doing it
          there requires that we create a new CALL_EXPR, and that requires
          copying EH region info to the new node.  Easier to just do it
@@ -1438,19 +1566,11 @@ fold_gimple_call (gimple_stmt_iterator *gsi)
       /* ??? Is there a good reason not to do this in fold_stmt_inplace?  */
       callee = gimple_call_fn (stmt);
       if (TREE_CODE (callee) == OBJ_TYPE_REF
-          && lang_hooks.fold_obj_type_ref
-          && TREE_CODE (OBJ_TYPE_REF_OBJECT (callee)) == ADDR_EXPR
-          && DECL_P (TREE_OPERAND
-                     (OBJ_TYPE_REF_OBJECT (callee), 0)))
+          && TREE_CODE (OBJ_TYPE_REF_OBJECT (callee)) == ADDR_EXPR)
         {
           tree t;
 
-          /* ??? Caution: Broken ADDR_EXPR semantics means that
-             looking at the type of the operand of the addr_expr
-             can yield an array type.  See silly exception in
-             check_pointer_types_r.  */
-          t = TREE_TYPE (TREE_TYPE (OBJ_TYPE_REF_OBJECT (callee)));
-          t = lang_hooks.fold_obj_type_ref (callee, t);
+          t = gimple_fold_obj_type_ref (callee, NULL_TREE);
           if (t)
             {
               gimple_call_set_fn (stmt, t);
index 4f1c4d4..d1018b7 100644 (file)
@@ -888,6 +888,8 @@ 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);
index 32f9801..d12a4ab 100644 (file)
@@ -1,3 +1,8 @@
+2010-05-13  Martin Jambor  <mjambor@suse.cz>
+
+       * g++.dg/otr-fold-1.C: New test.
+       * g++.dg/otr-fold-2.C: New test.
+
 2010-05-13  Jakub Jelinek  <jakub@redhat.com>
 
        PR fortran/44036