From: Matthias Braun Date: Fri, 5 Feb 2010 18:30:05 +0000 (+0000) Subject: a new garbage collection pass less conservative than gc_irgs (but does not respect... X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=11344bd09b754d61bd636a2358c82700aefa9314;p=libfirm a new garbage collection pass less conservative than gc_irgs (but does not respect properties of object-oriented programs) [r27056] --- diff --git a/include/libfirm/iroptimize.h b/include/libfirm/iroptimize.h index 4bfdfefee..f374a3ffa 100644 --- a/include/libfirm/iroptimize.h +++ b/include/libfirm/iroptimize.h @@ -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 diff --git a/ir/ana/cgana.c b/ir/ana/cgana.c index 2fc377359..b42cc1663 100644 --- a/ir/ana/cgana.c +++ b/ir/ana/cgana.c @@ -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); } diff --git a/ir/ir/irprog.c b/ir/ir/irprog.c index 01636c0f3..852c6fe6e 100644 --- a/ir/ir/irprog.c +++ b/ir/ir/irprog.c @@ -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 index 000000000..5e8c529b7 --- /dev/null +++ b/ir/opt/garbage_collect.c @@ -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); +} diff --git a/ir/tr/trvrfy.c b/ir/tr/trvrfy.c index 8bf75694c..504b32a5f 100644 --- a/ir/tr/trvrfy.c +++ b/ir/tr/trvrfy.c @@ -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; }