ipa-prop.c (ipa_set_jf_known_type): Check that we add only records.
authorJan Hubicka <jh@suse.cz>
Sat, 31 Aug 2013 12:26:32 +0000 (14:26 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sat, 31 Aug 2013 12:26:32 +0000 (12:26 +0000)
* ipa-prop.c (ipa_set_jf_known_type): Check that we add
only records.
(detect_type_change_1): Rename to ...
(detect_type_change): ... this one; early return on non-polymorphic
types.
(detect_type_change_ssa): Add comp_type parameter; update
use of detect_type_change.
(compute_complex_assign_jump_func): Add param_type parameter;
update use of detect_type_change_ssa.
(compute_complex_ancestor_jump_func): Likewise.
(ipa_get_callee_param_type): New function.
(ipa_compute_jump_functions_for_edge): Compute parameter type;
update calls to the jump function computation functions.

From-SVN: r202126

gcc/ChangeLog
gcc/ipa-prop.c

index 5e78ba1048bd0b68364aade270770d94debba764..030fa85e8b51a0d1da4287e722222a0690fc23cf 100644 (file)
@@ -1,3 +1,19 @@
+2013-08-30  Jan Hubicka  <jh@suse.cz>
+
+       * ipa-prop.c (ipa_set_jf_known_type): Check that we add
+       only records.
+       (detect_type_change_1): Rename to ...
+       (detect_type_change): ... this one; early return on non-polymorphic
+       types.
+       (detect_type_change_ssa): Add comp_type parameter; update       
+       use of detect_type_change.
+       (compute_complex_assign_jump_func): Add param_type parameter;
+       update use of detect_type_change_ssa.
+       (compute_complex_ancestor_jump_func): Likewise.
+       (ipa_get_callee_param_type): New function.
+       (ipa_compute_jump_functions_for_edge): Compute parameter type;
+       update calls to the jump function computation functions.
+
 2013-08-30  Teresa Johnson  <tejohnson@google.com>
            Steven Bosscher  <steven@gcc.gnu.org>
 
index ca133134d509e7e00469b5aa05b58fbb0811fa9e..fee5d1834d15861d18de1f7dd3cae8843a604f85 100644 (file)
@@ -371,6 +371,8 @@ static void
 ipa_set_jf_known_type (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset,
                       tree base_type, tree component_type)
 {
+  gcc_assert (TREE_CODE (component_type) == RECORD_TYPE
+             && TYPE_BINFO (component_type));
   jfunc->type = IPA_JF_KNOWN_TYPE;
   jfunc->value.known_type.offset = offset,
   jfunc->value.known_type.base_type = base_type;
@@ -633,13 +635,16 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
 
 
 
-/* Like detect_type_change but with extra argument COMP_TYPE which will become
-   the component type part of new JFUNC of dynamic type change is detected and
-   the new base type is identified.  */
+/* Detect whether the dynamic type of ARG of COMP_TYPE has changed (before
+   callsite CALL) by looking for assignments to its virtual table pointer.  If
+   it is, return true and fill in the jump function JFUNC with relevant type
+   information or set it to unknown.  ARG is the object itself (not a pointer
+   to it, unless dereferenced).  BASE is the base of the memory access as
+   returned by get_ref_base_and_extent, as is the offset.  */
 
 static bool
-detect_type_change_1 (tree arg, tree base, tree comp_type, gimple call,
-                     struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
+detect_type_change (tree arg, tree base, tree comp_type, gimple call,
+                   struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
 {
   struct type_change_info tci;
   ao_ref ao;
@@ -649,7 +654,12 @@ detect_type_change_1 (tree arg, tree base, tree comp_type, gimple call,
                       || handled_component_p (arg));
   /* Const calls cannot call virtual methods through VMT and so type changes do
      not matter.  */
-  if (!flag_devirtualize || !gimple_vuse (call))
+  if (!flag_devirtualize || !gimple_vuse (call)
+      /* Be sure expected_type is polymorphic.  */
+      || !comp_type
+      || TREE_CODE (comp_type) != RECORD_TYPE
+      || !TYPE_BINFO (comp_type)
+      || !BINFO_VTABLE (TYPE_BINFO (comp_type)))
     return false;
 
   ao_ref_init (&ao, arg);
@@ -679,40 +689,23 @@ detect_type_change_1 (tree arg, tree base, tree comp_type, gimple call,
   return true;
 }
 
-/* Detect whether the dynamic type of ARG has changed (before callsite CALL) by
-   looking for assignments to its virtual table pointer.  If it is, return true
-   and fill in the jump function JFUNC with relevant type information or set it
-   to unknown.  ARG is the object itself (not a pointer to it, unless
-   dereferenced).  BASE is the base of the memory access as returned by
-   get_ref_base_and_extent, as is the offset.  */
-
-static bool
-detect_type_change (tree arg, tree base, gimple call,
-                   struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
-{
-  return detect_type_change_1 (arg, base, TREE_TYPE (arg), call, jfunc, offset);
-}
-
 /* Like detect_type_change but ARG is supposed to be a non-dereferenced pointer
    SSA name (its dereference will become the base and the offset is assumed to
    be zero).  */
 
 static bool
-detect_type_change_ssa (tree arg, gimple call, struct ipa_jump_func *jfunc)
+detect_type_change_ssa (tree arg, tree comp_type,
+                       gimple call, struct ipa_jump_func *jfunc)
 {
-  tree comp_type;
-
   gcc_checking_assert (TREE_CODE (arg) == SSA_NAME);
   if (!flag_devirtualize
-      || !POINTER_TYPE_P (TREE_TYPE (arg))
-      || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != RECORD_TYPE)
+      || !POINTER_TYPE_P (TREE_TYPE (arg)))
     return false;
 
-  comp_type = TREE_TYPE (TREE_TYPE (arg));
   arg = build2 (MEM_REF, ptr_type_node, arg,
                build_int_cst (ptr_type_node, 0));
 
-  return detect_type_change_1 (arg, arg, comp_type, call, jfunc, 0);
+  return detect_type_change (arg, arg, comp_type, call, jfunc, 0);
 }
 
 /* Callback of walk_aliased_vdefs.  Flags that it has been invoked to the
@@ -988,7 +981,8 @@ static void
 compute_complex_assign_jump_func (struct ipa_node_params *info,
                                  struct param_analysis_info *parms_ainfo,
                                  struct ipa_jump_func *jfunc,
-                                 gimple call, gimple stmt, tree name)
+                                 gimple call, gimple stmt, tree name,
+                                 tree param_type)
 {
   HOST_WIDE_INT offset, size, max_size;
   tree op1, tc_ssa, base, ssa;
@@ -1030,7 +1024,11 @@ compute_complex_assign_jump_func (struct ipa_node_params *info,
        {
          bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
                                                     call, tc_ssa);
-         bool type_p = !detect_type_change_ssa (tc_ssa, call, jfunc);
+         bool type_p = false;
+
+         if (param_type && POINTER_TYPE_P (param_type))
+           type_p = !detect_type_change_ssa (tc_ssa, TREE_TYPE (param_type),
+                                             call, jfunc);
          if (type_p || jfunc->type == IPA_JF_UNKNOWN)
            ipa_set_jf_simple_pass_through (jfunc, index, agg_p, type_p);
        }
@@ -1057,9 +1055,10 @@ compute_complex_assign_jump_func (struct ipa_node_params *info,
 
   /* Dynamic types are changed in constructors and destructors.  */
   index = ipa_get_param_decl_index (info, SSA_NAME_VAR (ssa));
-  if (index >= 0)
+  if (index >= 0 && param_type && POINTER_TYPE_P (param_type))
     {
-      bool type_p = !detect_type_change (op1, base, call, jfunc, offset);
+      bool type_p = !detect_type_change (op1, base, TREE_TYPE (param_type),
+                                        call, jfunc, offset);
       if (type_p || jfunc->type == IPA_JF_UNKNOWN)
        ipa_set_ancestor_jf (jfunc, offset, TREE_TYPE (op1), index,
                             parm_ref_data_pass_through_p (&parms_ainfo[index],
@@ -1137,7 +1136,7 @@ static void
 compute_complex_ancestor_jump_func (struct ipa_node_params *info,
                                    struct param_analysis_info *parms_ainfo,
                                    struct ipa_jump_func *jfunc,
-                                   gimple call, gimple phi)
+                                   gimple call, gimple phi, tree param_type)
 {
   HOST_WIDE_INT offset;
   gimple assign, cond;
@@ -1188,7 +1187,10 @@ compute_complex_ancestor_jump_func (struct ipa_node_params *info,
        return;
     }
 
-  bool type_p = !detect_type_change (obj, expr, call, jfunc, offset);
+  bool type_p = false;
+  if (param_type && POINTER_TYPE_P (param_type))
+    type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type),
+                                 call, jfunc, offset);
   if (type_p || jfunc->type == IPA_JF_UNKNOWN)
     ipa_set_ancestor_jf (jfunc, offset, TREE_TYPE (obj), index,
                         parm_ref_data_pass_through_p (&parms_ainfo[index],
@@ -1197,18 +1199,24 @@ compute_complex_ancestor_jump_func (struct ipa_node_params *info,
 
 /* Given OP which is passed as an actual argument to a called function,
    determine if it is possible to construct a KNOWN_TYPE jump function for it
-   and if so, create one and store it to JFUNC.  */
+   and if so, create one and store it to JFUNC.
+   EXPECTED_TYPE represents a type the argument should be in  */
 
 static void
 compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc,
-                             gimple call)
+                             gimple call, tree expected_type)
 {
   HOST_WIDE_INT offset, size, max_size;
   tree base;
 
   if (!flag_devirtualize
       || TREE_CODE (op) != ADDR_EXPR
-      || TREE_CODE (TREE_TYPE (TREE_TYPE (op))) != RECORD_TYPE)
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (op))) != RECORD_TYPE
+      /* Be sure expected_type is polymorphic.  */
+      || !expected_type
+      || TREE_CODE (expected_type) != RECORD_TYPE
+      || !TYPE_BINFO (expected_type)
+      || !BINFO_VTABLE (TYPE_BINFO (expected_type)))
     return;
 
   op = TREE_OPERAND (op, 0);
@@ -1220,11 +1228,11 @@ compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc,
       || is_global_var (base))
     return;
 
-  if (!TYPE_BINFO (TREE_TYPE (base))
-      || detect_type_change (op, base, call, jfunc, offset))
+  if (detect_type_change (op, base, expected_type, call, jfunc, offset))
     return;
 
-  ipa_set_jf_known_type (jfunc, offset, TREE_TYPE (base), TREE_TYPE (op));
+  ipa_set_jf_known_type (jfunc, offset, TREE_TYPE (base),
+                        expected_type);
 }
 
 /* Inspect the given TYPE and return true iff it has the same structure (the
@@ -1495,6 +1503,37 @@ determine_known_aggregate_parts (gimple call, tree arg,
     }
 }
 
+static tree
+ipa_get_callee_param_type (struct cgraph_edge *e, int i)
+{
+  int n;
+  tree type = (e->callee
+              ? TREE_TYPE (e->callee->symbol.decl)
+              : gimple_call_fntype (e->call_stmt));
+  tree t = TYPE_ARG_TYPES (type);
+
+  for (n = 0; n < i; n++)
+    {
+      if (!t)
+        break;
+      t = TREE_CHAIN (t);
+    }
+  if (t)
+    return TREE_VALUE (t);
+  if (!e->callee)
+    return NULL;
+  t = DECL_ARGUMENTS (e->callee->symbol.decl);
+  for (n = 0; n < i; n++)
+    {
+      if (!t)
+       return NULL;
+      t = TREE_CHAIN (t);
+    }
+  if (t)
+    return TREE_TYPE (t);
+  return NULL;
+}
+
 /* Compute jump function for all arguments of callsite CS and insert the
    information in the jump_functions array in the ipa_edge_args corresponding
    to this callsite.  */
@@ -1519,6 +1558,7 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_ainfo,
     {
       struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, n);
       tree arg = gimple_call_arg (call, n);
+      tree param_type = ipa_get_callee_param_type (cs, n);
 
       if (is_gimple_ip_invariant (arg))
        ipa_set_jf_constant (jfunc, arg, cs);
@@ -1547,9 +1587,14 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_ainfo,
                  bool agg_p, type_p;
                  agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
                                                        call, arg);
-                 type_p = !detect_type_change_ssa (arg, call, jfunc);
+                 if (param_type && POINTER_TYPE_P (param_type))
+                   type_p = !detect_type_change_ssa (arg, TREE_TYPE (param_type),
+                                                     call, jfunc);
+                 else
+                   type_p = false;
                  if (type_p || jfunc->type == IPA_JF_UNKNOWN)
-                   ipa_set_jf_simple_pass_through (jfunc, index, agg_p,                                                    type_p);
+                   ipa_set_jf_simple_pass_through (jfunc, index, agg_p,
+                                                   type_p);
                }
            }
          else
