Hi,
here is variant of patch that drops the field walking from
gimple_extract_devirt_binfo_from_cst completely. As pointed out
by Jason, it is pointless since all structures have BINFO in C++
and thus get_binfo_at_offset will do the job.

I would like to return the code back eventually to handle arrays&unions
but that can be done incrementally (and this is not the only place that
sufers from the problem)

Martin: I am still not quite certain about the dynamic type changing logic.
if this is the case ipa-prop needs to deal with and it handles only 0 offsets
within the outer type, I guess it can just test the offset by itself?

Honza

Bootstrapped/regtested x86_64-linux, OK?

        * ipa-cp.c (ipa_get_indirect_edge_target_1): Update use
        of gimple_extract_devirt_binfo_from_cst.
        * gimple-fold.c (gimple_extract_devirt_binfo_from_cst): Rework.
        (gimple_fold_call): Update use of gimple_extract_devirt_binfo_from_cst.
        * ipa-prop.c (try_make_edge_direct_virtual_call): Likewise.
        * gimple.h (gimple_extract_devirt_binfo_from_cst): Update.

Index: ipa-cp.c
===================================================================
*** ipa-cp.c    (revision 201814)
--- ipa-cp.c    (working copy)
*************** ipa_get_indirect_edge_target_1 (struct c
*** 1541,1554 ****
    if (TREE_CODE (t) != TREE_BINFO)
      {
        tree binfo;
        binfo = gimple_extract_devirt_binfo_from_cst
!                (t, ie->indirect_info->otr_type);
        if (!binfo)
        return NULL_TREE;
!       binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
!       if (!binfo)
        return NULL_TREE;
!       return gimple_get_virt_method_for_binfo (token, binfo);
      }
    else
      {
--- 1541,1564 ----
    if (TREE_CODE (t) != TREE_BINFO)
      {
        tree binfo;
+       tree target, base_target;
        binfo = gimple_extract_devirt_binfo_from_cst
!                (t, ie->indirect_info->otr_type,
!                 ie->indirect_info->offset);
        if (!binfo)
        return NULL_TREE;
!       target = gimple_get_virt_method_for_binfo (token, binfo);
!       if (!target)
!       return NULL_TREE;
!       /* Constructors may be partially inlined.  We do not track
!          if type is in construction and during that time the
!        virtual table may correspond to virtual table of the
!        base type.  */
!       base_target = gimple_get_virt_method_for_binfo
!                    (token, TYPE_BINFO (ie->indirect_info->otr_type));
!       if (base_target != target)
        return NULL_TREE;
!       return target;
      }
    else
      {
Index: gimple-fold.c
===================================================================
*** gimple-fold.c       (revision 201814)
--- gimple-fold.c       (working copy)
*************** gimple_fold_builtin (gimple stmt)
*** 1006,1021 ****
  /* Return a binfo to be used for devirtualization of calls based on an object
     represented by a declaration (i.e. a global or automatically allocated one)
     or NULL if it cannot be found or is not safe.  CST is expected to be an
!    ADDR_EXPR of such object or the function will return NULL.  Currently it is
!    safe to use such binfo only if it has no base binfo (i.e. no ancestors)
!    EXPECTED_TYPE is type of the class virtual belongs to.  */
  
  tree
! gimple_extract_devirt_binfo_from_cst (tree cst, tree expected_type)
  {
    HOST_WIDE_INT offset, size, max_size;
!   tree base, type, binfo;
!   bool last_artificial = false;
  
    if (!flag_devirtualize
        || TREE_CODE (cst) != ADDR_EXPR
--- 1006,1025 ----
  /* Return a binfo to be used for devirtualization of calls based on an object
     represented by a declaration (i.e. a global or automatically allocated one)
     or NULL if it cannot be found or is not safe.  CST is expected to be an
!    ADDR_EXPR of such object or the function will return NULL.
! 
!    It is up to the caller to check for absence of dynamic type changes.
!    Because constructors may be partially inlined and the virtual tables
!    during construction may be overwritten by virtual tables by base types,
!    it is also up to caller to verify that either all base types have
!    the same virtual method or that this does not happen.  */
  
  tree
! gimple_extract_devirt_binfo_from_cst (tree cst, tree expected_type,
!                                     HOST_WIDE_INT otr_offset)
  {
    HOST_WIDE_INT offset, size, max_size;
!   tree base, type;
  
    if (!flag_devirtualize
        || TREE_CODE (cst) != ADDR_EXPR
*************** gimple_extract_devirt_binfo_from_cst (tr
*** 1028,1074 ****
    if (!DECL_P (base)
        || max_size == -1
        || max_size != size
!       || TREE_CODE (type) != RECORD_TYPE)
!     return NULL_TREE;
! 
!   /* Find the sub-object the constant actually refers to and mark whether it 
is
!      an artificial one (as opposed to a user-defined one).  */
!   while (true)
!     {
!       HOST_WIDE_INT pos, size;
!       tree fld;
! 
!       if (types_same_for_odr (type, expected_type))
!       break;
!       if (offset < 0)
!       return NULL_TREE;
! 
!       for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
!       {
!         if (TREE_CODE (fld) != FIELD_DECL)
!           continue;
! 
!         pos = int_bit_position (fld);
!         size = tree_low_cst (DECL_SIZE (fld), 1);
!         if (pos <= offset && (pos + size) > offset)
!           break;
!       }
!       if (!fld || TREE_CODE (TREE_TYPE (fld)) != RECORD_TYPE)
!       return NULL_TREE;
! 
!       last_artificial = DECL_ARTIFICIAL (fld);
!       type = TREE_TYPE (fld);
!       offset -= pos;
!     }
!   /* Artificial sub-objects are ancestors, we do not want to use them for
!      devirtualization, at least not here.  */
!   if (last_artificial)
!     return NULL_TREE;
!   binfo = TYPE_BINFO (type);
!   if (!binfo || BINFO_N_BASE_BINFOS (binfo) > 0)
      return NULL_TREE;
!   else
!     return binfo;
  }
  
  /* Attempt to fold a call statement referenced by the statement iterator GSI.
--- 1032,1042 ----
    if (!DECL_P (base)
        || max_size == -1
        || max_size != size
!       || TREE_CODE (type) != RECORD_TYPE
!       || !TYPE_BINFO (type))
      return NULL_TREE;
!   return get_binfo_at_offset (TYPE_BINFO (type),
!                             offset + otr_offset, expected_type);
  }
  
  /* Attempt to fold a call statement referenced by the statement iterator GSI.
*************** gimple_fold_call (gimple_stmt_iterator *
*** 1108,1121 ****
        else
        {
          tree obj = OBJ_TYPE_REF_OBJECT (callee);
          tree binfo = gimple_extract_devirt_binfo_from_cst
!                (obj, obj_type_ref_class (callee));
          if (binfo)
            {
              HOST_WIDE_INT token
                = TREE_INT_CST_LOW (OBJ_TYPE_REF_TOKEN (callee));
              tree fndecl = gimple_get_virt_method_for_binfo (token, binfo);
!             if (fndecl)
                {
                  gimple_call_set_fndecl (stmt, fndecl);
                  changed = true;
--- 1076,1095 ----
        else
        {
          tree obj = OBJ_TYPE_REF_OBJECT (callee);
+         tree class_type = obj_type_ref_class (callee);
          tree binfo = gimple_extract_devirt_binfo_from_cst
!                (obj, class_type, 0);
          if (binfo)
            {
              HOST_WIDE_INT token
                = TREE_INT_CST_LOW (OBJ_TYPE_REF_TOKEN (callee));
              tree fndecl = gimple_get_virt_method_for_binfo (token, binfo);
!             tree base_fndecl = gimple_get_virt_method_for_binfo (token, 
TYPE_BINFO (class_type));
!             /* Constructors may be partially inlined.  We do not track
!                if type is in construction and during that time the
!                virtual table may correspond to virtual table of the
!                base type.  */
!             if (fndecl && base_fndecl == fndecl)
                {
                  gimple_call_set_fndecl (stmt, fndecl);
                  changed = true;
Index: ipa-prop.c
===================================================================
*** ipa-prop.c  (revision 201814)
--- ipa-prop.c  (working copy)
*************** try_make_edge_direct_virtual_call (struc
*** 2444,2450 ****
                                   struct ipa_jump_func *jfunc,
                                   struct ipa_node_params *new_root_info)
  {
!   tree binfo, target;
  
    binfo = ipa_value_from_jfunc (new_root_info, jfunc);
  
--- 2444,2450 ----
                                   struct ipa_jump_func *jfunc,
                                   struct ipa_node_params *new_root_info)
  {
!   tree binfo, target, base_target = NULL;
  
    binfo = ipa_value_from_jfunc (new_root_info, jfunc);
  
*************** try_make_edge_direct_virtual_call (struc
*** 2454,2472 ****
    if (TREE_CODE (binfo) != TREE_BINFO)
      {
        binfo = gimple_extract_devirt_binfo_from_cst
!                (binfo, ie->indirect_info->otr_type);
        if (!binfo)
          return NULL;
      }
! 
!   binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
!                              ie->indirect_info->otr_type);
    if (binfo)
      target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
                                               binfo);
    else
      return NULL;
  
    if (target)
      return ipa_make_edge_direct_to_target (ie, target);
    else
--- 2454,2484 ----
    if (TREE_CODE (binfo) != TREE_BINFO)
      {
        binfo = gimple_extract_devirt_binfo_from_cst
!                (binfo, ie->indirect_info->otr_type,
!                 ie->indirect_info->offset);
        if (!binfo)
          return NULL;
+       /* Constructors may be partially inlined.  We do not track
+          if type is in construction and during that time the
+        virtual table may correspond to virtual table of the
+        base type.  */
+       base_target = gimple_get_virt_method_for_binfo 
(ie->indirect_info->otr_token,
+                                                     TYPE_BINFO 
(ie->indirect_info->otr_type));
+       if (!base_target)
+       return NULL;
      }
!   else
!     binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
!                                ie->indirect_info->otr_type);
    if (binfo)
      target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
                                               binfo);
    else
      return NULL;
  
+   if (base_target && target != base_target)
+     return NULL;
+ 
    if (target)
      return ipa_make_edge_direct_to_target (ie, target);
    else
Index: gimple.h
===================================================================
*** gimple.h    (revision 201814)
--- gimple.h    (working copy)
*************** unsigned get_gimple_rhs_num_ops (enum tr
*** 854,860 ****
  gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
  const char *gimple_decl_printable_name (tree, int);
  tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree);
! tree gimple_extract_devirt_binfo_from_cst (tree, tree);
  
  /* Returns true iff T is a scalar register variable.  */
  extern bool is_gimple_reg (tree);
--- 854,860 ----
  gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
  const char *gimple_decl_printable_name (tree, int);
  tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree);
! tree gimple_extract_devirt_binfo_from_cst (tree, tree, HOST_WIDE_INT);
  
  /* Returns true iff T is a scalar register variable.  */
  extern bool is_gimple_reg (tree);

Reply via email to