Implement empty base optimization.

* class.c (finish_struct_1): Add vbase fields earlier.  Set
	CLASSTYPE_SIZE of an empty base to 0.  Types with bases can be empty.
	* search.c (dfs_check_overlap, dfs_no_overlap_yet): New fns.
	(types_overlap_p): New fn.
	* tree.c (avoid_overlap): New fn.
	(build_base_fields): Use it to avoid overlapping empty bases.
	* cp-tree.h, decl2.c, lang-options.h: Add -fnew-abi.

From-SVN: r18978
This commit is contained in:
Jason Merrill 1998-04-03 14:13:24 +00:00 committed by Jason Merrill
parent e9eaed43b9
commit 732dcb6f2a
7 changed files with 152 additions and 19 deletions

View file

@ -1,5 +1,14 @@
Fri Apr 3 02:22:59 1998 Jason Merrill <jason@yorick.cygnus.com>
Implement empty base optimization.
* class.c (finish_struct_1): Add vbase fields earlier. Set
CLASSTYPE_SIZE of an empty base to 0. Types with bases can be empty.
* search.c (dfs_check_overlap, dfs_no_overlap_yet): New fns.
(types_overlap_p): New fn.
* tree.c (avoid_overlap): New fn.
(build_base_fields): Use it to avoid overlapping empty bases.
* cp-tree.h, decl2.c, lang-options.h: Add -fnew-abi.
* decl.c (cplus_expand_expr_stmt): Strip unused INDIRECT_REFs.
Re-implement allocation of base class subobjects.

View file

@ -3131,7 +3131,6 @@ finish_struct_1 (t, warn_anon)
cant_have_const_ctor = base_info.cant_have_const_ctor;
no_const_asn_ref = base_info.no_const_asn_ref;
aggregate = 0;
empty = 0;
}
else
{
@ -3209,6 +3208,9 @@ finish_struct_1 (t, warn_anon)
}
}
if (n_baseclasses)
fields = chainon (build_vbase_pointer_fields (t), fields);
last_x = NULL_TREE;
for (x = fields; x; x = TREE_CHAIN (x))
{
@ -3757,9 +3759,6 @@ finish_struct_1 (t, warn_anon)
}
if (n_baseclasses)
fields = chainon (build_vbase_pointer_fields (t), fields);
if (vfield == NULL_TREE && has_virtual)
{
/* We build this decl with ptr_type_node, and
@ -3852,21 +3851,33 @@ finish_struct_1 (t, warn_anon)
TYPE_FIELDS (t) = fields;
if (n_baseclasses)
TYPE_FIELDS (t) = chainon (build_base_fields (t), fields);
else if (empty)
{
last_x = build_base_fields (t);
/* If all our bases are empty, we can be empty too. */
for (x = last_x; empty && x; x = TREE_CHAIN (x))
if (DECL_SIZE (x) != integer_zero_node)
empty = 0;
}
if (empty)
{
/* C++: do not let empty structures exist. */
tree decl = build_lang_field_decl
(FIELD_DECL, NULL_TREE, char_type_node);
TREE_CHAIN (decl) = TYPE_FIELDS (t);
TREE_CHAIN (decl) = fields;
TYPE_FIELDS (t) = decl;
}
if (n_baseclasses)
TYPE_FIELDS (t) = chainon (last_x, TYPE_FIELDS (t));
layout_type (t);
/* Remember the size and alignment of the class before adding
the virtual bases. */
CLASSTYPE_SIZE (t) = TYPE_SIZE (t);
if (empty && flag_new_abi)
CLASSTYPE_SIZE (t) = integer_zero_node;
else
CLASSTYPE_SIZE (t) = TYPE_SIZE (t);
CLASSTYPE_ALIGN (t) = TYPE_ALIGN (t);
finish_struct_anon (t);

View file

@ -1914,6 +1914,10 @@ extern int flag_implicit_templates;
extern int flag_weak;
/* Nonzero to enable experimental ABI changes. */
extern int flag_new_abi;
/* Nonzero if we're done parsing and into end-of-file activities. */
extern int at_eof;

View file

@ -401,6 +401,8 @@ int flag_new_for_scope = 1;
int flag_weak = 1;
int flag_new_abi = 1;
/* Maximum template instantiation depth. Must be at least 17 for ANSI
compliance. */
@ -467,7 +469,8 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
{"check-new", &flag_check_new, 1},
{"repo", &flag_use_repository, 1},
{"for-scope", &flag_new_for_scope, 2},
{"weak", &flag_weak, 1}
{"weak", &flag_weak, 1},
{"new-abi", &flag_new_abi, 1}
};
/* Decode the string P as a language-specific option.

View file

@ -67,6 +67,8 @@ Boston, MA 02111-1307, USA. */
"-fmemoize-lookups",
"-fno-memoize-lookups",
"-fname-mangling-version-",
"-fnew-abi",
"-fno-new-abi",
"-fnonnull-objects",
"-fno-nonnull-objects",
"-foperator-names",

