- fixed a stupid Bug: the marks are not cleared at the beginning,
[libfirm] / ir / ana / cgana.c
index 1edd40f..722f6f3 100644 (file)
@@ -50,6 +50,7 @@
 #include "ircons.h"
 #include "irgmod.h"
 #include "iropt.h"
+#include "irtools.h"
 
 #include "irflag_t.h"
 #include "dbginfo_t.h"
@@ -58,6 +59,7 @@
 #include "eset.h"
 #include "pmap.h"
 #include "array.h"
+#include "error.h"
 
 #include "irdump.h"
 
@@ -83,12 +85,12 @@ static eset *entities = NULL;
 /** Returns the entity that contains the implementation of the inherited
  *  entity if available, else returns the entity passed. */
 static ir_entity *get_inherited_methods_implementation(ir_entity *inh_meth) {
-       assert(get_atomic_ent_value(inh_meth) && "constant entity without value");
-       assert((get_irn_op(get_atomic_ent_value(inh_meth)) == op_SymConst) &&
-              (get_SymConst_kind(get_atomic_ent_value(inh_meth)) == symconst_addr_ent) &&
+       ir_node *value = get_atomic_ent_value(inh_meth);
+       assert(value && "constant entity without value");
+       assert(is_SymConst_addr_ent(value) &&
               "Complex constant values not supported -- address of method should be straight constant!");
 
-       return get_SymConst_entity(get_atomic_ent_value(inh_meth));
+       return get_SymConst_entity(value);
 }
 
 /** Collect the entity representing the implementation of this
@@ -190,8 +192,10 @@ static void sel_methods_walker(ir_node *node, void *env) {
        /* Call standard optimizations */
        if (is_Sel(node)) {
                ir_node *new_node = optimize_in_place(node);
-               if (node != new_node)
+               if (node != new_node) {
                        exchange(node, new_node);
+                       node = new_node;
+               }
        }
 
        /* replace SymConst(name)-operations by SymConst(ent) */
@@ -204,44 +208,44 @@ static void sel_methods_walker(ir_node *node, void *env) {
                        }
                }
        } else if (is_Sel(node) && is_Method_type(get_entity_type(get_Sel_entity(node)))) {
-                       ir_entity *ent = get_SymConst_entity(get_atomic_ent_value(get_Sel_entity(node)));
-                       assert(get_entity_peculiarity(ent) != peculiarity_inherited);
-
-                       if (!eset_contains(entities, ent)) {
-                               /* Entity not yet handled. Find all (internal or external)
-                                * implemented methods that overwrites this entity.
-                                * This set is stored in the entity link. */
-                               set_entity_link(ent, get_impl_methods(ent));
-                               eset_insert(entities, ent);
-                       }
+               ir_entity *ent = get_SymConst_entity(get_atomic_ent_value(get_Sel_entity(node)));
+               assert(get_entity_peculiarity(ent) != peculiarity_inherited);
+
+               if (!eset_contains(entities, ent)) {
+                       /* Entity not yet handled. Find all (internal or external)
+                        * implemented methods that overwrites this entity.
+                        * This set is stored in the entity link. */
+                       set_entity_link(ent, get_impl_methods(ent));
+                       eset_insert(entities, ent);
+               }
 
-                       /* -- As an add on we get an optimization that removes polymorphic calls.
-                       This optimization is more powerful than that in transform_node_Sel().  -- */
-                       arr = get_entity_link(ent);
-                       if (arr == NULL) {
-                               /*
-                                * The Sel node never returns a pointer to a usable method.
-                                * We could not call it, but it may be description:
-                                * We call a method in a dead part of the program.
-                                */
-                               assert(get_entity_peculiarity(ent) == peculiarity_description);
-                       }
-                       else if (get_opt_closed_world() && get_opt_dyn_meth_dispatch() &&
-                               (ARR_LEN(arr) == 1 && arr[0] != NULL)) {
-                                       ir_node *new_node;
-
-                                       /*
-                                        * The Sel node returns only one possible method.
-                                        * So we could replace the Sel node by a SymConst.
-                                        * This method must exists.
-                                        */
-                                       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_irn_dbg_info(node), 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().  -- */
+               arr = get_entity_link(ent);
+               if (arr == NULL) {
+                       /*
+                        * The Sel node never returns a pointer to a usable method.
+                        * We could not call it, but it may be description:
+                        * We call a method in a dead part of the program.
+                        */
+                       assert(get_entity_peculiarity(ent) == peculiarity_description);
+               }
+               else if (get_opt_closed_world() && get_opt_dyn_meth_dispatch() &&
+                       (ARR_LEN(arr) == 1 && arr[0] != NULL)) {
+                       ir_node *new_node;
+
+                       /*
+                        * The Sel node returns only one possible method.
+                        * So we could replace the Sel node by a SymConst.
+                        * This method must exists.
+                        */
+                       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_irn_dbg_info(node), get_atomic_ent_value(arr[0]));
+                       DBG_OPT_POLY(node, new_node);
+                       exchange(node, new_node);
+               }
        }
 }
 
@@ -371,7 +375,7 @@ static void free_mark_proj(ir_node * node, long n, eset * set) {
                assert(0 && "unexpected opcode or opcode not implemented");
                break;
        }
-       set_irn_link(node, NULL);
+       // set_irn_link(node, NULL);
 }
 
 /**
@@ -427,7 +431,6 @@ static void free_mark(ir_node *node, eset * set) {
                /* nothing: */
                break;
        }
-       set_irn_link(node, NULL);
 }
 
 /**
@@ -475,7 +478,49 @@ static void free_ana_walker(ir_node *node, void *env) {
                }
                break;
        }
-       set_irn_link(node, NULL);
+}
+
+/**
+ * Add all method addresses in global new style initializers to the set.
+ *
+ * @note
+ * We do NOT check the type here, just it it's an entity address.
+ * The reason for this is code like:
+ *
+ * void *p = function;
+ *
+ * which is sometimes used to anchor functions.
+ */
+static void add_method_address_inititializer(ir_initializer_t *initializer,
+                                             eset *set)
+{
+       ir_node *n;
+       size_t  i;
+
+       switch (initializer->kind) {
+       case IR_INITIALIZER_CONST:
+               n = initializer->consti.value;
+
+               /* let's check if it's the address of a function */
+               if (is_Global(n)) {
+                       ir_entity *ent = get_Global_entity(n);
+
+                       if (is_Method_type(get_entity_type(ent)))
+                               eset_insert(set, ent);
+               }
+               return;
+       case IR_INITIALIZER_TARVAL:
+       case IR_INITIALIZER_NULL:
+               return;
+       case IR_INITIALIZER_COMPOUND:
+               for (i = 0; i < initializer->compound.n_initializers; ++i) {
+                       ir_initializer_t *sub_initializer
+                               = initializer->compound.initializers[i];
+                       add_method_address_inititializer(sub_initializer, set);
+               }
+               return;
+       }
+       panic("invalid initializer found");
 }
 
 /**
@@ -499,7 +544,9 @@ static void add_method_address(ir_entity *ent, eset *set)
        if (get_entity_variability(ent) == variability_uninitialized)
                return;
 
-       if (is_atomic_entity(ent)) {
+       if (ent->has_initializer) {
+               add_method_address_inititializer(get_entity_initializer(ent), set);
+       } else if (is_atomic_entity(ent)) {
                tp = get_entity_type(ent);
 
                /* ignore methods: these of course reference it's address */
@@ -508,8 +555,8 @@ static void add_method_address(ir_entity *ent, eset *set)
 
                /* let's check if it's the address of a function */
                n = get_atomic_ent_value(ent);
-               if (is_SymConst_addr_ent(n)) {
-                       ent = get_SymConst_entity(n);
+               if (is_Global(n)) {
+                       ent = get_Global_entity(n);
 
                        if (is_Method_type(get_entity_type(ent)))
                                eset_insert(set, ent);
@@ -519,8 +566,8 @@ static void add_method_address(ir_entity *ent, eset *set)
                        n = get_compound_ent_value(ent, i);
 
                        /* let's check if it's the address of a function */
-                       if (is_SymConst_addr_ent(n)) {
-                               ir_entity *ent = get_SymConst_entity(n);
+                       if (is_Global(n)) {
+                               ir_entity *ent = get_Global_entity(n);
 
                                if (is_Method_type(get_entity_type(ent)))
                                        eset_insert(set, ent);
@@ -551,18 +598,19 @@ static ir_entity **get_free_methods(int *length)
        for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
                irg = get_irp_irg(i);
                ent = get_irg_entity(irg);
-               /* insert "external visible" methods. */
                if (get_entity_visibility(ent) != visibility_local) {
+                       /* insert non-local (external) methods. */
                        eset_insert(free_set, ent);
-               }
-               /* insert "sticky" methods. */
-               if (get_entity_stickyness(ent) == stickyness_sticky) {
+               } else if (get_entity_stickyness(ent) == stickyness_sticky) {
+                       /* insert "sticky" methods. */
                        eset_insert(free_set, ent);
                }
 
-               /* Find all method entities that gets "visible" trough this graphs,
+               set_using_irn_link(irg);
+               /* Find all method entities that gets "visible" through this graphs,
                 * for instance because their address is stored. */
-               irg_walk_graph(irg, NULL, free_ana_walker, free_set);
+               irg_walk_graph(irg, firm_clear_link, free_ana_walker, free_set);
+               clear_using_irn_link(irg);
        }
 
        /* insert all methods that are used in global variables initializers */
@@ -631,8 +679,6 @@ static void callee_ana_proj(ir_node *node, long n, eset *methods) {
                eset_insert(methods, unknown_entity); /* free method -> unknown */
                break;
        }
-
-       set_irn_link(node, NULL);
 }
 
 /**
@@ -722,8 +768,6 @@ static void callee_ana_node(ir_node *node, eset *methods) {
                assert(0 && "invalid opcode or opcode not implemented");
                break;
        }
-
-       set_irn_link(node, NULL);
 }
 
 /**