@@ -1557,14 +1602,18 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_ainfo,
              gimple stmt = SSA_NAME_DEF_STMT (arg);
              if (is_gimple_assign (stmt))
                compute_complex_assign_jump_func (info, parms_ainfo, jfunc,
-                                                 call, stmt, arg);
+                                                 call, stmt, arg, param_type);
              else if (gimple_code (stmt) == GIMPLE_PHI)
                compute_complex_ancestor_jump_func (info, parms_ainfo, jfunc,
-                                                   call, stmt);
+                                                   call, stmt, param_type);
            }
        }
       else
-       compute_known_type_jump_func (arg, jfunc, call);
+       compute_known_type_jump_func (arg, jfunc, call,
+                                     param_type
+                                     && POINTER_TYPE_P (param_type)
+                                     ? TREE_TYPE (param_type)
+                                     : NULL);
 
       if ((jfunc->type != IPA_JF_PASS_THROUGH
              || !ipa_get_jf_pass_through_agg_preserved (jfunc))
@@ -1908,7 +1957,8 @@ ipa_analyze_virtual_call_uses (struct cgraph_node *node,
       anc_offset = 0;
       index = ipa_get_param_decl_index (info, SSA_NAME_VAR (obj));
       gcc_assert (index >= 0);
-      if (detect_type_change_ssa (obj, call, &jfunc))
+      if (detect_type_change_ssa (obj, obj_type_ref_class (target),
+                                 call, &jfunc))
        return;
     }
   else
@@ -1922,7 +1972,8 @@ ipa_analyze_virtual_call_uses (struct cgraph_node *node,
       index = ipa_get_param_decl_index (info,
                                        SSA_NAME_VAR (TREE_OPERAND (expr, 0)));
       gcc_assert (index >= 0);
-      if (detect_type_change (obj, expr, call, &jfunc, anc_offset))
+      if (detect_type_change (obj, expr, obj_type_ref_class (target),
+                             call, &jfunc, anc_offset))
        return;
     }
 
@@ -2134,7 +2185,7 @@ ipa_intraprocedural_devirtualization (gimple call)
 
   jfunc.type = IPA_JF_UNKNOWN;
   compute_known_type_jump_func (OBJ_TYPE_REF_OBJECT (otr), &jfunc,
-                               call);
+                               call, obj_type_ref_class (otr));
   if (jfunc.type != IPA_JF_KNOWN_TYPE)
     return NULL_TREE;
   binfo = ipa_binfo_from_known_type_jfunc (&jfunc);