View file

@ -3830,3 +3830,49 @@ get_template_base (template, binfo)
return rval;
}
/* Check whether the empty class indicated by EMPTY_BINFO is also present
at offset 0 in COMPARE_TYPE, and set found_overlap if so. */
static tree compare_type;
static int found_overlap;
static void
dfs_check_overlap (empty_binfo)
tree empty_binfo;
{
tree binfo;
for (binfo = TYPE_BINFO (compare_type); ; binfo = BINFO_BASETYPE (binfo, 0))
{
if (BINFO_TYPE (binfo) == BINFO_TYPE (empty_binfo))
{
found_overlap = 1;
break;
}
else if (BINFO_BASETYPES (binfo) == NULL_TREE)
break;
}
}
/* Trivial function to stop base traversal when we find something. */
static int
dfs_no_overlap_yet (t)
tree t;
{
return found_overlap == 0;
}
/* Returns nonzero if EMPTY_TYPE or any of its bases can also be found at
offset 0 in NEXT_TYPE. Used in laying out empty base class subobjects. */
int
types_overlap_p (empty_type, next_type)
tree empty_type, next_type;
{
if (! IS_AGGR_TYPE (next_type))
return 0;
compare_type = next_type;
found_overlap = 0;
dfs_walk (TYPE_BINFO (empty_type), dfs_check_overlap, dfs_no_overlap_yet);
return found_overlap;
}

View file

@ -750,6 +750,28 @@ layout_basetypes (rec, max)
return max;
}
/* If the empty base field in DECL overlaps with a base of the same type in
NEWDECL, which is either another base field or the first data field of
the class, pad the base just before NEWDECL and return 1. Otherwise,
return 0. */
static int
avoid_overlap (decl, newdecl)
tree decl, newdecl;
{
tree field;
if (newdecl == NULL_TREE
|| ! types_overlap_p (TREE_TYPE (decl), TREE_TYPE (newdecl)))
return 0;
for (field = decl; TREE_CHAIN (field) && TREE_CHAIN (field) != newdecl;
field = TREE_CHAIN (field))
;
DECL_SIZE (field) = integer_one_node;
}
/* Returns a list of fields to stand in for the base class subobjects
of REC. These fields are later removed by layout_basetypes. */
@ -762,8 +784,8 @@ build_base_fields (rec)
tree base_decls = NULL_TREE;
tree binfos = TYPE_BINFO_BASETYPES (rec);
int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree decl;
int i;
tree decl, nextdecl;
int i, saw_empty = 0;
unsigned int base_align = 0;
for (i = 0; i < n_baseclasses; ++i)
@ -787,18 +809,54 @@ build_base_fields (rec)
TREE_CHAIN (decl) = base_decls;
base_decls = decl;
/* Brain damage for backwards compatibility. For no good reason, the
old layout_basetypes made every base at least as large as the
alignment for the bases up to that point, gratuitously wasting
space. So we do the same thing here. */
base_align = MAX (base_align, DECL_ALIGN (decl));
DECL_SIZE (decl) = size_int (MAX (TREE_INT_CST_LOW (DECL_SIZE (decl)),
base_align));
if (! flag_new_abi)
{
/* Brain damage for backwards compatibility. For no good reason,
the old layout_basetypes made every base at least as large as
the alignment for the bases up to that point, gratuitously
wasting space. So we do the same thing here. */
base_align = MAX (base_align, DECL_ALIGN (decl));
DECL_SIZE (decl)
= size_int (MAX (TREE_INT_CST_LOW (DECL_SIZE (decl)),
base_align));
}
else if (DECL_SIZE (decl) == integer_zero_node)
saw_empty = 1;
}
/* Reverse the list of fields so we allocate the bases in the proper
order. */
return nreverse (base_decls);
base_decls = nreverse (base_decls);
/* In the presence of empty base classes, we run the risk of allocating
two objects of the same class on top of one another. Avoid that. */
if (flag_new_abi && saw_empty)
for (decl = base_decls; decl; decl = TREE_CHAIN (decl))
{
if (DECL_SIZE (decl) == integer_zero_node)
{
/* First step through the following bases until we find
an overlap or a non-empty base. */
for (nextdecl = TREE_CHAIN (decl); nextdecl;
nextdecl = TREE_CHAIN (nextdecl))
{
if (avoid_overlap (decl, nextdecl)
|| DECL_SIZE (nextdecl) != integer_zero_node)
goto nextbase;
}
/* If we're still looking, also check against the first
field. */
for (nextdecl = TYPE_FIELDS (rec);
nextdecl && TREE_CODE (nextdecl) != FIELD_DECL;
nextdecl = TREE_CHAIN (nextdecl))
/* keep looking */;
avoid_overlap (decl, nextdecl);
}
nextbase:;
}
return base_decls;
}
/* Returns list of virtual base class pointers in a FIELD_DECL chain. */