bugfix
authorGötz Lindenmaier <goetz@ipd.info.uni-karlsruhe.de>
Thu, 10 Mar 2005 10:07:40 +0000 (10:07 +0000)
committerGötz Lindenmaier <goetz@ipd.info.uni-karlsruhe.de>
Thu, 10 Mar 2005 10:07:40 +0000 (10:07 +0000)
[r5339]

ir/ana/cgana.c
ir/ana/cgana.h
ir/opt/ldstopt.c

index d776fe3..f3d7675 100644 (file)
  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
  */
 
-/**
- * @file cgana.c
- * Intraprozedurale Analyse zur Abschätzung der Aufrufrelation. Es
- * wird eine Menge von freien Methoden und anschließend die an den
- * Call-Operationen aufrufbaren Methoden bestimmt.
+/** @file cgana.c
+ *
+ * Interprocedural analysis to estimate the calling relation.
  *
+ * This analysis computes all entities representing methods that
+ * can be called at a Call node.  Further it computes a set of
+ * methods that are 'free', i.e., their adress is handled by
+ * the program directly, or they are visible external.
  */
+
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
@@ -35,6 +38,7 @@
 #include "irgwalk.h"
 #include "ircons.h"
 #include "irgmod.h"
+#include "iropt.h"
 
 #include "irflag_t.h"
 #include "dbginfo_t.h"
 
 #include "irhooks.h"
 
-/* Eindeutige Adresse zur Markierung von besuchten Knoten und zur
- * Darstellung der unbekannten Methode. */
-static void * MARK = &MARK;
-
 
 
-/* --- sel methods ---------------------------------------------------------- */
+/* Eindeutige Adresse zur Markierung von besuchten Knoten und zur
+ * Darstellung der unbekannten Methode. */
+static void *MARK = &MARK;
 
+static eset *entities = NULL;
 
-static eset * entities = NULL;
+/*--------------------------------------------------------------------------*/
+/* The analysis                                                             */
+/*--------------------------------------------------------------------------*/
 
 
-/** Bestimmt die eindeutige Methode, die die Methode für den
- *  übergebenen (dynamischen) Typ überschreibt. */
-static entity * get_implementation(type * class, entity * method) {
-  int i;
-  if (get_entity_peculiarity(method) != peculiarity_description &&
-      get_entity_owner(method) == class) {
-    return method;
-  }
-  for (i = get_entity_n_overwrittenby(method) - 1; i >= 0; --i) {
-    entity * e = get_entity_overwrittenby(method, i);
-    if (get_entity_peculiarity(e) != peculiarity_description && get_entity_owner(e) == class) {
-      return e;
-    }
-  }
-  for (i = get_class_n_supertypes(class) - 1; i >= 0; --i) {
-    entity * e = get_implementation(get_class_supertype(class, i), method);
-    if (e) {
-      return e;
-    }
-  }
-  assert(0 && "implementation not found");
-  return NULL;
-}
+/*--------------------------------------------------------------------------*/
+/* Initialize datastructures, remove unwanted constructs, optimize          */
+/* call target computations.                                                */
+/*--------------------------------------------------------------------------*/
 
 /** Returns the entity that contains the implementation of the inherited
     entity if available, else returns the entity passed. */
@@ -93,35 +79,8 @@ static entity *get_inherited_methods_implementation(entity *inh_meth) {
         "Complex constant values not supported -- address of method should be straight constant!");
 
   return get_SymConst_entity(get_atomic_ent_value(inh_meth));
-
-#if 0  // this stuff is outdated, I think. GL 10.11.04
-  entity *impl_meth = NULL;
-  ir_node *addr = get_atomic_ent_value(inh_meth);
-
-  assert(get_atomic_ent_value(inh_meth) && "constant entity without value");
-
-  if ((get_irn_op(addr) == op_SymConst) &&
-      (get_SymConst_kind(addr) == symconst_addr_ent)) {
-    impl_meth = get_SymConst_entity(addr);
-  } else {
-    assert(0 && "Complex constant values not supported -- address of method should be straight constant!");
-  }
-
-  if (impl_meth && (get_entity_peculiarity(impl_meth) != peculiarity_existent)) {
-    /*
-      printf("this_meth: "); DDMEO(inh_meth);
-      printf("impl meth: "); DDMEO(impl_meth);
-      assert(!impl_meth || get_entity_peculiarity(impl_meth) == peculiarity_existent);
-    */
-    assert(0);
-    impl_meth = NULL;
-  }
-  assert((impl_meth || inh_meth) && "no implementation for inherited entity");
-  return impl_meth? impl_meth : inh_meth;
-#endif
 }
 
-
 /** Collect the entity representing the implementation of this
  *  entity (not the same if inherited) and all entities for overwriting
  *  implementations in "set".
@@ -139,36 +98,6 @@ static void collect_impls(entity *method, eset *set, int *size, bool *open) {
   int i;
   entity *impl;
 
-#if 0
-  if (get_entity_peculiarity(method) == peculiarity_existent) {
-    if ((get_entity_visibility(method) == visibility_external_allocated)
-       && (NULL == get_entity_irg(method))) {
-      /* We could also add these entities to the callees, but right now we
-        subsume them by unknown_entity. */
-      *open = true;
-    } else {
-      assert(get_entity_irg(method) != NULL);
-      if (!eset_contains(set, method)) {
-        eset_insert(set, method);
-        ++(*size);
-      }
-    }
-  }
-
-  if (get_entity_peculiarity(method) == peculiarity_inherited) {
-    entity *impl_ent = get_inherited_methods_implementation(method);
-    if (get_entity_visibility(impl_ent) == visibility_external_allocated) {
-      assert(get_entity_irg(impl_ent) == NULL);
-      *open = true;
-    } else {
-      assert(get_entity_irg(impl_ent) != NULL);
-      if (!eset_contains(set, impl_ent)) {
-        eset_insert(set, impl_ent);
-        ++(*size);
-      }
-    }
-  }
-#endif
   /* Only the assertions: */
   if (get_entity_peculiarity(method) == peculiarity_existent) {
     if ((get_entity_visibility(method) == visibility_external_allocated)
@@ -215,7 +144,6 @@ static void collect_impls(entity *method, eset *set, int *size, bool *open) {
     collect_impls(get_entity_overwrittenby(method, i), set, size, open);
 }
 
-
 /** Alle Methoden bestimmen, die die übergebene Methode überschreiben
  *  (und implementieren). In der zurückgegebenen Reihung kommt jede
  *  Methode nur einmal vor. Der Wert 'NULL' steht für unbekannte
@@ -257,11 +185,18 @@ static entity ** get_impl_methods(entity * method) {
 
 /** Analyze address computations.
  *
+ *  Compute for all Sel nodes the set of methods that can be selected.
+ *
+ *  Further do some optimizations:
+ *  - Call standard optimizations for Sel nodes: this removes polymorphic
+ *    calls.
  *  - If the node is a SymConst(name) replace it by SymConst(ent) if possible.
+ *    For this we precomputed a map name->entity.
  *  - If the node is a Sel:
- *    * If the pointer to the Sel comes directly from an Alloc node
- *      replace the Sel by a SymConst(ent).
- *
+ *     If we found only a single method that can be called, replace the Sel
+ *     by a SymConst.  This is more powerful than the analysis in opt_polymorphy,
+ *     as here we walk the typegraph.  In opt_polymorphy we only apply a local
+ *     pattern.
  *
  *  @param node The node to analyze
  *  @param env  A map that maps names of entities to the entities.
@@ -269,118 +204,97 @@ static entity ** get_impl_methods(entity * method) {
 static void sel_methods_walker(ir_node * node, void *env) {
   pmap *ldname_map = env;
 
+  if (get_irn_op(node) == op_Sel) {
+    ir_node *new_node = optimize_in_place(node);
+    if (node != new_node) exchange(node, new_node);
+  }
+
   /* replace SymConst(name)-operations by SymConst(ent) */
   if (get_irn_op(node) == op_SymConst) {
     if (get_SymConst_kind(node) == symconst_addr_name) {
       pmap_entry * entry = pmap_find(ldname_map, (void *) get_SymConst_name(node));
       if (entry != NULL) { /* Method is declared in the compiled code */
-           entity * ent = entry->value;
-           if (get_opt_normalize() && (get_entity_visibility(ent) != visibility_external_allocated)) { /* Meth. is defined */
+       assert(0 && "There should not be a SymConst[addr_name] addressing a method with an implementation"
+              "in this compilation unit.  Use a SymConst[addr_ent].");
+#if 0
+       entity * ent = entry->value;
+       if (get_opt_normalize() &&
+           (get_entity_visibility(ent) != visibility_external_allocated)) { /* Meth. is defined */
           ir_node *new_node;
 
-             set_irg_current_block(current_ir_graph, get_nodes_block(node));
-             new_node = copy_const_value(get_atomic_ent_value(ent));
+         set_irg_current_block(current_ir_graph, get_nodes_block(node));
+         new_node = copy_const_value(get_atomic_ent_value(ent));
 
-             DBG_OPT_CSTEVAL(node, new_node);
+         DBG_OPT_CSTEVAL(node, new_node);
 
-             assert(get_entity_irg(ent));
-             DDMN(new_node);
-             exchange(node, new_node);
-           }
+         assert(get_entity_irg(ent));
+         DDMN(new_node);
+         exchange(node, new_node);
+       }
+#endif
       }
     }
   }
   else if (get_irn_op(node) == op_Sel &&
           is_Method_type(get_entity_type(get_Sel_entity(node)))) {
     entity * ent = get_Sel_entity(node);
-
-    /* Sel from Alloc: replace by constant */
-    if (get_opt_optimize() && get_opt_dyn_meth_dispatch() &&
-        (get_irn_op(skip_Proj(get_Sel_ptr(node))) == op_Alloc)) {
-      ir_node *new_node;
-      entity *called_ent;
-
-      /* We know which method will be called, no dispatch necessary. */
-      called_ent = resolve_ent_polymorphy(get_Alloc_type(skip_Proj(get_Sel_ptr(node))), ent);
-      set_irg_current_block(current_ir_graph, get_nodes_block(node));
-
-      /* called_ent may not be description: has no Address/Const to Call! */
-      assert(get_entity_peculiarity(called_ent) != peculiarity_description);
-      new_node = copy_const_value(get_atomic_ent_value(called_ent));
-
-      DBG_OPT_POLY_ALLOC(node, new_node);
-      exchange(node, new_node);
+    assert(get_entity_peculiarity(ent) != peculiarity_inherited);
+
+    if (!eset_contains(entities, ent)) {
+      /* Entity noch nicht behandelt. Alle (intern oder extern)
+       * implementierten Methoden suchen, die diese Entity
+       * überschreiben. Die Menge an entity.link speichern. */
+      set_entity_link(ent, get_impl_methods(ent));
+      eset_insert(entities, ent);
     }
-    else {
-      assert(get_entity_peculiarity(ent) != peculiarity_inherited);
-      if (!eset_contains(entities, ent)) {
-        /* Entity noch nicht behandelt. Alle (intern oder extern)
-         * implementierten Methoden suchen, die diese Entity
-         * überschreiben. Die Menge an entity.link speichern. */
-        set_entity_link(ent, get_impl_methods(ent));
-        eset_insert(entities, ent);
-      }
-      if (get_entity_link(ent) == NULL) {
-        /* Die Sel-Operation kann nie einen Zeiger auf eine aufrufbare
-         * Methode zurückgeben. Damit ist sie insbesondere nicht
-         * ausführbar und nicht erreichbar. */
-        /* Gib eine Warnung aus wenn die Entitaet eine Beschreibung ist
-           fuer die es keine Implementierung gibt. */
-        if (get_entity_peculiarity(ent) == peculiarity_description) {
-          /* This is possible:  We call a method in a dead part of the program. */
-        } else {
-             DDMN(node);
-             assert(0);  /* Why should this happen ??? */
-          //exchange(node, new_Bad());
-        }
-      } else {
-        entity ** arr = get_entity_link(ent);
 
-#if 0
-        int i;
-        printf("\nCall site "); DDMN(node);
-        printf("  in "); DDME(get_irg_entity(current_ir_graph));
-        printf("  can call:\n");
-        for (i = 0; i < ARR_LEN(arr); i++) {
-          printf("   - "); DDME(arr[i]);
-          printf("     with owner "); DDMT(get_entity_owner(arr[i]));
-        }
-        printf("\n");
-#endif
-
-        if (get_opt_optimize() && get_opt_dyn_meth_dispatch() &&
-            (ARR_LEN(arr) == 1 && arr[0] != NULL)) {
-          ir_node *new_node;
-          /* Die Sel-Operation kann immer nur _einen_ Wert auf eine
-           * interne Methode zurückgeben. Wir können daher die
-           * Sel-Operation durch eine Const- bzw. SymConst-Operation
-           * ersetzen. */
-          set_irg_current_block(current_ir_graph, get_nodes_block(node));
-          assert(get_entity_peculiarity(get_SymConst_entity(get_atomic_ent_value(arr[0]))) ==
-                peculiarity_existent);
-          new_node = copy_const_value(get_atomic_ent_value(arr[0]));
-          DBG_OPT_POLY(node, new_node);
-          exchange (node, new_node);
-        }
+    /* -- As an add on we get an optimization that removes polymorphic calls.
+       This optimization is more powerful than that in transform_node_Sel.  -- */
+    if (get_entity_link(ent) == NULL) {
+      /* Die Sel-Operation kann nie einen Zeiger auf eine aufrufbare
+       * Methode zurückgeben. Damit ist sie insbesondere nicht
+       * ausführbar und nicht erreichbar. */
+      /* Gib eine Warnung aus wenn die Entitaet eine Beschreibung ist
+        fuer die es keine Implementierung gibt. */
+      if (get_entity_peculiarity(ent) == peculiarity_description) {
+       /* This is possible:  We call a method in a dead part of the program. */
+      } else {
+       DDMN(node);
+       assert(0);  /* Why should this happen ??? */
+       //exchange(node, new_Bad());
+      }
+    } else {
+      entity ** arr = get_entity_link(ent);
+      if (get_opt_optimize() && get_opt_dyn_meth_dispatch() &&
+         (ARR_LEN(arr) == 1 && arr[0] != NULL)) {
+       ir_node *new_node;
+       /* Die Sel-Operation kann immer nur _einen_ Wert auf eine
+        * interne Methode zurückgeben. Wir können daher die
+        * Sel-Operation durch eine Const- bzw. SymConst-Operation
+        * ersetzen. */
+       set_irg_current_block(current_ir_graph, get_nodes_block(node));
+       assert(get_entity_peculiarity(get_SymConst_entity(get_atomic_ent_value(arr[0]))) ==
+              peculiarity_existent);
+       new_node = copy_const_value(get_atomic_ent_value(arr[0]));
+       DBG_OPT_POLY(node, new_node);
+       exchange (node, new_node);
       }
     }
   }
 }
 
-
 /** Datenstruktur initialisieren. Zusätzlich werden alle
  *  SymConst(name)-Operationen, die auf interne Methoden verweisen, durch
  *  SymConst(entity)-Operationen ersetzt. */
 static void sel_methods_init(void) {
   int i;
-  pmap * ldname_map = pmap_create();   /* Map entity names to entities: to replace SymConst(name) by SymConst(ent). */
-
+  pmap * ldname_map = pmap_create();   /* Map entity names to entities: to replace
+                                         SymConst(name) by SymConst(ent). */
   assert(entities == NULL);
   entities = eset_create();
   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
-    ir_graph *irg = get_irp_irg(i);
-    entity * ent = get_irg_entity(irg);
-    /* Nur extern sichtbare Methoden können überhaupt mit SymConst
+    entity * ent = get_irg_entity(get_irp_irg(i));
+    /* Nur extern sichtbare Methoden können überhaupt mit SymConst_ptr_name
      * aufgerufen werden. */
     if (get_entity_visibility(ent) != visibility_local) {
       pmap_insert(ldname_map, (void *) get_entity_ld_ident(ent), ent);
@@ -390,23 +304,12 @@ static void sel_methods_init(void) {
   pmap_destroy(ldname_map);
 }
 
-/*****************************************************************************/
-
-/** Frees the allocated entity map */
-static void sel_methods_dispose(void) {
-  entity * ent;
-  assert(entities);
-  for (ent = eset_first(entities); ent; ent = eset_next(entities)) {
-    entity ** arr = get_entity_link(ent);
-    if (arr) {
-      DEL_ARR_F(arr);
-    }
-    set_entity_link(ent, NULL);
-  }
-  eset_destroy(entities);
-  entities = NULL;
-}
-
+/*--------------------------------------------------------------------------*/
+/* Find free methods.
+ *
+ * We expect that each entity has an array with all implementations in its
+ * link field.                                                              */
+/*--------------------------------------------------------------------------*/
 
 /**
  * Returns an array of all methods that could be called at a Sel node.
@@ -449,13 +352,195 @@ static entity * get_Sel_method(ir_node * sel, int pos) {
   return arr[pos];
 }
 
+static void free_mark(ir_node * node, eset * set);
 
+static void free_mark_proj(ir_node * node, long n, eset * set) {
+  assert(get_irn_mode(node) == mode_T);
+  if (get_irn_link(node) == MARK) {
+    /* already visited */
+    return;
+  }
+  set_irn_link(node, MARK);
+  switch (get_irn_opcode(node)) {
+  case iro_Proj: {
+    /* proj_proj: in einem "sinnvollen" Graphen kommt jetzt ein
+     * op_Tuple oder ein Knoten, der in "free_ana_walker" behandelt
+     * wird. */
+    ir_node * pred = get_Proj_pred(node);
+    if (get_irn_link(pred) != MARK && get_irn_op(pred) == op_Tuple) {
+      free_mark_proj(get_Tuple_pred(pred, get_Proj_proj(node)), n, set);
+    } else {
+      /* nothing: da in "free_ana_walker" behandelt. */
+    }
+    break;
+  }
 
-/* --- callee analysis ------------------------------------------------------ */
+  case iro_Tuple:
+    free_mark(get_Tuple_pred(node, n), set);
+    break;
 
+  case iro_Id:
+    free_mark_proj(get_Id_pred(node), n, set);
+    break;
+
+  case iro_Start:
+  case iro_Alloc:
+  case iro_Load:
+    /* nothing: Die Operationen werden in "free_ana_walker" selbst
+     * behandelt. */
+    break;
+
+  default:
+    assert(0 && "unexpected opcode or opcode not implemented");
+    break;
+  }
+  set_irn_link(node, NULL);
+}
+
+
+static void free_mark(ir_node * node, eset * set) {
+  int i;
+
+  if (get_irn_link(node) == MARK) {
+    return; /* already visited */
+  }
+  set_irn_link(node, MARK);
+  switch (get_irn_opcode(node)) {
+  case iro_Sel: {
+    entity * ent = get_Sel_entity(node);
+    if (is_Method_type(get_entity_type(ent))) {
+      for (i = get_Sel_n_methods(node) - 1; i >= 0; --i) {
+        eset_insert(set, get_Sel_method(node, i));
+      }
+    }
+    break;
+  }
+  case iro_SymConst:
+    if (get_SymConst_kind(node) == symconst_addr_ent) {
+      entity * ent = get_SymConst_entity(node);
+      if (is_Method_type(get_entity_type(ent))) {
+        eset_insert(set, ent);
+      }
+    } else {
+      assert(get_SymConst_kind(node) == symconst_addr_name);
+      /* nothing: SymConst points to extern method */
+    }
+    break;
+
+  case iro_Phi:
+    for (i = get_Phi_n_preds(node) - 1; i >= 0; --i) {
+      free_mark(get_Phi_pred(node, i), set);
+    }
+    break;
+  case iro_Id:
+    free_mark(get_Id_pred(node), set);
+    break;
+  case iro_Proj:
+    free_mark_proj(get_Proj_pred(node), get_Proj_proj(node), set);
+    break;
+  default:
+    /* nothing: Wird unten behandelt! */
+    break;
+  }
+  set_irn_link(node, NULL);
+}
 
-static void callee_ana_node(ir_node * node, eset * methods);
 
+static void free_ana_walker(ir_node * node, eset * set) {
+  int i;
+  if (get_irn_link(node) == MARK) {
+    /* bereits in einem Zyklus besucht. */
+    return;
+  }
+  switch (get_irn_opcode(node)) {
+  /* special nodes */
+  case iro_Sel:
+  case iro_SymConst:
+  case iro_Const:
+  case iro_Phi:
+  case iro_Id:
+  case iro_Proj:
+  case iro_Tuple:
+    /* nothing */
+    break;
+  /* Sonderbehandlung, da der Funktionszeigereingang natürlich kein
+   * Verräter ist. */
+  case iro_Call:
+    set_irn_link(node, MARK);
+    for (i = get_Call_arity(node) - 1; i >= 0; --i) {
+      ir_node * pred = get_Call_param(node, i);
+      if (mode_is_reference(get_irn_mode(pred))) {
+        free_mark(pred, set);
+      }
+    }
+    break;
+  /* other nodes: Alle anderen Knoten nehmen wir als Verräter an, bis
+   * jemand das Gegenteil implementiert. */
+  default:
+    set_irn_link(node, MARK);
+    for (i = get_irn_arity(node) - 1; i >= 0; --i) {
+      ir_node * pred = get_irn_n(node, i);
+      if (mode_is_reference(get_irn_mode(pred))) {
+        free_mark(pred, set);
+      }
+    }
+    break;
+  }
+  set_irn_link(node, NULL);
+}
+
+/* Die Datenstrukturen für sel-Methoden (sel_methods) muß vor dem
+ * Aufruf von "get_free_methods" aufgebaut sein. Die (internen)
+ * SymConst(name)-Operationen müssen in passende SymConst(ent)-Operationen
+ * umgewandelt worden sein, d.h. SymConst-Operationen verweisen immer
+ * auf eine echt externe Methode. */
+static entity ** get_free_methods(void)
+{
+  eset * set = eset_create();
+  int i;
+  entity ** arr = NEW_ARR_F(entity *, 0);
+  entity * ent;
+
+  for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
+    ir_graph * irg = get_irp_irg(i);
+    entity * ent = get_irg_entity(irg);
+    /* insert "external visible" methods. */
+    if (get_entity_visibility(ent) != visibility_local) {
+      eset_insert(set, ent);
+    }
+    /* Finde alle Methoden die in dieser Methode extern sichtbar werden,
+       z.B. da die Adresse einer Methode abgespeichert wird. */
+    irg_walk_graph(irg, NULL, (irg_walk_func *) free_ana_walker, set);
+  }
+
+  /* insert sticky methods, too */
+  for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
+    entity * ent = get_irg_entity(get_irp_irg(i));
+    /* insert "external visible" methods. */
+    if (get_entity_stickyness (ent) == stickyness_sticky) {
+      eset_insert(set, ent);
+    }
+  }
+
+  /* Hauptprogramm ist auch dann frei, wenn es nicht "external
+   * visible" ist. */
+  if (get_irp_main_irg()) {
+    eset_insert(set, get_irg_entity(get_irp_main_irg()));
+  }
+  /* Wandle Menge in Feld um.  Effizienter. */
+  for (ent = eset_first(set); ent; ent = eset_next(set)) {
+    ARR_APP1(entity *, arr, ent);
+  }
+  eset_destroy(set);
+
+  return arr;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Callee analysis.                                                         */
+/*--------------------------------------------------------------------------*/
+
+static void callee_ana_node(ir_node * node, eset * methods);
 
 static void callee_ana_proj(ir_node * node, long n, eset * methods) {
   assert(get_irn_mode(node) == mode_T);
@@ -610,7 +695,6 @@ static void callee_walker(ir_node * call, void * env) {
       int i;
       for (i = 0; i < ARR_LEN(arr); ++i) {
        assert(arr[i]);
-       //if (arr[i] == unknown_entity) arr[i] = NULL;
       }
 
       set_Call_callee_arr(call, ARR_LEN(arr), arr);
@@ -644,196 +728,38 @@ static void callee_ana(void) {
   set_irp_callee_info_state(irg_callee_info_consistent);
 }
 
+/*--------------------------------------------------------------------------*/
+/* Cleanup after analyses.                                                  */
+/*--------------------------------------------------------------------------*/
 
-
-/* --- free method analysis ------------------------------------------------- */
-
-
-static void free_mark(ir_node * node, eset * set);
-
-static void free_mark_proj(ir_node * node, long n, eset * set) {
-  assert(get_irn_mode(node) == mode_T);
-  if (get_irn_link(node) == MARK) {
-    /* already visited */
-    return;
-  }
-  set_irn_link(node, MARK);
-  switch (get_irn_opcode(node)) {
-  case iro_Proj: {
-    /* proj_proj: in einem "sinnvollen" Graphen kommt jetzt ein
-     * op_Tuple oder ein Knoten, der in "free_ana_walker" behandelt
-     * wird. */
-    ir_node * pred = get_Proj_pred(node);
-    if (get_irn_link(pred) != MARK && get_irn_op(pred) == op_Tuple) {
-      free_mark_proj(get_Tuple_pred(pred, get_Proj_proj(node)), n, set);
-    } else {
-      /* nothing: da in "free_ana_walker" behandelt. */
-    }
-    break;
-  }
-
-  case iro_Tuple:
-    free_mark(get_Tuple_pred(node, n), set);
-    break;
-
-  case iro_Id:
-    free_mark_proj(get_Id_pred(node), n, set);
-    break;
-
-  case iro_Start:
-  case iro_Alloc:
-  case iro_Load:
-    /* nothing: Die Operationen werden in "free_ana_walker" selbst
-     * behandelt. */
-    break;
-
-  default:
-    assert(0 && "unexpected opcode or opcode not implemented");
-    break;
-  }
-  set_irn_link(node, NULL);
-}
-
-
-static void free_mark(ir_node * node, eset * set) {
-  int i;
-
-  if (get_irn_link(node) == MARK) {
-    return; /* already visited */
-  }
-  set_irn_link(node, MARK);
-  switch (get_irn_opcode(node)) {
-  case iro_Sel: {
-    entity * ent = get_Sel_entity(node);
-    if (is_Method_type(get_entity_type(ent))) {
-      for (i = get_Sel_n_methods(node) - 1; i >= 0; --i) {
-        eset_insert(set, get_Sel_method(node, i));
-      }
-    }
-    break;
-  }
-  case iro_SymConst:
-    if (get_SymConst_kind(node) == symconst_addr_ent) {
-      entity * ent = get_SymConst_entity(node);
-      if (is_Method_type(get_entity_type(ent))) {
-        eset_insert(set, ent);
-      }
-    } else {
-      assert(get_SymConst_kind(node) == symconst_addr_name);
-      /* nothing: SymConst points to extern method */
-    }
-    break;
-
-  case iro_Phi:
-    for (i = get_Phi_n_preds(node) - 1; i >= 0; --i) {
-      free_mark(get_Phi_pred(node, i), set);
+/** Frees intermediate data structures. */
+static void sel_methods_dispose(void) {
+  entity * ent;
+  assert(entities);
+  for (ent = eset_first(entities); ent; ent = eset_next(entities)) {
+    entity ** arr = get_entity_link(ent);
+    if (arr) {
+      DEL_ARR_F(arr);
     }
-    break;
-  case iro_Id:
-    free_mark(get_Id_pred(node), set);
-    break;
-  case iro_Proj:
-    free_mark_proj(get_Proj_pred(node), get_Proj_proj(node), set);
-    break;
-  default:
-    /* nothing: Wird unten behandelt! */
-    break;
+    set_entity_link(ent, NULL);
   }
-  set_irn_link(node, NULL);
+  eset_destroy(entities);
+  entities = NULL;
 }
 
+/*--------------------------------------------------------------------------*/
+/* Freeing the callee arrays.                                               */
+/*--------------------------------------------------------------------------*/
 
-static void free_ana_walker(ir_node * node, eset * set) {
-  int i;
-  if (get_irn_link(node) == MARK) {
-    /* bereits in einem Zyklus besucht. */
-    return;
-  }
-  switch (get_irn_opcode(node)) {
-  /* special nodes */
-  case iro_Sel:
-  case iro_SymConst:
-  case iro_Const:
-  case iro_Phi:
-  case iro_Id:
-  case iro_Proj:
-  case iro_Tuple:
-    /* nothing */
-    break;
-  /* Sonderbehandlung, da der Funktionszeigereingang natürlich kein
-   * Verräter ist. */
-  case iro_Call:
-    set_irn_link(node, MARK);
-    for (i = get_Call_arity(node) - 1; i >= 0; --i) {
-      ir_node * pred = get_Call_param(node, i);
-      if (mode_is_reference(get_irn_mode(pred))) {
-        free_mark(pred, set);
-      }
-    }
-    break;
-  /* other nodes: Alle anderen Knoten nehmen wir als Verräter an, bis
-   * jemand das Gegenteil implementiert. */
-  default:
-    set_irn_link(node, MARK);
-    for (i = get_irn_arity(node) - 1; i >= 0; --i) {
-      ir_node * pred = get_irn_n(node, i);
-      if (mode_is_reference(get_irn_mode(pred))) {
-        free_mark(pred, set);
-      }
-    }
-    break;
+static void destruct_walker(ir_node * node, void * env) {
+  if (get_irn_op(node) == op_Call) {
+    remove_Call_callee_arr(node);
   }
-  set_irn_link(node, NULL);
 }
 
-
-/* Die Datenstrukturen für sel-Methoden (sel_methods) muß vor dem
- * Aufruf von "get_free_methods" aufgebaut sein. Die (internen)
- * SymConst-Operationen müssen in passende Const-Operationen
- * umgewandelt worden sein, d.h. SymConst-Operationen verweisen immer
- * auf eine echt externe Methode.  */
-static entity ** get_free_methods(void)
-{
-  eset * set = eset_create();
-  int i;
-  entity ** arr = NEW_ARR_F(entity *, 0);
-  entity * ent;
-
-  for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
-    ir_graph * irg = get_irp_irg(i);
-    entity * ent = get_irg_entity(irg);
-    /* insert "external visible" methods. */
-    if (get_entity_visibility(ent) != visibility_local) {
-      eset_insert(set, ent);
-    }
-    /* Finde alle Methoden die in dieser Methode extern sichtbar werden,
-       z.B. da die Adresse einer Methode abgespeichert wird. */
-    irg_walk_graph(irg, NULL, (irg_walk_func *) free_ana_walker, set);
-  }
-
-  /* insert sticky methods, too */
-  for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
-    ir_graph * irg = get_irp_irg(i);
-    entity * ent = get_irg_entity(irg);
-    /* insert "external visible" methods. */
-    if (get_entity_stickyness (ent) == stickyness_sticky) {
-      eset_insert(set, ent);
-    }
-  }
-
-  /* Hauptprogramm ist auch dann frei, wenn es nicht "external
-   * visible" ist. */
-  if (get_irp_main_irg()) {
-    eset_insert(set, get_irg_entity(get_irp_main_irg()));
-  }
-  /* Wandle Menge in Feld um.  Effizienter. */
-  for (ent = eset_first(set); ent; ent = eset_next(set)) {
-    ARR_APP1(entity *, arr, ent);
-  }
-  eset_destroy(set);
-
-  return arr;
-}
+/*--------------------------------------------------------------------------*/
+/* Main drivers.                                                            */
+/*--------------------------------------------------------------------------*/
 
 void cgana(int *length, entity ***free_methods) {
   entity ** free_meths, **p;
@@ -854,20 +780,11 @@ void cgana(int *length, entity ***free_methods) {
   DEL_ARR_F(free_meths);
 }
 
-
-
-static void destruct_walker(ir_node * node, void * env) {
-  if (get_irn_op(node) == op_Call) {
-    remove_Call_callee_arr(node);
-  }
-}
-
 void free_callee_info(ir_graph *irg) {
   irg_walk_graph(irg, destruct_walker, NULL, NULL);
   set_irg_callee_info_state(irg, irg_callee_info_none);
 }
 
-
 /* Optimize the address expressions passed to call nodes.
  *
  * This optimization performs the following transformations for
@@ -876,7 +793,7 @@ void free_callee_info(ir_graph *irg) {
  *   by Const operations refering to the corresponding entity.
  * - Sel nodes, that select entities that are not overwritten are
  *   replaced by Const nodes refering to the selected entity.
- * - Sel nodes, for witch no method exists at all are replaced by Bad
+ * - Sel nodes, for which no method exists at all are replaced by Bad
  *   nodes.
  * - Sel nodes with a pointer input that is an Alloc node are replaced
  *   by Const nodes refering to the entity that implements the method in
index ca85bd7..a04105d 100644 (file)
  *
  * Die main-Methode ist immer in der Menge enthalten.
  *
- * Die Links an den "ir_node"s werden geloescht. */
+ * Die Links an den "ir_node"s werden geloescht.
+ */
 
 /** Analyses a rough estimation of the possible call graph.
  *
  *  Determines for each Call node the set of possibly called methods.
  *  Stores the result in the field 'callees' of the Call node.  If the
  *  address can not be analysed, e.g. because it is loaded from a
- *  variable, the array contains NULL. @@@ the array should contain a
- *  special entity 'unknown'. (See "set_Call_callee"). cgana returns
- *  the set of 'free' methods, i.e., the methods that can be called
- *  from external or via function pointers.  This datastructure must
- *  be freed with 'free()' by the caller of cgana.
+ *  variable, the array contains the unknown_entity. (See
+ *  "set_Call_callee"). cgana returns the set of 'free' methods, i.e.,
+ *  the methods that can be called from external or via function
+ *  pointers.  This datastructure must be freed with 'free()' by the
+ *  caller of cgana.
  *
- *  cgana sets the callee_info_state of each graph to consistent.
+ *  cgana sets the callee_info_state of each graph and the program to
+ *  consistent.
  *
  *  The algorithm implements roughly Static Class Hierarchy Analysis
  *  as described in "Optimization of Object-Oriented Programs Using
@@ -58,7 +60,7 @@
  *    - Replace SymConst-name nodes by SymConst-entity nodes if possible.
  *    - Replace (Sel-method(Alloc)) by SymConst-entity.
  *    - Replaces Sel nodes by Bad if there is no implementation for the
- *         selected entity.  (@@@ was genau meint unreachable?)
+ *         selected entity.
  *    - Replaces Sel-method by SymConst-entity if the method is never overwritten.
  *    - Replaces Calls by Tuple containing Bads if callee array is empty
  *         (there is no implementation to call)
index 4070a87..043a3b2 100644 (file)
@@ -307,12 +307,15 @@ static long get_Sel_array_index_long(ir_node *n, int dim) {
   return get_tarval_long(get_Const_tarval(index));
 }
 
-compound_graph_path *rec_get_accessed_path(ir_node *ptr, int depth) {
+static compound_graph_path *rec_get_accessed_path(ir_node *ptr, int depth) {
   compound_graph_path *res;
   if (get_irn_op(ptr) == op_SymConst) {
     assert(get_SymConst_kind(ptr) == symconst_addr_ent);
     entity *root = get_SymConst_entity(ptr);
-    res = new_compound_graph_path(get_entity_type(root), depth);
+    if (depth == 0)
+      res = NULL;
+    else
+      res = new_compound_graph_path(get_entity_type(root), depth);
   } else {
     assert(get_irn_op(ptr) == op_Sel);
     res = rec_get_accessed_path(get_Sel_ptr(ptr), depth+1);
@@ -328,7 +331,10 @@ compound_graph_path *rec_get_accessed_path(ir_node *ptr, int depth) {
   return res;
 }
 
-compound_graph_path *get_accessed_path(ir_node *ptr) {
+
+/** Returns an access path or NULL.  The access path is only
+ *  valid, if the graph is in phase_high and _no_ address computation is used. */
+static compound_graph_path *get_accessed_path(ir_node *ptr) {
   return rec_get_accessed_path(ptr, 0);
 }
 
@@ -463,27 +469,30 @@ static int optimize_load(ir_node *load)
        printf("  ptr:  "); DDMN(ptr);
 
        compound_graph_path *path = get_accessed_path(ptr);
-       assert(is_proper_compound_graph_path(path, get_compound_graph_path_length(path)-1));
-       ir_node *c = get_compound_ent_value_by_path(ent, path);
-
-       printf("  cons: "); DDMN(c);
-
-        if (info->projs[pn_Load_M])
-          exchange(info->projs[pn_Load_M], mem);
-        if (info->projs[pn_Load_res])
-         exchange(info->projs[pn_Load_res], copy_const_value(c));
-
-       {
-       int j;
-               for (j = 0; j < get_compound_graph_path_length(path); ++j) {
-                 entity *node = get_compound_graph_path_node(path, j);
-                 fprintf(stdout, ".%s", get_entity_name(node));
-                 if (is_Array_type(get_entity_owner(node)))
-                   fprintf(stdout, "[%d]", get_compound_graph_path_array_index(path, j));
-               }
-               printf("\n");
+       if (path) {
+         assert(is_proper_compound_graph_path(path, get_compound_graph_path_length(path)-1));
+         ir_node *c = get_compound_ent_value_by_path(ent, path);
+
+         printf("  cons: "); DDMN(c);
+
+         if (info->projs[pn_Load_M])
+           exchange(info->projs[pn_Load_M], mem);
+         if (info->projs[pn_Load_res])
+           exchange(info->projs[pn_Load_res], copy_const_value(c));
+
+         {
+           int j;
+           for (j = 0; j < get_compound_graph_path_length(path); ++j) {
+             entity *node = get_compound_graph_path_node(path, j);
+             fprintf(stdout, ".%s", get_entity_name(node));
+             if (is_Array_type(get_entity_owner(node)))
+               fprintf(stdout, "[%d]", get_compound_graph_path_array_index(path, j));
+           }
+           printf("\n");
+         }
+       } else {
+         printf("cannot optimize.\n");
        }
-
       }
 
       /* we changed the irg, but try further */