Add support for discarding unused virtual functions.
authorJason Merrill <jason@gcc.gnu.org>
Fri, 28 Aug 1998 16:11:35 +0000 (12:11 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 28 Aug 1998 16:11:35 +0000 (12:11 -0400)
* 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

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl2.c
gcc/cp/lang-options.h
gcc/cp/search.c

index 4cfc4c63f99e70170076d7f84aa8d5a6f6246046..dcf090b32e2c6cc6725042a3907e18c42121b34e 100644 (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
index da6c20ec9a28a228017327e23faa855e503093bc..dac59983d97ebbca44415a161d64d42724c3b47b 100644 (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;
index f7ce4f2714eb44367ffbfc2173a9338724b685ef..010959d0b06b29717d8a9a3d58a628a6eca65718 100644 (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;
 \f
 /* C++ language-specific tree codes.  */
 #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM,
index ebd942dbde92a5afb7dfd49f10e0b28ca81e26be..3e86fe6c6387dd45506fc86b19ca675fb2ad1282 100644 (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)))
index 25f642f1307c718dacc841f0dc71d06e3002e5b9..97ec99b38e78b88a7b365d8ba95e1640ae3eebaa 100644 (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" },
index fe028c28e9c45685f06f79736ef210f9392fce39..fa3109daac6c6d57e54f504b2cbaaf10a5775207 100644 (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));
+}