add lower_const_code, make begnuas skip Id nodes
[libfirm] / ir / ana / irmemory.c
index 1585930..935d01f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
  *
  * This file is part of libFirm.
  *
@@ -41,6 +41,7 @@
 #include "irgwalk.h"
 #include "irprintf.h"
 #include "debug.h"
+#include "error.h"
 
 /** The debug handle. */
 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
@@ -282,6 +283,8 @@ static ir_alias_relation different_index(ir_node *idx1, ir_node *idx2, int size)
  */
 static ir_alias_relation different_sel_offsets(ir_node *sel1, ir_node *sel2) {
        /* seems to be broken */
+       (void) sel1;
+       (void) sel2;
 #if 0
        ir_entity *ent1 = get_Sel_entity(sel1);
        ir_entity *ent2 = get_Sel_entity(sel2);
@@ -335,12 +338,12 @@ static ir_alias_relation different_types(ir_node *adr1, ir_node *adr2)
 {
        ir_entity *ent1 = NULL, *ent2 = NULL;
 
-       if (is_SymConst(adr1) && get_SymConst_kind(adr1) == symconst_addr_ent)
+       if (is_SymConst_addr_ent(adr1))
                ent1 = get_SymConst_entity(adr1);
        else if (is_Sel(adr1))
                ent1 = get_Sel_entity(adr1);
 
-       if (is_SymConst(adr2) && get_SymConst_kind(adr2) == symconst_addr_ent)
+       if (is_SymConst_addr_ent(adr2))
                ent2 = get_SymConst_entity(adr2);
        else if (is_Sel(adr2))
                ent2 = get_Sel_entity(adr2);
@@ -455,22 +458,45 @@ static ir_alias_relation different_pointer(ir_node *adr1, ir_mode *mode1, ir_nod
 /**
  * Returns non-zero if a node is a routine parameter.
  *
- * @param node  the node to test
+ * @param node  the Proj node to test
  */
 static int is_arg_Proj(ir_node *node) {
-       if (! is_Proj(node))
-               return 0;
        node = get_Proj_pred(node);
        if (! is_Proj(node))
                return 0;
        return pn_Start_T_args == get_Proj_proj(node) && is_Start(get_Proj_pred(node));
 }  /* is_arg_Proj */
 
+/**
+ * Returns non-zero if a node is a result on a malloc-like routine.
+ *
+ * @param node  the Proj node to test
+ */
+static int is_malloc_Result(ir_node *node) {
+       node = get_Proj_pred(node);
+       if (! is_Proj(node))
+               return 0;
+       node = get_Proj_pred(node);
+       if (! is_Call(node))
+               return 0;
+       node = get_Call_ptr(node);
+       if (is_SymConst_addr_ent(node)) {
+               ir_entity *ent = get_SymConst_entity(node);
+
+               if (get_entity_additional_properties(ent) & mtp_property_malloc)
+                       return 1;
+               return 0;
+       }
+       return 0;
+}  /* is_malloc_Result */
+
 /**
  * Returns true if an address represents a global variable.
+ *
+ * @param irn  the node representing the address
  */
 static INLINE int is_global_var(ir_node *irn) {
-       return is_SymConst(irn) && get_SymConst_kind(irn) == symconst_addr_ent;
+       return is_SymConst_addr_ent(irn);
 }  /* is_global_var */
 
 /**
@@ -524,8 +550,7 @@ static ir_alias_relation _get_alias_relation(
                                /* equal entity addresses */
                                return sure_alias;
                        }
-               }
-               if (is_Sel(adr2)) {
+               } else if (is_Sel(adr2)) {
                        ir_node *base2 = find_base_adr(adr2, &ent2);
 
                        if (is_global_var(base2)) {
@@ -540,6 +565,18 @@ static ir_alias_relation _get_alias_relation(
                                /* the second one is a TLS variable so they are always
                                   different (R1 c) */
                                return no_alias;
+                       } else if (is_Proj(base2)) {
+                               if (is_malloc_Result(base2)) {
+                                       /* the second one is an offset from a result of a malloc like call, ie.
+                                          freshly allocated non-aliases heap memory, (R1 f) */
+                                       return no_alias;
+                               }
+                       }
+               } else if (is_Proj(adr2)) {
+                       if (is_malloc_Result(adr2)) {
+                               /* the second one is a result of a malloc like call, ie.
+                                  freshly allocated non-aliases heap memory, (R1 f) */
+                               return no_alias;
                        }
                }
 
@@ -574,14 +611,26 @@ static ir_alias_relation _get_alias_relation(
                                        /* the second one is a TLS variable so they are always
                                       different (R1 d) */
                                        return no_alias;
-                               } else if (is_arg_Proj(base2)) {
-                                       /* the second one is an offset from a parameter so they are
-                                          always different (R1 e) */
+                               } else if (is_Proj(base2)) {
+                                       if (is_arg_Proj(base2)) {
+                                               /* the second one is an offset from a parameter so they are
+                                                  always different (R1 e) */
+                                               return no_alias;
+                                       } else if (is_malloc_Result(base2)) {
+                                               /* the second one is an offset from a result of a malloc like call, ie.
+                                                  freshly allocated non-aliases heap memory (R1 g) */
+                                               return no_alias;
+                                       }
+                               }
+                       } else if (is_Proj(adr2)) {
+                               if (is_arg_Proj(adr2)) {
+                                       /* a local variable and a parameter are always different (R1 e) */
+                                       return no_alias;
+                               } else if (is_malloc_Result(adr2)) {
+                                       /* the second one is a result of a malloc like call, ie.
+                                          freshly allocated non-aliases heap memory (R1 g) */
                                        return no_alias;
                                }
-                       } else if (is_arg_Proj(adr2)) {
-                               /* a local variable and a parameter are always different (R1 e) */
-                               return no_alias;
                        }
                } else if (base1 == get_irg_tls(irg)) {
                        /* the first is a TLS variable */
@@ -589,34 +638,61 @@ static ir_alias_relation _get_alias_relation(
                                /* the second address is a Sel */
                                ir_node *base2 = find_base_adr(adr2, &ent2);
 
-                               if (base1 == base2)
+                               if (base1 == base2) {
                                        if (ent1 != ent2) {
                                                /* both addresses are tls variables and we know
                                               they are different (R1 a) */
+                                               return no_alias;
                                        } else {
                                                /* same tls var */
                                                return different_sel_offsets(adr1, adr2);
                                        }
-                               else if (base2 == get_irg_frame(irg)) {
+                               else if (base2 == get_irg_frame(irg)) {
                                        /* the first one is a tls variable, the second a local one,
                                           they are different (R1 d) */
                                        return no_alias;
+                               } else if (is_Proj(base2)) {
+                                       if (is_malloc_Result(base2)) {
+                                               /* the second one is an offset from a result of a malloc like call, ie.
+                                                  freshly allocated non-aliases heap memory (R1 h) */
+                                               return no_alias;
+                                       }
                                }
-                       }
-               } else if (is_arg_Proj(base1)) {
-                       /* the first one is an offset from a parameter */
-                       if (is_Sel(adr2)) {
-                               /* the second address is a Sel */
-                               ir_node *base2 = find_base_adr(adr2, &ent2);
-
-                               if (base2 == get_irg_frame(irg)) {
-                                       /* the second one is a local variable so they are always
-                                      different (R1 e) */
+                       } else if (is_Proj(adr2)) {
+                               if (is_malloc_Result(adr2)) {
+                                       /* the second one is an offset from a result of a malloc like call, ie.
+                                          freshly allocated non-aliases heap memory (R1 h) */
                                        return no_alias;
                                }
                        }
+               } else if (is_Proj(base1)) {
+                       if (is_arg_Proj(base1)) {
+                               /* the first one is an offset from a parameter */
+                               if (is_Sel(adr2)) {
+                                       /* the second address is a Sel */
+                                       ir_node *base2 = find_base_adr(adr2, &ent2);
+
+                                       if (base2 == get_irg_frame(irg)) {
+                                               /* the second one is a local variable so they are always
+                                                  different (R1 e) */
+                                               return no_alias;
+                                       } else if (is_Proj(base2)) {
+                                               if (is_malloc_Result(base2)) {
+                                                       /* the second one is an offset from a result of a malloc like call, ie.
+                                                          freshly allocated non-aliases heap memory (R1 í) */
+                                                       return no_alias;
+                                               }
+                                       }
+                               } else if (is_Proj(adr2)) {
+                                       if (is_malloc_Result(adr2)) {
+                                               /* the second one is a malloc like call, ie.
+                                                  freshly allocated non-aliases heap memory (R1 í) */
+                                               return no_alias;
+                                       }
+                               }
+                       }
                } else if (is_global_var(base1)) {
-                       /* the first one is a global variable */
+                       /* the first one is an offset from a global variable */
                        ent1 = get_SymConst_entity(base1);
                        if (is_Sel(adr2)) {
                                /* the second address is a Sel */
@@ -625,8 +701,7 @@ static ir_alias_relation _get_alias_relation(
                                if (base1 == base2) {
                                        /* same global var */
                                        return different_sel_offsets(adr1, adr2);
-                               }
-                               else if (base2 == get_irg_frame(irg)) {
+                               } else if (base2 == get_irg_frame(irg)) {
                                        /* the second one is a local variable so they are always
                                       different (R1 a) */
                                        return no_alias;
@@ -634,10 +709,16 @@ static ir_alias_relation _get_alias_relation(
                                        /* the second one is a TLS variable so they are always
                                       different (R1 a) */
                                        return no_alias;
-                               } else if (is_arg_Proj(base2)) {
-                                       if (get_entity_address_taken(ent1) == ir_address_not_taken) {
-                                               /* The address of the global variable was never taken, so
-                                                  the pointer cannot match (R2). */
+                               } else if (is_Proj(base2)) {
+                                       if (is_arg_Proj(base2)) {
+                                               if (get_entity_address_taken(ent1) == ir_address_not_taken) {
+                                                       /* The address of the global variable was never taken, so
+                                                          the pointer cannot match (R2). */
+                                                       return no_alias;
+                                               }
+                                       } else if (is_malloc_Result(base2)) {
+                                               /* the second one is an offset from a result of a malloc like call, ie.
+                                                  freshly allocated non-aliases heap memory (R1 g) */
                                                return no_alias;
                                        }
                                } else if (is_global_var(base2)) {
@@ -650,6 +731,10 @@ static ir_alias_relation _get_alias_relation(
                        }
                }
        } else {
+               /* Note: we cannot check for malloc result here, as we cannot be sure the result is not stored anywhere
+                  after getting if.
+                */
+
                /* some pointers, check if they have the same base buf constant offset */
                ir_alias_relation rel = different_pointer(adr1, mode1, adr2, mode2);
                if (rel != may_alias)
@@ -948,6 +1033,36 @@ static void init_taken_flag(ir_type * tp) {
        }
 }  /* init_taken_flag */
 
+static void check_initializer_nodes(ir_initializer_t *initializer)
+{
+       switch(initializer->kind) {
+       case IR_INITIALIZER_CONST: {
+               ir_node *n = initializer->consti.value;
+
+               /* let's check if it's an address */
+               if (is_SymConst_addr_ent(n)) {
+                       ir_entity *ent = get_SymConst_entity(n);
+                       set_entity_address_taken(ent, ir_address_taken);
+               }
+               return;
+       }
+       case IR_INITIALIZER_TARVAL:
+       case IR_INITIALIZER_NULL:
+               return;
+       case IR_INITIALIZER_COMPOUND: {
+               size_t i;
+
+               for(i = 0; i < initializer->compound.n_initializers; ++i) {
+                       ir_initializer_t *sub_initializer
+                               = initializer->compound.initializers[i];
+                       check_initializer_nodes(sub_initializer);
+               }
+               return;
+       }
+       }
+       panic("invalid initialzier found");
+}
+
 /**
  * Mark all entities used in the initializer for the given entity as address taken
  */
@@ -964,10 +1079,12 @@ static void check_initializer(ir_entity *ent) {
        if (is_Method_type(get_entity_type(ent)))
                return;
 
-       if (is_atomic_entity(ent)) {
+       if (ent->has_initializer) {
+               check_initializer_nodes(ent->attr.initializer);
+       } else if (is_atomic_entity(ent)) {
                /* let's check if it's an address */
                n = get_atomic_ent_value(ent);
-               if (is_SymConst(n) && get_SymConst_kind(n) == symconst_addr_ent) {
+               if (is_SymConst_addr_ent(n)) {
                        ir_entity *ent = get_SymConst_entity(n);
                        set_entity_address_taken(ent, ir_address_taken);
                }
@@ -976,7 +1093,7 @@ static void check_initializer(ir_entity *ent) {
                        n = get_compound_ent_value(ent, i);
 
                        /* let's check if it's an address */
-                       if (is_SymConst(n) && get_SymConst_kind(n) == symconst_addr_ent) {
+                       if (is_SymConst_addr_ent(n)) {
                                ir_entity *ent = get_SymConst_entity(n);
                                set_entity_address_taken(ent, ir_address_taken);
                        }
@@ -1024,7 +1141,7 @@ static void check_global_address(ir_node *irn, void *env) {
        ir_entity *ent;
        ir_address_taken_state state;
 
-       if (is_SymConst(irn) && get_SymConst_kind(irn) == symconst_addr_ent) {
+       if (is_SymConst_addr_ent(irn)) {
                /* A global. */
                ent = get_SymConst_entity(irn);
        } else if (is_Sel(irn) && get_Sel_ptr(irn) == tls) {
@@ -1115,6 +1232,7 @@ static ir_type *clone_type_and_cache(ir_type *tp) {
 
        res = clone_type_method(tp, prefix);
        pmap_insert(mtp_map, tp, res);
+       DB((dbgcall, LEVEL_2, "cloned type %+F into %+F\n", tp, res));
 
        return res;
 }  /* clone_type_and_cache */
@@ -1129,14 +1247,15 @@ static void update_calls_to_private(ir_node *call, void *env) {
 
                if (is_SymConst(ptr)) {
                        ir_entity *ent = get_SymConst_entity(ptr);
-                       ir_type *mtp = get_entity_type(ent);
                        ir_type *ctp = get_Call_type(call);
 
-                       if ((get_method_additional_properties(ctp) & mtp_property_private) == 0) {
-                               ctp = clone_type_and_cache(ctp);
-                               set_method_additional_property(ctp, mtp_property_private);
-                               set_Call_type(call, ctp);
-                               DB((dbgcall, LEVEL_1, "changed call to private method %+F\n", ent));
+                       if (get_entity_additional_properties(ent) & mtp_property_private) {
+                               if ((get_method_additional_properties(ctp) & mtp_property_private) == 0) {
+                                       ctp = clone_type_and_cache(ctp);
+                                       set_method_additional_property(ctp, mtp_property_private);
+                                       set_Call_type(call, ctp);
+                                       DB((dbgcall, LEVEL_1, "changed call to private method %+F\n", ent));
+                               }
                        }
                }
        }
@@ -1164,6 +1283,7 @@ void mark_private_methods(void) {
                        ir_type *mtp = get_entity_type(ent);
 
                        set_entity_additional_property(ent, mtp_property_private);
+                       DB((dbgcall, LEVEL_1, "found private method %+F\n", ent));
                        if ((get_method_additional_properties(mtp) & mtp_property_private) == 0) {
                                /* need a new type */
                                mtp = clone_type_and_cache(mtp);
@@ -1171,7 +1291,6 @@ void mark_private_methods(void) {
                                set_method_additional_property(mtp, mtp_property_private);
                                changed = 1;
                        }
-                       DB((dbgcall, LEVEL_1, "found private method %+F\n", ent));
                }
        }