Add support for discarding unused virtual functions.

* search.c (dfs_search, binfo_for_vtable, dfs_bfv_helper): New fns.
	* decl2.c (output_vtable_inherit): Call binfo_for_vtable.
	* lang-options.h: Add -fvtable-gc.
	* cp-tree.h: Add flag_vtable_gc.
	* decl2.c (output_vtable_inherit): New fn.
	(finish_vtable_vardecl): Call it.
	* class.c (build_vtable_entry_ref): New fn.
	(build_vtbl_ref): Call it.

From-SVN: r22061
This commit is contained in:
Jason Merrill 1998-08-28 12:11:35 -04:00
parent 079e1098ab
commit a1dd0d36f4
6 changed files with 150 additions and 1 deletions

View File

@ -1,3 +1,18 @@
1998-08-28 Jason Merrill <jason@yorick.cygnus.com>
* search.c (dfs_search, binfo_for_vtable, dfs_bfv_helper): New fns.
* decl2.c (output_vtable_inherit): Call binfo_for_vtable.
1998-08-28 Richard Henderson <rth@cygnus.com>
Add support for discarding unused virtual functions.
* lang-options.h: Add -fvtable-gc.
* cp-tree.h: Add flag_vtable_gc.
* decl2.c (output_vtable_inherit): New fn.
(finish_vtable_vardecl): Call it.
* class.c (build_vtable_entry_ref): New fn.
(build_vtbl_ref): Call it.
1998-08-28 Mark Mitchell <mark@markmitchell.com>
* cp-tree.h (build_enumerator): Take the enumeration type as a

View File

@ -429,6 +429,36 @@ build_vtable_entry (delta, pfn)
}
}
/* We want to give the assembler the vtable identifier as well as
the offset to the function pointer. So we generate
__asm__ __volatile__ (".vtable_entry %0, %1"
: : "s"(&class_vtable),
"i"((long)&vtbl[idx].pfn - (long)&vtbl[0])); */
static void
build_vtable_entry_ref (basetype, vtbl, idx)
tree basetype, vtbl, idx;
{
static char asm_stmt[] = ".vtable_entry %0, %1";
tree s, i, i2;
s = build_unary_op (ADDR_EXPR, TYPE_BINFO_VTABLE (basetype), 0);
s = build_tree_list (build_string (1, "s"), s);
i = build_array_ref (vtbl, idx);
if (!flag_vtable_thunks)
i = build_component_ref (i, pfn_identifier, vtable_entry_type, 0);
i = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i, 0));
i2 = build_array_ref (vtbl, build_int_2(0,0));
i2 = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i2, 0));
i = build_binary_op (MINUS_EXPR, i, i2, 0);
i = build_tree_list (build_string (1, "i"), i);
expand_asm_operands (build_string (sizeof(asm_stmt)-1, asm_stmt),
NULL_TREE, chainon (s, i), NULL_TREE, 1, NULL, 0);
}
/* Given an object INSTANCE, return an expression which yields the
virtual function vtable element corresponding to INDEX. There are
many special cases for INSTANCE which we take care of here, mainly
@ -489,7 +519,12 @@ build_vtbl_ref (instance, idx)
vtbl = build_indirect_ref (build_vfield_ref (instance, basetype),
NULL_PTR);
}
assemble_external (vtbl);
if (flag_vtable_gc)
build_vtable_entry_ref (basetype, vtbl, idx);
aref = build_array_ref (vtbl, idx);
return aref;

View File

@ -476,6 +476,9 @@ extern int flag_do_squangling;
/* Nonzero if we want to issue diagnostics that the standard says are not
required. */
extern int flag_optional_diags;
/* Nonzero means output .vtable_{entry,inherit} for use in doing vtable gc. */
extern int flag_vtable_gc;
/* C++ language-specific tree codes. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM,

View File

@ -454,6 +454,9 @@ int flag_guiding_decls;
and class qualifiers. */
int flag_do_squangling;
/* Nonzero means output .vtable_{entry,inherit} for use in doing vtable gc. */
int flag_vtable_gc;
/* Table of language-dependent -f options.
STRING is the option name. VARIABLE is the address of the variable.
@ -496,6 +499,7 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
{"init-priority", &flag_init_priority, 1},
{"huge-objects", &flag_huge_objects, 1},
{"conserve-space", &flag_conserve_space, 1},
{"vtable-gc", &flag_vtable_gc, 1},
{"vtable-thunks", &flag_vtable_thunks, 1},
{"access-control", &flag_access_control, 1},
{"nonansi-builtins", &flag_no_nonansi_builtin, 0},
@ -2672,7 +2676,35 @@ finish_prevtable_vardecl (prev, vars)
import_export_vtable (vars, ctype, 1);
return 1;
}
/* We need to describe to the assembler the relationship between
a vtable and the vtable of the parent class. It is not
straightforward how to get this during multiple inheritance. */
static void
output_vtable_inherit (vars)
tree vars;
{
tree parent;
rtx op[2];
op[0] = XEXP (DECL_RTL (vars), 0); /* strip the mem ref */
parent = binfo_for_vtable (vars);
if (parent == TYPE_BINFO (DECL_CONTEXT (vars)))
op[1] = const0_rtx;
else if (parent)
{
parent = TYPE_BINFO_VTABLE (BINFO_TYPE (parent));
op[1] = XEXP (DECL_RTL (parent), 0); /* strip the mem ref */
}
else
my_friendly_abort (980826);
output_asm_insn (".vtable_inherit %0, %1", op);
}
static int
finish_vtable_vardecl (prev, vars)
tree prev, vars;
@ -2716,6 +2748,10 @@ finish_vtable_vardecl (prev, vars)
}
rest_of_decl_compilation (vars, NULL_PTR, 1, 1);
if (flag_vtable_gc)
output_vtable_inherit (vars);
return 1;
}
else if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (vars)))

