This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC] Issues with intraprocedural devirtualization


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);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]