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