Renamed get_Cond_defaultProj() to get_Cond_default_proj() for consistency. Added...
[libfirm] / ir / ana / irmemory.c
index 4b3a7f8..db0aa7c 100644 (file)
  * @date     27.12.2006
  * @version  $Id$
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <stdlib.h>
 #include <stdbool.h>
 
+#include "adt/pmap.h"
 #include "irnode_t.h"
 #include "irgraph_t.h"
 #include "irprog_t.h"
 #include "irprintf.h"
 #include "debug.h"
 #include "error.h"
+#include "typerep.h"
 
 /** The debug handle. */
 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
+DEBUG_ONLY(static firm_dbg_module_t *dbgcall = NULL;)
 
 /** The source language specific language disambiguator function. */
 static DISAMBIGUATOR_FUNC language_disambuigator = NULL;
@@ -333,6 +334,8 @@ static ir_alias_relation different_sel_offsets(ir_node *sel1, ir_node *sel2) {
                        return have_no > 0 ? no_alias : sure_alias;
                }
        }
+#else
+       (void) different_index;
 #endif
        return ir_may_alias;
 }  /* different_sel_offsets */
@@ -363,13 +366,11 @@ static ir_alias_relation different_types(ir_node *adr1, ir_node *adr2)
                ir_type *tp2 = get_entity_type(ent2);
 
                if (tp1 != tp2) {
-#if 0
                        /* do deref until no pointer types are found */
                        while (is_Pointer_type(tp1) && is_Pointer_type(tp2)) {
                                tp1 = get_pointer_points_to_type(tp1);
                                tp2 = get_pointer_points_to_type(tp2);
                        }
-#endif
 
                        if (get_type_tpop(tp1) != get_type_tpop(tp2)) {
                                /* different type structure */
@@ -439,6 +440,8 @@ ir_storage_class_class_t classify_pointer(ir_graph *irg, ir_node *irn, ir_entity
                        res |= ir_sc_modifier_nottaken;
        } else if (is_Proj(irn) && is_malloc_Result(irn)) {
                return ir_sc_malloced;
+       } else if (is_Const(irn)) {
+               return ir_sc_globaladdr;
        }
 
        return res;
@@ -484,7 +487,7 @@ static ir_alias_relation _get_alias_relation(
        ir_node               *orig_adr1 = adr1;
        ir_node               *orig_adr2 = adr2;
        unsigned              mode_size;
-       ir_storage_class_class_t class1, class2;
+       ir_storage_class_class_t class1, class2, mod1, mod2;
        int                   have_const_offsets;
 
        if (! get_opt_alias_analysis())
@@ -578,16 +581,19 @@ static ir_alias_relation _get_alias_relation(
                        return different_sel_offsets(adr1, adr2);
        }
 
-       class1 = classify_pointer(irg, base1, ent1);
-       class2 = classify_pointer(irg, base2, ent2);
+       mod1 = classify_pointer(irg, base1, ent1);
+       mod2 = classify_pointer(irg, base2, ent2);
+
+       class1 = GET_BASE_SC(mod1);
+       class2 = GET_BASE_SC(mod2);
 
        if (class1 == ir_sc_pointer) {
-               if (class2 & ir_sc_modifier_nottaken) {
+               if (mod2 & ir_sc_modifier_nottaken) {
                        /* a pointer and an object whose objects was never taken */
                        return ir_no_alias;
                }
        } else if (class2 == ir_sc_pointer) {
-               if (class1 & ir_sc_modifier_nottaken) {
+               if (mod1 & ir_sc_modifier_nottaken) {
                        /* a pointer and an object whose objects was never taken */
                        return ir_no_alias;
                }
@@ -604,6 +610,16 @@ static ir_alias_relation _get_alias_relation(
 
                        /* for some reason CSE didn't happen yet for the 2 SymConsts... */
                        return ir_may_alias;
+               } else if (class1 == ir_sc_globaladdr) {
+                       tarval *tv  = get_Const_tarval(base1);
+                       offset1    += get_tarval_long(tv);
+                       tv          = get_Const_tarval(base2);
+                       offset2    += get_tarval_long(tv);
+
+                       if ((unsigned long)labs(offset2 - offset1) >= mode_size)
+                               return ir_no_alias;
+                       else
+                               return ir_sure_alias;
                }
        }
 
@@ -772,7 +788,7 @@ static int is_hidden_cast(ir_mode *mode, ir_mode *ent_mode) {
 }  /* is_hidden_cast */
 
 /**
- * Determine the usage state of a node (or it's successor Sels).
+ * Determine the usage state of a node (or its successor Sels).
  *
  * @param irn  the node
  */
@@ -788,7 +804,8 @@ static ir_entity_usage determine_entity_usage(const ir_node *irn, ir_entity *ent
 
                switch (get_irn_opcode(succ)) {
                case iro_Load:
-                       assert(irn == get_Load_ptr(succ));
+                       /* beware: irn might be a Id node here, so irn might be not
+                          equal to get_Load_ptr(succ) */
                        res |= ir_usage_read;
 
                        /* check if this load is not a hidden conversion */
@@ -852,8 +869,36 @@ static ir_entity_usage determine_entity_usage(const ir_node *irn, ir_entity *ent
                        }
                        break;
 
+               /* skip identities */
+               case iro_Id:
+                       res |= determine_entity_usage(succ, entity);
+                       break;
+
+               /* skip tuples */
+               case iro_Tuple: {
+                       int input_nr;
+                       for (input_nr = get_Tuple_n_preds(succ) - 1; input_nr >= 0;
+                                       --input_nr) {
+                               ir_node *pred = get_Tuple_pred(succ, input_nr);
+                               if (pred == irn) {
+                                       int k;
+                                       /* we found one input */
+                                       for (k = get_irn_n_outs(succ) - 1; k >= 0; --k) {
+                                               ir_node *proj = get_irn_out(succ, k);
+
+                                               if (is_Proj(proj) && get_Proj_proj(proj) == input_nr) {
+                                                       res |= determine_entity_usage(proj, entity);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       break;
+               }
+
                default:
-                       /* another op, we don't know anything */
+                       /* another op, we don't know anything (we could do more advanced
+                        * things like a dataflow analysis here) */
                        res |= ir_usage_unknown;
                        break;
                }
@@ -868,13 +913,18 @@ static ir_entity_usage determine_entity_usage(const ir_node *irn, ir_entity *ent
 static void analyse_irg_entity_usage(ir_graph *irg) {
        ir_type *ft = get_irg_frame_type(irg);
        ir_node *irg_frame;
-       int i;
+       int i, j, k, static_link_arg;
 
        /* set initial state to not_taken, as this is the "smallest" state */
        for (i = get_class_n_members(ft) - 1; i >= 0; --i) {
                ir_entity *ent = get_class_member(ft, i);
 
-               set_entity_usage(ent, 0);
+               /* methods can only be analyzed globally */
+               if (! is_method_entity(ent)) {
+                       ir_entity_usage  flags =
+                               get_entity_stickyness(ent) == stickyness_sticky ? ir_usage_unknown : 0;
+                       set_entity_usage(ent, flags);
+               }
        }
 
        assure_irg_outs(irg);
@@ -895,6 +945,46 @@ static void analyse_irg_entity_usage(ir_graph *irg) {
                set_entity_usage(entity, flags);
        }
 
+       /* check inner functions accessing outer frame */
+       static_link_arg = 0;
+       for (i = get_class_n_members(ft) - 1; i >= 0; --i) {
+               ir_entity *ent = get_class_member(ft, i);
+               ir_graph  *inner_irg;
+               ir_node   *args;
+
+               if (! is_method_entity(ent))
+                       continue;
+               if (get_entity_peculiarity(ent) == peculiarity_description)
+                       continue;
+
+               inner_irg = get_entity_irg(ent);
+               assure_irg_outs(inner_irg);
+               args = get_irg_args(inner_irg);
+               for (j = get_irn_n_outs(args) - 1; j >= 0; --j) {
+                       ir_node *arg = get_irn_out(args, j);
+
+                       if (get_Proj_proj(arg) == static_link_arg) {
+                               for (k = get_irn_n_outs(arg) - 1; k >= 0; --k) {
+                                       ir_node *succ = get_irn_out(arg, k);
+
+                                       if (is_Sel(succ)) {
+                                               ir_entity *entity = get_Sel_entity(succ);
+
+                                               if (get_entity_owner(entity) == ft) {
+                                                       /* found an access to the outer frame */
+                                                       ir_entity_usage flags;
+
+                                                       flags  = get_entity_usage(entity);
+                                                       flags |= determine_entity_usage(succ, entity);
+                                                       set_entity_usage(entity, flags);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+
        /* now computed */
        irg->entity_usage_state = ir_entity_usage_computed;
 }
@@ -923,37 +1013,42 @@ static void init_entity_usage(ir_type * tp) {
 
        /* We have to be conservative: All external visible entities are unknown */
        for (i = get_compound_n_members(tp) - 1; i >= 0; --i) {
-               ir_entity       *entity = get_compound_member(tp, i);
-               ir_entity_usage  flags  = 0;
+               ir_entity       *ent  = get_compound_member(tp, i);
+               ir_entity_usage flags = ir_usage_none;
+               ir_visibility   vis   = get_entity_visibility(ent);
 
-               if (get_entity_visibility(entity) == visibility_external_visible
-                               || get_entity_visibility(entity) == visibility_external_allocated) {
+               if (vis == visibility_external_visible   ||
+                   vis == visibility_external_allocated ||
+                   get_entity_stickyness(ent) == stickyness_sticky) {
                        flags |= ir_usage_unknown;
                }
-
-               set_entity_usage(entity, flags);
+               set_entity_usage(ent, flags);
        }
 }
 
+/**
+ * Mark all entities used in the initializer as unknown usage.
+ *
+ * @param initializer  the initializer to check
+ */
 static void check_initializer_nodes(ir_initializer_t *initializer)
 {
-       switch (initializer->kind) {
-       case IR_INITIALIZER_CONST: {
-               ir_node *n = initializer->consti.value;
+       unsigned i;
+       ir_node  *n;
 
+       switch (initializer->kind) {
+       case IR_INITIALIZER_CONST:
                /* let's check if it's an address */
+               n = initializer->consti.value;
                if (is_Global(n)) {
                        ir_entity *ent = get_Global_entity(n);
                        set_entity_usage(ent, ir_usage_unknown);
                }
                return;
-       }
        case IR_INITIALIZER_TARVAL:
        case IR_INITIALIZER_NULL:
                return;
-       case IR_INITIALIZER_COMPOUND: {
-               size_t i;
-
+       case IR_INITIALIZER_COMPOUND:
                for (i = 0; i < initializer->compound.n_initializers; ++i) {
                        ir_initializer_t *sub_initializer
                                = initializer->compound.initializers[i];
@@ -961,12 +1056,12 @@ static void check_initializer_nodes(ir_initializer_t *initializer)
                }
                return;
        }
-       }
        panic("invalid initializer found");
 }  /* check_initializer_nodes */
 
 /**
- * Mark all entities used in the initializer for the given entity as address taken.
+ * Mark all entities used in the initializer for the given entity as unknown
+ * usage.
  *
  * @param ent  the entity
  */
@@ -1007,7 +1102,7 @@ static void check_initializer(ir_entity *ent) {
 
 
 /**
- * Mark all entities used in initializers as address taken.
+ * Mark all entities used in initializers as unknown usage.
  *
  * @param tp  a compound type
  */
@@ -1035,7 +1130,7 @@ static void print_entity_usage_flags(ir_type *tp) {
 
                if (flags == 0)
                        continue;
-               ir_printf("%+F:");
+               ir_printf("%+F:", ent);
                if (flags & ir_usage_address_taken)
                        printf(" address_taken");
                if (flags & ir_usage_read)
@@ -1128,14 +1223,10 @@ void assure_irp_globals_entity_usage_computed(void) {
 
 void firm_init_memory_disambiguator(void) {
        FIRM_DBG_REGISTER(dbg, "firm.ana.irmemory");
+       FIRM_DBG_REGISTER(dbgcall, "firm.opt.cc");
 }
 
 
-#include <adt/pmap.h>
-#include "typerep.h"
-
-DEBUG_ONLY(static firm_dbg_module_t *dbgcall = NULL;)
-
 /** Maps method types to cloned method types. */
 static pmap *mtp_map;
 
@@ -1192,8 +1283,6 @@ void mark_private_methods(void) {
        int i;
        int changed = 0;
 
-       FIRM_DBG_REGISTER(dbgcall, "firm.opt.cc");
-
        assure_irp_globals_entity_usage_computed();
 
        mtp_map = pmap_create();