Commit 11344bd0 authored by Matthias Braun's avatar Matthias Braun
Browse files

a new garbage collection pass less conservative than gc_irgs (but does not...

a new garbage collection pass less conservative than gc_irgs (but does not respect properties of object-oriented programs)

[r27056]
parent 2814a774
......@@ -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
......@@ -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);
}
......
......@@ -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) {
......
/*
* 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);
}
......@@ -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;
}
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