a new garbage collection pass less conservative than gc_irgs (but does not respect...
authorMatthias Braun <matze@braunis.de>
Fri, 5 Feb 2010 18:30:05 +0000 (18:30 +0000)
committerMatthias Braun <matze@braunis.de>
Fri, 5 Feb 2010 18:30:05 +0000 (18:30 +0000)
[r27056]

include/libfirm/iroptimize.h
ir/ana/cgana.c
ir/ir/irprog.c
ir/opt/garbage_collect.c [new file with mode: 0644]
ir/tr/trvrfy.c

index 4bfdfef..f374a3f 100644 (file)
@@ -908,4 +908,17 @@ typedef ir_type *(*get_Alloc_func)(ir_node *n);
 /** Set a new get_Alloc_func and returns the old one. */
 get_Alloc_func firm_set_Alloc_func(get_Alloc_func newf);
 
+/**
+ * Removes all entities which are unused.
+ *
+ * Unused entities have ir_visibility_local and are not used directly or
+ * indirectly through entities/code visible outside the compilation unit.
+ * This is usually conservative than gc_irgs, but does not respect properties
+ * of object-oriented programs.
+ */
+void garbage_collect_entities(void);
+
+/** Pass for garbage_collect_entities */
+ir_prog_pass_t *garbage_collect_entities_pass(const char *name);
+
 #endif
index 2fc3773..b42cc16 100644 (file)
@@ -586,8 +586,8 @@ static ir_entity **get_free_methods(int *length)
                add_method_address(ent, free_set);
        }
        tp = get_tls_type();
