#include "rta.h"
#include <stdlib.h>
-#include "cgana.h" /* get_implementation */
#include "irnode_t.h"
#include "irprog.h"
#include "eset.h"
-/* #include "pmap.h" */
-/* #include "array.h" */
#include "irgwalk.h"
-/* #include "ircons.h" */
-/* #include "irgmod.h" */
-/* #include "irflag_t.h" */
-
-/* #include "dbginfo_t.h" */
+#include "irgmod.h"
+#include "irvrfy.h"
+#include "trvrfy.h"
# define TRUE 1
# define FALSE 0
static eset *_live_graphs = NULL;
static eset *_dead_graphs = NULL;
-/* now the meat */
-
+/**
+ Initialise the static data structures.
+*/
static void init_tables (void)
{
_live_classes = eset_create ();
}
/**
- Enter all method and field accesses and all class allocations into our tables.
+ Enter all method and field accesses and all class allocations into
+ our tables.
*/
static void rta_act (ir_node *node, void *env)
{
opcode op = get_irn_opcode (node);
- if (iro_Call == op) {
+ if (iro_Call == op) { /* CALL */
entity *ent = NULL;
ir_node *ptr = get_Call_ptr (node);
- if (iro_Sel == get_irn_opcode (ptr)) {
+ if (iro_Sel == get_irn_opcode (ptr)) { /* CALL SEL */
ent = get_Sel_entity (ptr);
- } else if (iro_Const == get_irn_opcode (ptr)) {
+ } else if (iro_Const == get_irn_opcode (ptr)) { /* CALL CONST */
ent = get_tarval_entity (get_Const_tarval (ptr));
- }
- /* assert (ent); */
+ } else if (iro_SymConst == get_irn_opcode (ptr)) { /* CALL SYMCONST */
+ assert (ent && "couldn't determine entity of call to symConst");
+ }
if (ent) {
eset_insert (_called_methods, ent);
}
- } else if (iro_Load == op) {
+ } else if (iro_Load == op) { /* LOAD */
ir_node *ptr = get_Load_ptr (node);
entity *ent = NULL;
if (ent) {
eset_insert (_live_fields, ent);
}
- } else if (iro_Store == op) {
+ } else if (iro_Store == op) { /* STORE */
ir_node *ptr = get_Store_ptr (node);
entity *ent = NULL;
if (ent) {
eset_insert (_live_fields, ent);
}
- } else if (iro_Alloc == op) {
+ } else if (iro_Alloc == op) { /* ALLOC */
type *type = get_Alloc_type (node);
eset_insert (_live_classes, type);
}
/**
-Traverse the given graph to collect method and field accesses and object allocations.
+ Traverse the given graph to collect method and field accesses and
+ object allocations.
*/
static void rta_fill_graph (ir_graph* graph)
{
if (NULL != graph) {
if (NULL != get_irg_end (graph)) {
current_ir_graph = graph;
+
irg_walk (get_irg_end (graph), rta_act, NULL, NULL);
}
}
}
+/**
+ Check whether the given graph is alive based on the contents of the
+ given esets.
+*/
static int is_alive (ir_graph *graph, eset *live_graphs, eset *dead_graphs)
{
if (eset_contains (live_graphs, graph)) {
return (FALSE);
}
- assert (0 && "what's up");
+ assert (0 && "graph neither live not dead (shouldn't happen)");
}
/**
eset *live_graphs = NULL;
eset *dead_graphs = NULL;
- interprocedural_view = 0;
+ interprocedural_view = 0; /* save this for later */
if (rerun) {
- int i;
int n_graphs = get_irp_n_irgs ();
/* force all graphs to be entered in either live_graphs or dead_graphs */
init_tables ();
}
- /* consider all graphs, possibly taking into account existing infos */
+ /* Consider all graphs, possibly taking into account existing infos */
for (i = 0; i < get_irp_n_irgs(); i++) {
ir_graph *graph = get_irp_irg (i);
- if (!rerun || is_alive (graph, live_graphs, dead_graphs)) {
+ /* Need to take care of graphs that are externally
+ visible. Pretend that they are called: */
+ entity *ent = get_irg_entity (graph);
+ if (visibility_local != get_entity_visibility (ent)) {
+ eset_insert (_called_methods, ent);
+
+ if (get_entity_irg (ent)) {
+ eset_insert (_live_graphs, get_entity_irg (ent));
+ }
+
+ eset_insert (_live_classes, get_entity_owner (ent));
+ }
+
+ /* now check the graph */
+ if (rerun) {
+ if (is_alive (graph, live_graphs, dead_graphs)) {
+ rta_fill_graph (graph);
+ } else {
+ /* nothing (except debugging printf's :-) */
+ }
+ } else {
rta_fill_graph (graph);
}
}
eset_destroy (dead_graphs);
}
- interprocedural_view = old_ip_view;
+ interprocedural_view = old_ip_view; /* cover up our traces */
}
/**
}
}
- assert (graph && "no graph");
+ /* we *must* always return a graph != NULL, *except* when we're used
+ inside remove_irg or force_description */
+ /* assert (graph && "no graph"); */
return (graph);
}
int i, n_over;
/* stop searching if a overwriting method comes with a new graph */
- if (get_irg_ent (graph) != method) {
+ if (get_irg_ent (graph) != method) { /* shouldn't we comare GRAPS????? */
return (FALSE);
}
int n_over;
type *clazz;
- /* const char *name = get_entity_name (method); */
-
/* stop searching when an overwriting method provides a new graph */
if (get_implementing_graph (method) != graph) {
return (FALSE);
return (has_class);
}
+/*
+ Count the number of graphs that we have found to be live. Since
+ this touches every graph of the irp, it also forces that each graph
+ is either in _live_graphs xor in _dead_graphs. This is useful if
+ we use is_alive(ir_graph*) internally.
+*/
static int stats (void)
{
int i;
return (n_live_graphs);
}
+/* remove a graph, part I */
+/*
+ We removed the first graph to implement the entity, so we're
+ abstract now. Pretend that it wasn't there at all, and every
+ entity that used to inherit this entity's graph is now abstract.
+*/
+/* Since we *know* that this entity will not be called, this is OK. */
+static void force_description (entity *ent, entity *addr)
+{
+ int i, n_over = get_entity_n_overwrittenby (ent);
+
+ set_entity_peculiarity (ent, peculiarity_description);
+
+ for (i = 0; i < n_over; i ++) {
+ entity *over = get_entity_overwrittenby (ent, i);
+
+ if (peculiarity_inherited == get_entity_peculiarity (over)) {
+ /* We rely on the fact that cse is performed on the const_code_irg. */
+ entity *my_addr =
+ tarval_to_entity(get_Const_tarval(get_atomic_ent_value(over)));
+
+ if (addr == my_addr) {
+ force_description (over, addr);
+ }
+ } else if (peculiarity_existent == get_entity_peculiarity (over)) {
+ /* check wether 'over' forces 'inheritance' of *our* graph: */
+ ir_node *f_addr = get_atomic_ent_value (over);
+ entity *impl_ent = tarval_to_entity (get_Const_tarval (f_addr));
+
+ assert ((get_irn_op(f_addr) == op_Const) && "can't do complex addrs");
+ if (impl_ent == addr) {
+ assert (0 && "gibt's denn sowas");
+ force_description (over, addr);
+ }
+ }
+ }
+}
+
+/* remove a graph, part II */
+/*
+ Note: get_implementing_graph is not well defined here (graph->ent
+ could overwrite more than one superclass implementation (graph).
+ Since we *know* that this entity will not be called, this is OK.
+*/
+static void remove_irg (ir_graph *graph)
+{
+ entity *ent = get_irg_entity (graph);
+
+ /* delete the ir_graph data */
+ remove_irp_irg (graph);
+ /* remove reference to the graph */
+ set_entity_irg (ent, NULL);
+ /* find the implementation (graph) from *some* superclass: */
+ graph = get_implementing_graph (ent);
+
+ if (TRUE || (NULL == graph)) { /* always pretend to be 'abstract'; let the others figure this out */
+ /* nothing to inherit! pretend we're abstract */
+ force_description (ent, ent);
+ } else {
+ /* pretend that we inherit the implementation (graph) from some superclass: */
+ set_entity_peculiarity (ent, peculiarity_inherited);
+
+ exchange (get_atomic_ent_value (ent),
+ get_atomic_ent_value (get_irg_ent(graph)));
+ }
+}
+
+/* Initialise the RTA data structures, and perform RTA.
+ @param verbose Iff != 0, print statistics as we go along
+*/
void rta_init (int verbose)
{
int n_live_graphs = get_irp_n_irgs ();
int n_graphs = 0;
int n_runs = 0;
+# ifdef DEBUG_libfirm
+ int i;
+ for (i = 0; i < get_irp_n_irgs(); i++) {
+ irg_vrfy (get_irp_irg(i));
+ }
+ tr_vrfy ();
+# endif /* defined DEBUG_libfirm */
+
init_tables ();
- printf ("RTA: run %i (%i graphs to go)\n", n_runs, n_live_graphs);
+ if (verbose) {
+ printf ("RTA: run %i (%i graphs to go)\n", n_runs, n_live_graphs);
+ }
+
rta_fill_all (FALSE);
while (n_graphs != n_live_graphs) {
n_runs ++;
rta_fill_all (TRUE);
n_live_graphs = stats ();
+
if (verbose) {
printf ("RTA: run %i (%i graphs to go)\n", n_runs, n_live_graphs);
}
printf ("RTA: n_live_graphs = %i\n", n_live_graphs);
printf ("RTA: n_runs = %i\n", n_runs);
}
+
+# ifdef DEBUG_libfirm
+ for (i = 0; i < get_irp_n_irgs(); i++) {
+ irg_vrfy (get_irp_irg(i));
+ }
+ tr_vrfy ();
+# endif /* defined DEBUG_libfirm */
+}
+
+/* Delete all graphs that we have found to be dead from the program */
+void rta_delete_dead_graphs ()
+{
+ int i;
+ int n_graphs = get_irp_n_irgs ();
+ ir_graph *graph = NULL;
+
+ eset *dead_graphs = eset_create ();
+
+ for (i = 0; i < n_graphs; i++) {
+ graph = get_irp_irg(i);
+
+ if (is_alive (graph, _live_graphs, _dead_graphs)) {
+ /* do nothing (except some debugging fprintf`s :-) */
+ } else {
+ entity *ent = get_irg_entity (graph);
+ assert (visibility_external_visible != get_entity_visibility (ent));
+
+ eset_insert (dead_graphs, graph);
+ }
+ }
+
+ /* now delete the graphs. */
+ for (graph = eset_first (dead_graphs);
+ graph;
+ graph = (ir_graph*) eset_next (dead_graphs)) {
+ remove_irg (graph);
+ }
}
-void rta_cleanup (void)
+/* Clean up the RTA data structures. Call this after calling rta_init */
+void rta_cleanup ()
{
+# ifdef DEBUG_libfirm
+ int i;
+ for (i = 0; i < get_irp_n_irgs(); i++) {
+ irg_vrfy (get_irp_irg(i));
+ }
+ tr_vrfy ();
+# endif /* defined DEBUG_libfirm */
+
if (_live_classes) {
eset_destroy (_live_classes);
_live_classes = NULL;
}
}
+/* Say wether this class might be instantiated at any point in the program: */
int rta_is_alive_class (type *clazz)
{
return (eset_contains (_live_classes, clazz));
}
+/* Say wether this graph might be run at any time in the program: */
int rta_is_alive_graph (ir_graph *graph)
{
- entity *meth;
-
if (eset_contains (_live_graphs, graph)) {
return (TRUE);
}
return (FALSE);
}
- meth = get_irg_ent (graph);
+ entity *meth = get_irg_ent (graph);
if (has_live_call (meth, graph) && has_live_class (meth, graph)) {
eset_insert (_live_graphs, graph);
}
}
+/* Say wether there have been any accesses to this field: */
int rta_is_alive_field (entity *field)
{
return (eset_contains (_live_fields, field));
/*
* $Log$
- * Revision 1.7 2004/06/15 11:44:54 beck
- * New inlining schema implemented:
- *
- * small functions that should be inlined in libFirm are implemented in _t.h files
- * with a __ prefix.
- * Preprocessor magic is used to automatically inline these functions whenever a _t.h
- * file is included instead of a .h file.
- * Note that this magic did not work outside libFirm without accessing _t.h files.
+ * Revision 1.8 2004/06/17 08:33:01 liekweg
+ * Added comments; added remove_irg
*
* Revision 1.6 2004/06/14 13:02:03 goetz
* bugfixesbug