Commit 732dcb6f by Jason Merrill Committed by Jason Merrill

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
parent e9eaed43
Fri Apr 3 02:22:59 1998 Jason Merrill <jason@yorick.cygnus.com> 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. * decl.c (cplus_expand_expr_stmt): Strip unused INDIRECT_REFs.
Re-implement allocation of base class subobjects. Re-implement allocation of base class subobjects.
......
...@@ -3131,7 +3131,6 @@ finish_struct_1 (t, warn_anon) ...@@ -3131,7 +3131,6 @@ finish_struct_1 (t, warn_anon)
cant_have_const_ctor = base_info.cant_have_const_ctor; cant_have_const_ctor = base_info.cant_have_const_ctor;
no_const_asn_ref = base_info.no_const_asn_ref; no_const_asn_ref = base_info.no_const_asn_ref;
aggregate = 0; aggregate = 0;
empty = 0;
} }
else else
{ {
...@@ -3209,6 +3208,9 @@ finish_struct_1 (t, warn_anon) ...@@ -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; last_x = NULL_TREE;
for (x = fields; x; x = TREE_CHAIN (x)) for (x = fields; x; x = TREE_CHAIN (x))
{ {
...@@ -3757,9 +3759,6 @@ finish_struct_1 (t, warn_anon) ...@@ -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) if (vfield == NULL_TREE && has_virtual)
{ {
/* We build this decl with ptr_type_node, and /* We build this decl with ptr_type_node, and
...@@ -3852,21 +3851,33 @@ finish_struct_1 (t, warn_anon) ...@@ -3852,21 +3851,33 @@ finish_struct_1 (t, warn_anon)
TYPE_FIELDS (t) = fields; TYPE_FIELDS (t) = fields;
if (n_baseclasses) 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. */ /* C++: do not let empty structures exist. */
tree decl = build_lang_field_decl tree decl = build_lang_field_decl
(FIELD_DECL, NULL_TREE, char_type_node); (FIELD_DECL, NULL_TREE, char_type_node);
TREE_CHAIN (decl) = TYPE_FIELDS (t); TREE_CHAIN (decl) = fields;
TYPE_FIELDS (t) = decl; TYPE_FIELDS (t) = decl;
} }
if (n_baseclasses)
TYPE_FIELDS (t) = chainon (last_x, TYPE_FIELDS (t));
layout_type (t); layout_type (t);
/* Remember the size and alignment of the class before adding /* Remember the size and alignment of the class before adding
the virtual bases. */ 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); CLASSTYPE_ALIGN (t) = TYPE_ALIGN (t);
finish_struct_anon (t); finish_struct_anon (t);
......
...@@ -1914,6 +1914,10 @@ extern int flag_implicit_templates; ...@@ -1914,6 +1914,10 @@ extern int flag_implicit_templates;
extern int flag_weak; 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. */ /* Nonzero if we're done parsing and into end-of-file activities. */
extern int at_eof; extern int at_eof;
......
...@@ -401,6 +401,8 @@ int flag_new_for_scope = 1; ...@@ -401,6 +401,8 @@ int flag_new_for_scope = 1;
int flag_weak = 1; int flag_weak = 1;
int flag_new_abi = 1;
/* Maximum template instantiation depth. Must be at least 17 for ANSI /* Maximum template instantiation depth. Must be at least 17 for ANSI
compliance. */ compliance. */
...@@ -467,7 +469,8 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] = ...@@ -467,7 +469,8 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
{"check-new", &flag_check_new, 1}, {"check-new", &flag_check_new, 1},
{"repo", &flag_use_repository, 1}, {"repo", &flag_use_repository, 1},
{"for-scope", &flag_new_for_scope, 2}, {"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. /* Decode the string P as a language-specific option.
......
...@@ -67,6 +67,8 @@ Boston, MA 02111-1307, USA. */ ...@@ -67,6 +67,8 @@ Boston, MA 02111-1307, USA. */
"-fmemoize-lookups", "-fmemoize-lookups",
"-fno-memoize-lookups", "-fno-memoize-lookups",
"-fname-mangling-version-", "-fname-mangling-version-",
"-fnew-abi",
"-fno-new-abi",
"-fnonnull-objects", "-fnonnull-objects",
"-fno-nonnull-objects", "-fno-nonnull-objects",
"-foperator-names", "-foperator-names",
......
...@@ -3830,3 +3830,49 @@ get_template_base (template, binfo) ...@@ -3830,3 +3830,49 @@ get_template_base (template, binfo)
return rval; 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;
}
...@@ -750,6 +750,28 @@ layout_basetypes (rec, max) ...@@ -750,6 +750,28 @@ layout_basetypes (rec, max)
return 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 /* Returns a list of fields to stand in for the base class subobjects
of REC. These fields are later removed by layout_basetypes. */ of REC. These fields are later removed by layout_basetypes. */
...@@ -762,8 +784,8 @@ build_base_fields (rec) ...@@ -762,8 +784,8 @@ build_base_fields (rec)
tree base_decls = NULL_TREE; tree base_decls = NULL_TREE;
tree binfos = TYPE_BINFO_BASETYPES (rec); tree binfos = TYPE_BINFO_BASETYPES (rec);
int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0; int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree decl; tree decl, nextdecl;
int i; int i, saw_empty = 0;
unsigned int base_align = 0; unsigned int base_align = 0;
for (i = 0; i < n_baseclasses; ++i) for (i = 0; i < n_baseclasses; ++i)
...@@ -787,18 +809,54 @@ build_base_fields (rec) ...@@ -787,18 +809,54 @@ build_base_fields (rec)
TREE_CHAIN (decl) = base_decls; TREE_CHAIN (decl) = base_decls;
base_decls = decl; base_decls = decl;
/* Brain damage for backwards compatibility. For no good reason, the if (! flag_new_abi)
old layout_basetypes made every base at least as large as the {
alignment for the bases up to that point, gratuitously wasting /* Brain damage for backwards compatibility. For no good reason,
space. So we do the same thing here. */ the old layout_basetypes made every base at least as large as
base_align = MAX (base_align, DECL_ALIGN (decl)); the alignment for the bases up to that point, gratuitously
DECL_SIZE (decl) = size_int (MAX (TREE_INT_CST_LOW (DECL_SIZE (decl)), wasting space. So we do the same thing here. */
base_align)); 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 /* Reverse the list of fields so we allocate the bases in the proper
order. */ 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. */ /* Returns list of virtual base class pointers in a FIELD_DECL chain. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment