Commit e18eba3e authored by Götz Lindenmaier's avatar Götz Lindenmaier
Browse files

moved stuff handling inheritance to an own file

Added algorithm to compute transitive closure of inheritance

[r5368]
parent 4842e339
......@@ -28,6 +28,7 @@
#include "firm_common_t.h"
#include "typegmod.h"
#include "irtypeinfo.h"
#include "tr_inheritance.h"
#include "callgraph.h"
#include "field_temperature.h"
......@@ -63,6 +64,7 @@ struct ir_prog {
irg_callee_info_state callee_info_state; /**< Validity of callee information.
Contains the lowest value or all irgs. */
ir_typeinfo_state typeinfo_state; /**< Validity of type information. */
inh_transitive_closure_state inh_trans_closure_state; /**< trans closure of inh relations. */
irp_callgraph_state callgraph_state; /**< State of the callgraph. */
struct ir_loop *outermost_cg_loop; /**< For callgraph analysis: entry point
......
......@@ -16,13 +16,13 @@ topdir = ../..
subdir := ir/tr
INSTALL_HEADERS = entity.h mangle.h tpop.h type.h typewalk.h type_or_entity.h \
typegmod.h trvrfy.h type_identify.h
typegmod.h trvrfy.h type_identify.h tr_inheritance.h
SOURCES = $(INSTALL_HEADERS)
SOURCES += Makefile.in \
entity.c entity_t.h mangle.c tpop.c tpop_t.h type.c type_t.h \
typewalk.c typegmod.c trvrfy.h trvrfy.c type_identify.c
typewalk.c typegmod.c trvrfy.h trvrfy.c type_identify.c tr_inheritance.c
include $(topdir)/MakeRules
......
......@@ -1285,44 +1285,3 @@ bool entity_not_visited(entity *ent) {
assert(ent && ent->kind == k_entity);
return get_entity_visited(ent) < type_visited;
}
/* Need two routines because I want to assert the result. */
static entity *resolve_ent_polymorphy2 (type *dynamic_class, entity *static_ent) {
int i, n_overwrittenby;
entity *res = NULL;
if (get_entity_owner(static_ent) == dynamic_class) return static_ent;
n_overwrittenby = get_entity_n_overwrittenby(static_ent);
for (i = 0; i < n_overwrittenby; ++i) {
res = resolve_ent_polymorphy2(dynamic_class, get_entity_overwrittenby(static_ent, i));
if (res)
break;
}
return res;
}
/** Resolve polymorphy in the inheritance relation.
*
* Returns the dynamically referenced entity if the static entity and the
* dynamic type are given.
* Search downwards in overwritten tree. */
entity *resolve_ent_polymorphy(type *dynamic_class, entity *static_ent) {
entity *res;
assert(static_ent && static_ent->kind == k_entity);
res = resolve_ent_polymorphy2(dynamic_class, static_ent);
#if DEBUG_libfirm
if (!res) {
printf(" Could not find entity "); DDME(static_ent);
printf(" in "); DDMT(dynamic_class);
printf("\n");
dump_entity(static_ent);
dump_type(get_entity_owner(static_ent));
dump_type(dynamic_class);
}
#endif
assert(res);
return res;
}
......@@ -49,13 +49,11 @@
* - int offset: Offset in bits for this entity. Fixed when layout
* of owner is determined.
* - ir_graph *irg: If (type == method_type) this is the corresponding irg.
* The ir_graph constructor automatically sets this field.
* The ir_graph constructor automatically sets this field.
* If (type != method_type) access of this field will cause
* an assertion.
*/
/* $Id$ */
# ifndef _ENTITY_H_
# define _ENTITY_H_
......@@ -63,6 +61,8 @@
# include "type.h"
# include "dbginfo.h"
# include "tr_inheritance.h"
/*-----------------------------------------------------------------*/
/* general */
/*-----------------------------------------------------------------*/
......@@ -517,7 +517,6 @@ int is_compound_entity(entity *ent);
*/
bool equal_entity(entity *ent1, entity *ent2);
/** Outputs a unique number for this entity if libfirm is compiled for
debugging, (configure with --enable-debug) else returns 0. */
long get_entity_nr(entity *ent);
......@@ -537,10 +536,6 @@ bool entity_visited(entity *ent);
/** Returns true if this entity was not visited. */
bool entity_not_visited(entity *ent);
/** Returns the dynamically referenced entity if the static entity and the
* dynamic type are given. */
entity *resolve_ent_polymorphy(type *dynamic_class, entity* static_ent);
/**
* @page unknown_entity
*
......
/**
*
* @file tp_inheritance.c
*
* Project: libFIRM <br>
* File name: ir/tr/tp_inheritance.c <br>
* Purpose: Utility routines for inheritance representation <br>
* Author: Goetz Lindenmaier <br>
* Modified by: <br>
* Created: <br>
* Copyright: (c) 2001-2005 Universität Karlsruhe <br>
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE. <br>
* CVS-ID: $Id$
*
*
*
* @see type.h entity.h
*/
#include "type.h"
#include "entity.h"
#include "typewalk.h"
#include "irprog_t.h"
#include "pset.h"
#include "set.h"
#include "mangle.h"
//#include ".h"
/* ----------------------------------------------------------------------- */
/* Resolve implicit inheritance. */
/* ----------------------------------------------------------------------- */
ident *default_mangle_inherited_name(entity *super, type *clss) {
return mangle_u(get_type_ident(clss), get_entity_ident(super));
}
/* Replicates all entities in all super classes that are not overwritten
by an entity of this class. */
static void copy_entities_from_superclass(type *clss, void *env)
{
int i, j, k, l;
int overwritten;
type *super, *inhenttype;
entity *inhent, *thisent;
mangle_inherited_name_func *mfunc = (mangle_inherited_name_func *)env;
for(i = 0; i < get_class_n_supertypes(clss); i++) {
super = get_class_supertype(clss, i);
assert(is_Class_type(super) && "not a class");
for(j = 0; j < get_class_n_members(super); j++) {
inhent = get_class_member(super, j);
inhenttype = get_entity_type(inhent);
/* check whether inhent is already overwritten */
overwritten = 0;
for (k = 0; (k < get_class_n_members(clss)) && (overwritten == 0); k++) {
thisent = get_class_member(clss, k);
for(l = 0; l < get_entity_n_overwrites(thisent); l++) {
if(inhent == get_entity_overwrites(thisent, l)) {
/* overwritten - do not copy */
overwritten = 1;
break;
}
}
}
/* Inherit entity */
if (!overwritten) {
thisent = copy_entity_own(inhent, clss);
add_entity_overwrites(thisent, inhent);
set_entity_peculiarity(thisent, peculiarity_inherited);
set_entity_ld_ident(thisent, mfunc(inhent, clss));
if (get_entity_variability(inhent) == variability_constant) {
assert(is_atomic_entity(inhent) && /* @@@ */
"Inheritance of constant, compound entities not implemented");
set_entity_variability(thisent, variability_constant);
set_atomic_ent_value(thisent, get_atomic_ent_value(inhent));
}
}
}
}
}
/* Resolve implicit inheritance.
*
* Resolves the implicit inheritance supplied by firm.
*/
void resolve_inheritance(mangle_inherited_name_func *mfunc) {
if (!mfunc)
mfunc = default_mangle_inherited_name;
class_walk_super2sub(copy_entities_from_superclass, NULL, (void *)mfunc);
}
/* ----------------------------------------------------------------------- */
/* The transitive closure of the subclass/superclass and */
/* overwrites/overwrittenby relation. */
/* */
/* A walk over the ir (O(#types+#entities)) computes the transitive */
/* closure. Adding a new type/entity or changing the basic relations in */
/* some other way invalidates the transitive closure, i.e., it is not */
/* updated by the basic functions. */
/* */
/* All functions are named as their counterparts for the basic relations, */
/* adding the infix 'trans_'. */
/* ----------------------------------------------------------------------- */
void set_irp_inh_transitive_closure_state(inh_transitive_closure_state s) {
irp->inh_trans_closure_state = s;
}
void invalidate_irp_inh_transitive_closure_state(void) {
if (irp->inh_trans_closure_state == inh_transitive_closure_valid)
irp->inh_trans_closure_state = inh_transitive_closure_invalid;
}
inh_transitive_closure_state get_irp_inh_transitive_closure_state(void) {
return irp->inh_trans_closure_state;
}
static void assert_valid_state(void) {
assert(irp->inh_trans_closure_state == inh_transitive_closure_valid ||
irp->inh_trans_closure_state == inh_transitive_closure_invalid);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* There is a set that extends each entity/type with two new */
/* fields: one for the upwards directed relation: 'up' (supertype, */
/* overwrites) and one for the downwards directed relation: 'down' (sub- */
/* type, overwrittenby. These fields contain psets (and maybe later */
/* arrays) listing all subtypes... */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef struct {
firm_kind *kind; /* An entity or type. */
pset *up;
pset *down;
} tr_inh_trans_tp;
/* We use this set for all types and entities. */
static set *tr_inh_trans_set = NULL;
static int tr_inh_trans_cmp(const void *e1, const void *e2, size_t size) {
tr_inh_trans_tp *ef1 = (tr_inh_trans_tp *)e1;
tr_inh_trans_tp *ef2 = (tr_inh_trans_tp *)e2;
return (ef1->kind != ef2->kind);
}
static INLINE unsigned int tr_inh_trans_hash(void *e) {
void *v = (void *) ((tr_inh_trans_tp *)e)->kind;
return HASH_PTR(v);
}
typedef enum {
d_up,
d_down,
} dir;
/* This always completes successfully. */
static tr_inh_trans_tp* get_firm_kind_entry(firm_kind *k) {
tr_inh_trans_tp a, *found;
a.kind = k;
if (!tr_inh_trans_set) tr_inh_trans_set = new_set(tr_inh_trans_cmp, 128);
found = set_find(tr_inh_trans_set, &a, sizeof(a), tr_inh_trans_hash(&a));
if (!found) {
a.up = pset_new_ptr(16);
a.down = pset_new_ptr(16);
found = set_insert(tr_inh_trans_set, &a, sizeof(a), tr_inh_trans_hash(&a));
}
return found;
}
static pset *get_entity_map(entity *ent, dir d) {
assert(is_entity(ent));
tr_inh_trans_tp *found = get_firm_kind_entry((firm_kind *)ent);
if (d == d_up) return found->up;
else return found->down;
}
/*
static void add_entity_map(entity *ent, dir d, entity *new) {
assert(is_entity(ent) && is_entity(new));
tr_inh_trans_tp *found = get_firm_kind_entry((firm_kind *)ent);
if (d == d_up) pset_insert_ptr(found->up, new);
else pset_insert_ptr(found->down, new);
}
*/
static pset *get_type_map(type *tp, dir d) {
assert(is_type(tp));
tr_inh_trans_tp *found = get_firm_kind_entry((firm_kind *)tp);
if (d == d_up) return found->up;
else return found->down;
}
/*
static void add_type_map(type *tp, dir d, type *new) {
assert(is_type(tp) && is_type(new));
tr_inh_trans_tp *found = get_firm_kind_entry((firm_kind *)tp);
if (d == d_up) pset_insert_ptr(found->up, new);
else pset_insert_ptr(found->down, new);
}
*/
/* Walk over all types reachable from tp in the sub/supertype
* retlation and compute the closure for the two downwards directed
* relations.
*
* The walk in the dag formed by the relation is tricky: We must visit
* all subtypes before visiting the supertypes. So we first walk down.
* Then we can compute the closure for this type. Then we walk up.
* As we call ourselves recursive, and walk in both directions, there
* can be cycles. So we have to make sure, that if we visit a node
* a second time (in a walk up) we do nothing. For this we increment
* the master visited flag twice.
* If the type is marked with master_flag_visited-1 it is on the stack.
* If it is marked with master_flag_visited it is fully processed.
*
* Well, we still miss some candidates ... */
static void compute_down_closure(type *tp) {
pset *myset, *subset;
int i, n_subtypes, n_members, n_supertypes;
int master_visited = get_master_type_visited();
assert(is_Class_type(tp));
set_type_visited(tp, master_visited-1);
/* Recursive descend. */
n_subtypes = get_class_n_subtypes(tp);
for (i = 0; i < n_subtypes; ++i) {
type *stp = get_class_subtype(tp, i);
if (type_not_visited(stp)) {
assert(get_type_visited(tp) < master_visited-1);
compute_down_closure(stp);
}
}
/* types */
myset = get_type_map(tp, d_down);
for (i = 0; i < n_subtypes; ++i) {
type *stp = get_class_subtype(tp, i);
subset = get_type_map(stp, d_down);
pset_insert_ptr(myset, stp);
pset_insert_pset_ptr(myset, subset);
}
/* entities */
n_members = get_class_n_members(tp);
for (i = 0; i < n_members; ++i) {
entity *mem = get_class_member(tp, i);
int j, n_overwrittenby = get_entity_n_overwrittenby(mem);
myset = get_entity_map(mem, d_down);
for (j = 0; j > n_overwrittenby; ++j) {
entity *ov = get_entity_overwrittenby(mem, j);
subset = get_entity_map(ov, d_down);
pset_insert_pset_ptr(myset, subset);
pset_insert_ptr(myset, ov);
}
}
mark_type_visited(tp);
/* Walk up. */
n_supertypes = get_class_n_supertypes(tp);
for (i = 0; i < n_supertypes; ++i) {
type *stp = get_class_supertype(tp, i);
if (get_type_visited(tp) < master_visited-1) {
compute_down_closure(stp);
}
}
}
static void compute_up_closure(type *tp) {
pset *myset, *subset;
int i, n_subtypes, n_members, n_supertypes;
int master_visited = get_master_type_visited();
assert(is_Class_type(tp));
set_type_visited(tp, master_visited-1);
/* Recursive descend. */
n_supertypes = get_class_n_supertypes(tp);
for (i = 0; i < n_supertypes; ++i) {
type *stp = get_class_supertype(tp, i);
if (type_not_visited(stp)) {
assert(get_type_visited(tp) < get_master_type_visited()-1);
compute_up_closure(stp);
}
}
/* types */
myset = get_type_map(tp, d_up);
for (i = 0; i < n_supertypes; ++i) {
type *stp = get_class_supertype(tp, i);
subset = get_type_map(stp, d_up);
pset_insert_ptr(myset, stp);
pset_insert_pset_ptr(myset, subset);
}
/* entities */
n_members = get_class_n_members(tp);
for (i = 0; i < n_members; ++i) {
entity *mem = get_class_member(tp, i);
int j, n_overwrites = get_entity_n_overwrites(mem);
myset = get_entity_map(mem, d_up);
for (j = 0; j > n_overwrites; ++j) {
entity *ov = get_entity_overwrites(mem, j);
subset = get_entity_map(ov, d_up);
pset_insert_pset_ptr(myset, subset);
pset_insert_ptr(myset, ov);
}
}
mark_type_visited(tp);
/* Walk down. */
n_subtypes = get_class_n_subtypes(tp);
for (i = 0; i < n_subtypes; ++i) {
type *stp = get_class_subtype(tp, i);
if (get_type_visited(tp) < master_visited-1) {
compute_up_closure(stp);
}
}
}
/** Compute the transitive closure of the subclass/superclass and
* overwrites/overwrittenby relation.
*
* This function walks over the ir (O(#types+#entities)) to compute the
* transitive closure. */
void compute_inh_transitive_closure(void) {
int i, n_types = get_irp_n_types();
free_inh_transitive_closure();
/* The 'down' relation */
inc_master_type_visited(); /* Inc twice: one if on stack, second if values computed. */
inc_master_type_visited();
for (i = 0; i < n_types; ++i) {
type *tp = get_irp_type(i);
if (is_Class_type(tp) && type_not_visited(tp)) { /* For others there is nothing to accumulate. */
assert(get_type_visited(tp) < get_master_type_visited()-1);
int j, n_subtypes = get_class_n_subtypes(tp);
int has_unmarked_subtype = false;
for (j = 0; j < n_subtypes && !has_unmarked_subtype; ++j) {
type *stp = get_class_subtype(tp, j);
if (type_not_visited(stp)) has_unmarked_subtype = true;
}
/* This is a good starting point. */
if (!has_unmarked_subtype)
compute_down_closure(tp);
}
}
/* The 'up' relation */
inc_master_type_visited();
inc_master_type_visited();
for (i = 0; i < n_types; ++i) {
type *tp = get_irp_type(i);
if (is_Class_type(tp) && type_not_visited(tp)) { /* For others there is nothing to accumulate. */
assert(get_type_visited(tp) < get_master_type_visited()-1);
int j, n_supertypes = get_class_n_supertypes(tp);
int has_unmarked_supertype = false;
for (j = 0; j < n_supertypes && !has_unmarked_supertype; ++j) {
type *stp = get_class_supertype(tp, j);
if (type_not_visited(stp)) has_unmarked_supertype = true;
}
/* This is a good starting point. */
if (!has_unmarked_supertype)
compute_up_closure(tp);
}
}
irp->inh_trans_closure_state = inh_transitive_closure_valid;
}
/** Free memory occupied by the transitive closure information. */
void free_inh_transitive_closure(void) {
if (tr_inh_trans_set) {
tr_inh_trans_tp *elt;
for (elt = set_first(tr_inh_trans_set); elt; elt = set_next(tr_inh_trans_set)) {
del_pset(elt->up);
del_pset(elt->down);
}
del_set(tr_inh_trans_set);
tr_inh_trans_set = NULL;
}
irp->inh_trans_closure_state = inh_transitive_closure_none;
}
/* - subtype ------------------------------------------------------------- */
type *get_class_trans_subtype_first(type *tp) {
assert_valid_state();
return pset_first(get_type_map(tp, d_down));
}
type *get_class_trans_subtype_next (type *tp) {
assert_valid_state();
return pset_next(get_type_map(tp, d_down));
}
/* - supertype ----------------------------------------------------------- */
type *get_class_trans_supertype_first(type *tp) {
assert_valid_state();
return pset_first(get_type_map(tp, d_up));
}
type *get_class_trans_supertype_next (type *tp) {
assert_valid_state();
return pset_next(get_type_map(tp, d_up));
}
/* - overwrittenby ------------------------------------------------------- */
entity *get_entity_trans_overwrittenby_first(entity *ent) {
assert_valid_state();
return pset_first(get_entity_map(ent, d_down));
}
entity *get_entity_trans_overwrittenby_next (entity *ent) {
assert_valid_state();
return pset_next(get_entity_map(ent, d_down));
}
/* - overwrites ---------------------------------------------------------- */
/** Iterate over all transitive overwritten entities. */
entity *get_entity_trans_overwrites_first(entity *ent) {
assert_valid_state();
return pset_first(get_entity_map(ent, d_up));
}
entity *get_entity_trans_overwrites_next (entity *ent) {
assert_valid_state();
return pset_next(get_entity_map(ent, d_up));
}
/* ----------------------------------------------------------------------- */
/* Classify pairs of types/entities in the inheritance relations. */
/* ----------------------------------------------------------------------- */
/* Returns true if low is subclass of high. */
int is_subclass_of(type *low, type *high) {
int i, n_subtypes;
assert(is_Class_type(low) && is_Class_type(high));
if (low == high) return 1;
if (get_irp_inh_transitive_closure_state() == inh_transitive_closure_valid) {
pset *m = get_type_map(high, d_down);
if (pset_find_ptr(m, low)) return 1;
else return 0;
}
/* depth first search from high downwards. */
n_subtypes = get_class_n_subtypes(high);
for (i = 0; i < n_subtypes; i++) {
type *stp = get_class_subtype(high, i);
if (low == stp) return 1;
if (is_subclass_of(low, stp))
return 1;
}
return 0;
}
int is_overwritten_by(entity *high, entity *low) {
int i, n_overwrittenby;
assert(is_entity(low) && is_entity(high));
if (get_irp_inh_transitive_closure_state() == inh_transitive_closure_valid) {
pset *m = get_entity_map(high, d_down);
if (pset_find_ptr(m, low)) return 1;
else return 0;
}
/* depth first search from high downwards. */
n_overwrittenby = get_entity_n_overwrittenby(high);
for (i = 0; i < n_overwrittenby; i++) {
entity *ov = get_entity_overwrittenby(high, i);
if (low == ov) return 1;
if (is_overwritten_by(low, ov))
return 1;
}
return 0;
}
/* Need two routines because I want to assert the result. */
static entity *resolve_ent_polymorphy2 (type *dynamic_class, entity *static_ent) {
int i, n_overwrittenby;
entity *res = NULL;