View File

@ -93,6 +93,8 @@ DEFINE_LANG_NAME ("C++")
{ "-ftemplate-depth-", "Specify maximum template instantiation depth"},
{ "-fthis-is-variable", "Make 'this' not be type '* const'" },
{ "-fno-this-is-variable", "" },
{ "-fvtable-gc", "Discard unused virtual functions" },
{ "-fno-vtable-gc", "" },
{ "-fvtable-thunks", "Implement vtables using thunks" },
{ "-fno-vtable-thunks", "" },
{ "-fweak", "Emit common-like symbols as weak symbols" },

View File

@ -2147,6 +2147,41 @@ dfs_walk (binfo, fn, qfn)
fn (binfo);
}
/* Like dfs_walk, but only walk until fn returns something, and return
that. We also use the real vbase binfos instead of the placeholders
in the normal binfo hierarchy. START is the most-derived type for this
hierarchy, so that we can find the vbase binfos. */
static tree
dfs_search (binfo, fn, start)
tree binfo, start;
tree (*fn) PROTO((tree));
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree retval;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
if (TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TYPE_PARM
|| TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TEMPLATE_PARM)
/* Pass */;
else
{
if (TREE_VIA_VIRTUAL (base_binfo) && start)
base_binfo = binfo_member (BINFO_TYPE (base_binfo),
CLASSTYPE_VBASECLASSES (start));
retval = dfs_search (base_binfo, fn, start);
if (retval)
return retval;
}
}
return fn (binfo);
}
static int markedp (binfo) tree binfo;
{ return BINFO_MARKED (binfo); }
static int unmarkedp (binfo) tree binfo;
@ -3370,3 +3405,26 @@ types_overlap_p (empty_type, next_type)
return found_overlap;
}
/* Passed to dfs_search by binfo_for_vtable; determine if bvtable comes
from BINFO. */
static tree bvtable;
static tree
dfs_bfv_helper (binfo)
tree binfo;
{
if (BINFO_VTABLE (binfo) == bvtable)
return binfo;
return NULL_TREE;
}
/* Given a vtable VARS, determine which binfo it comes from. */
tree
binfo_for_vtable (vars)
tree vars;
{
bvtable = vars;
return dfs_search (TYPE_BINFO (DECL_CONTEXT (vars)), dfs_bfv_helper,
DECL_CONTEXT (vars));
}