-       for (i = get_struct_n_members(tp) - 1; i >= 0; --i) {
-               ent = get_struct_member(tp, i);
+       for (i = get_class_n_members(tp) - 1; i >= 0; --i) {
+               ent = get_class_member(tp, i);
                add_method_address(ent, free_set);
        }
 
index 01636c0..852c6fe 100644 (file)
@@ -85,11 +85,11 @@ static ir_prog *complete_ir_prog(ir_prog *irp, const char *module_name)
        irp->name = new_id_from_str(module_name);
        irp->segment_types[IR_SEGMENT_GLOBAL] = new_type_class(IDENT("GlobalType"));
        irp->segment_types[IR_SEGMENT_THREAD_LOCAL]
-               = new_type_struct(IDENT("ThreadLocal"));
+               = new_type_class(IDENT("ThreadLocal"));
        irp->segment_types[IR_SEGMENT_CONSTRUCTORS]
-               = new_type_struct(IDENT("Constructors"));
+               = new_type_class(IDENT("Constructors"));
        irp->segment_types[IR_SEGMENT_DESTRUCTORS]
-               = new_type_struct(IDENT("Destructors"));
+               = new_type_class(IDENT("Destructors"));
        /* Remove these types from type list.  Must be treated differently than
           other types. */
        for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
diff --git a/ir/opt/garbage_collect.c b/ir/opt/garbage_collect.c
new file mode 100644 (file)
index 0000000..5e8c529
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2010 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief    Removal of unreachable methods.
+ * @author   Matthias Braun
+ * @version  $Id$
+ */
+#include "config.h"
+
+#include "iroptimize.h"
+#include "typerep.h"
+#include "type_t.h"
+#include "entity_t.h"
+#include "irprog_t.h"
+#include "irprintf.h"
+#include "irpass.h"
+#include "irgwalk.h"
+#include "error.h"
+#include "debug.h"
+
+DEBUG_ONLY(static firm_dbg_module_t *dbg);
+
+static void visit_entity(ir_entity *entity);
+
+static void visit_node(ir_node *node, void *env)
+{
+       ir_entity *entity;
+       (void) env;
+
+       if (!is_SymConst(node))
+               return;
+       if (!SYMCONST_HAS_ENT(get_SymConst_kind(node)))
+               return;
+
+       entity = get_SymConst_entity(node);
+       visit_entity(entity);
+}
+
+static void start_visit_node(ir_node *node)
+{
+       ir_graph *irg = get_irn_irg(node);
+
+       if (get_irg_visited(irg) < get_max_irg_visited()) {
+               set_irg_visited(irg, get_max_irg_visited());
+       }
+       current_ir_graph = irg;
+       irg_walk_2(node, visit_node, NULL, NULL);
+}
+
+static void visit_initializer(ir_initializer_t *initializer)
+{
+       switch (initializer->kind) {
+       case IR_INITIALIZER_CONST:
+               start_visit_node(initializer->consti.value);
+               return;
+       case IR_INITIALIZER_TARVAL:
+       case IR_INITIALIZER_NULL:
+               return;
+
+       case IR_INITIALIZER_COMPOUND: {
+               size_t i;
+               for(i = 0; i < initializer->compound.n_initializers; ++i) {
+                       ir_initializer_t *subinitializer
+                               = initializer->compound.initializers[i];
+                       visit_initializer(subinitializer);
+               }
+               return;
+       }
+       }
+       panic("invalid initializer found");
+}
+
+static void visit_entity(ir_entity *entity)
+{
+       ir_graph *irg;
+
+       if (entity_visited(entity))
+               return;
+       mark_entity_visited(entity);
+
+       if (entity->initializer != NULL) {
+               visit_initializer(entity->initializer);
+       }  else if (entity_has_compound_ent_values(entity)) {
+               int i;
+               int n_members = get_compound_ent_n_values(entity);
+               for (i = 0; i < n_members; ++i) {
+                       ir_node *node = get_compound_ent_value(entity, i);
+                       start_visit_node(node);
+               }
+       }
+
+       irg = get_entity_irg(entity);
+       if (irg != NULL) {
+               start_visit_node(get_irg_end(irg));
+       }
+}
+
+static void visit_segment(ir_type *segment)
+{
+       int n_entities = get_compound_n_members(segment);
+       int i;
+
+       for (i = 0; i < n_entities; ++i) {
+               ir_entity *entity = get_compound_member(segment, i);
+               if (get_entity_visibility(entity) != ir_visibility_default
+                               && !(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER))
+                       continue;
+
+               visit_entity(entity);
+       }
+}
+
+static void garbage_collect_in_segment(ir_type *segment)
+{
+       int i;
+
+       for (i = get_compound_n_members(segment)-1; i >= 0; --i) {
+               ir_entity *entity = get_compound_member(segment, i);
+
+               if (entity_visited(entity))
+                       continue;
+
+               DB((dbg, LEVEL_1, "  removing entity %+F\n", entity));
+
+               /* TODO: this is O(n^2) improve our interfaces! */
+               remove_class_member(get_entity_owner(entity), entity);
+       }
+}
+
+void garbage_collect_entities(void)
+{
+       int          i;
+       ir_segment_t s;
+
+       FIRM_DBG_REGISTER(dbg, "firm.opt.garbagecollect");
+
+       /* start a type walk for all externally visible entities */
+       irp_reserve_resources(irp, IR_RESOURCE_TYPE_VISITED);
+       inc_master_type_visited();
+       inc_max_irg_visited();
+
+       for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
+               ir_type *type = get_segment_type(s);
+               mark_type_visited(type);
+
+               visit_segment(type);
+       }
+
+       /* remove graphs of non-visited functions
+        * (we have to count backwards so we can safely call remove_irp_irg
+        *  while iterating) */
+       for (i = get_irp_n_irgs()-1; i >= 0; --i) {
+               ir_graph  *irg    = get_irp_irg(i);
+               ir_entity *entity = get_irg_entity(irg);
+
+               if (entity_visited(entity))
+                       continue;
+
+               DB((dbg, LEVEL_1, "  freeing method %+F\n",     entity));
+               remove_irp_irg(irg);
+       }
+
+       /* we can now remove all non-visited (global) entities */
+       for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
+               ir_type *type = get_segment_type(s);
+               garbage_collect_in_segment(type);
+       }
+       irp_free_resources(irp, IR_RESOURCE_TYPE_VISITED);
+}
+
+ir_prog_pass_t *garbage_collect_entities_pass(const char *name)
+{
+       return def_prog_pass(name ? name : "garbage_collect",
+                            garbage_collect_entities);
+}
index 8bf7569..504b32a 100644 (file)
@@ -412,9 +412,29 @@ static void check_tore(type_or_ent tore, void *env) {
 /*
  * Verify types and entities.
  */
-int tr_vrfy(void) {
-       int res;
+int tr_vrfy(void)
+{
+       int      res = no_error;
+       ir_type *constructors;
+       ir_type *destructors;
+       int      i;
 
        type_walk(check_tore, NULL, &res);
+
+       constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
+       for (i = get_compound_n_members(constructors)-1; i >= 0; --i) {
+               ir_entity *entity = get_compound_member(constructors, i);
+               ASSERT_AND_RET(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER,
+                              "entity without LINKAGE_HIDDEN_USER in constructors is pointless",
+                              1);
+       }
+       destructors = get_segment_type(IR_SEGMENT_DESTRUCTORS);
+       for (i = get_compound_n_members(destructors)-1; i >= 0; --i) {
+               ir_entity *entity = get_compound_member(destructors, i);
+               ASSERT_AND_RET(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER,
+                              "entity without LINKAGE_HIDDEN_USER in destructors is pointless",
+                              1);
+       }
+
        return res;
 }