- removed redundant checks
[libfirm] / ir / opt / ldstopt.c
index c5892e3..f5e2cb4 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.
  *
@@ -63,7 +63,7 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg;)
 #undef IMAX
 #define IMAX(a,b)      ((a) > (b) ? (a) : (b))
 
-#define MAX_PROJ       IMAX(pn_Load_max, pn_Store_max)
+#define MAX_PROJ       IMAX(IMAX(pn_Load_max, pn_Store_max), pn_Call_max)
 
 enum changes_t {
        DF_CHANGED = 1,       /**< data flow changed */
@@ -78,19 +78,11 @@ typedef struct _walk_env_t {
        unsigned changes;             /**< a bitmask of graph changes */
 } walk_env_t;
 
-/**
- * flags for Load/Store
- */
-enum ldst_flags_t {
-       LDST_VISITED = 1              /**< if set, this Load/Store is already visited */
-};
-
 /** A Load/Store info. */
 typedef struct _ldst_info_t {
        ir_node  *projs[MAX_PROJ];    /**< list of Proj's of this node */
        ir_node  *exc_block;          /**< the exception block if available */
        int      exc_idx;             /**< predecessor index in the exception block */
-       unsigned flags;               /**< flags */
        unsigned visited;             /**< visited counter for breaking loops */
 } ldst_info_t;
 
@@ -190,28 +182,20 @@ static unsigned update_exc(ldst_info_t *info, ir_node *block, int pos)
  */
 static void collect_nodes(ir_node *node, void *env)
 {
-       ir_op       *op = get_irn_op(node);
+       ir_opcode   opcode = get_irn_opcode(node);
        ir_node     *pred, *blk, *pred_blk;
        ldst_info_t *ldst_info;
        walk_env_t  *wenv = env;
 
-       if (op == op_Proj) {
-               ir_node *adr;
-               ir_op *op;
-
-               pred = get_Proj_pred(node);
-               op   = get_irn_op(pred);
+       if (opcode == iro_Proj) {
+               pred   = get_Proj_pred(node);
+               opcode = get_irn_opcode(pred);
 
-               if (op == op_Load) {
+               if (opcode == iro_Load || opcode == iro_Store || opcode == iro_Call) {
                        ldst_info = get_ldst_info(pred, &wenv->obst);
 
                        wenv->changes |= update_projs(ldst_info, node);
 
-                       if ((ldst_info->flags & LDST_VISITED) == 0) {
-                               adr = get_Load_ptr(pred);
-                               ldst_info->flags |= LDST_VISITED;
-                       }
-
                        /*
                         * Place the Proj's to the same block as the
                         * predecessor Load. This is always ok and prevents
@@ -224,30 +208,8 @@ static void collect_nodes(ir_node *node, void *env)
                                wenv->changes |= DF_CHANGED;
                                set_nodes_block(node, pred_blk);
                        }
-               } else if (op == op_Store) {
-                       ldst_info = get_ldst_info(pred, &wenv->obst);
-
-                       wenv->changes |= update_projs(ldst_info, node);
-
-                       if ((ldst_info->flags & LDST_VISITED) == 0) {
-                               adr = get_Store_ptr(pred);
-                               ldst_info->flags |= LDST_VISITED;
-                       }
-
-                       /*
-                       * Place the Proj's to the same block as the
-                       * predecessor Store. This is always ok and prevents
-                       * "non-SSA" form after optimizations if the Proj
-                       * is in a wrong block.
-                       */
-                       blk      = get_nodes_block(node);
-                       pred_blk = get_nodes_block(pred);
-                       if (blk != pred_blk) {
-                               wenv->changes |= DF_CHANGED;
-                               set_nodes_block(node, pred_blk);
-                       }
                }
-       } else if (op == op_Block) {
+       } else if (opcode == iro_Block) {
                int i;
 
                for (i = get_Block_n_cfgpreds(node) - 1; i >= 0; --i) {
@@ -274,7 +236,8 @@ static void collect_nodes(ir_node *node, void *env)
                        else if (is_irn_forking(pred))
                                bl_info->flags |= BLOCK_HAS_COND;
 
-                       if (is_exc && (get_irn_op(pred) == op_Load || get_irn_op(pred) == op_Store)) {
+                       opcode = get_irn_opcode(pred);
+                       if (is_exc && (opcode == iro_Load || opcode == iro_Store || opcode == iro_Call)) {
                                ldst_info = get_ldst_info(pred, &wenv->obst);
 
                                wenv->changes |= update_exc(ldst_info, node, i);
@@ -293,14 +256,12 @@ static void collect_nodes(ir_node *node, void *env)
 static ir_entity *find_constant_entity(ir_node *ptr)
 {
        for (;;) {
-               ir_op *op = get_irn_op(ptr);
-
-               if (op == op_SymConst && (get_SymConst_kind(ptr) == symconst_addr_ent)) {
+               if (is_SymConst(ptr) && get_SymConst_kind(ptr) == symconst_addr_ent) {
                        ir_entity *ent = get_SymConst_entity(ptr);
                        if (variability_constant == get_entity_variability(ent))
                                return ent;
                        return NULL;
-               } else if (op == op_Sel) {
+               } else if (is_Sel(ptr)) {
                        ir_entity *ent = get_Sel_entity(ptr);
                        ir_type   *tp  = get_entity_owner(ent);
 
@@ -346,6 +307,31 @@ static ir_entity *find_constant_entity(ir_node *ptr)
 
                        /* try next */
                        ptr = get_Sel_ptr(ptr);
+               } else if (is_Add(ptr)) {
+                       ir_node *l = get_Add_left(ptr);
+                       ir_node *r = get_Add_right(ptr);
+
+                       if (get_irn_mode(l) == get_irn_mode(ptr) && is_Const(r))
+                               ptr = l;
+                       else if (get_irn_mode(r) == get_irn_mode(ptr) && is_Const(l))
+                               ptr = r;
+                       else
+                               return NULL;
+
+                       /* for now, we support only one addition, reassoc should fold all others */
+                       if (! is_SymConst(ptr) && !is_Sel(ptr))
+                               return NULL;
+               } else if (is_Sub(ptr)) {
+                       ir_node *l = get_Sub_left(ptr);
+                       ir_node *r = get_Sub_right(ptr);
+
+                       if (get_irn_mode(l) == get_irn_mode(ptr) &&     is_Const(r))
+                               ptr = l;
+                       else
+                               return NULL;
+                       /* for now, we support only one substraction, reassoc should fold all others */
+                       if (! is_SymConst(ptr) && !is_Sel(ptr))
+                               return NULL;
                } else
                        return NULL;
        }
@@ -370,10 +356,12 @@ static long get_Sel_array_index_long(ir_node *n, int dim) {
  */
 static compound_graph_path *rec_get_accessed_path(ir_node *ptr, int depth) {
        compound_graph_path *res = NULL;
-       ir_entity           *root, *field;
-       int                 path_len, pos;
+       ir_entity           *root, *field, *ent;
+       int                 path_len, pos, idx;
+       tarval              *tv;
+       ir_type             *tp;
 
-       if (get_irn_op(ptr) == op_SymConst) {
+       if (is_SymConst(ptr)) {
                /* a SymConst. If the depth is 0, this is an access to a global
                 * entity and we don't need a component path, else we know
                 * at least it's length.
@@ -381,10 +369,11 @@ static compound_graph_path *rec_get_accessed_path(ir_node *ptr, int depth) {
                assert(get_SymConst_kind(ptr) == symconst_addr_ent);
                root = get_SymConst_entity(ptr);
                res = (depth == 0) ? NULL : new_compound_graph_path(get_entity_type(root), depth);
-       } else {
-               assert(get_irn_op(ptr) == op_Sel);
+       } else if (is_Sel(ptr)) {
                /* it's a Sel, go up until we find the root */
                res = rec_get_accessed_path(get_Sel_ptr(ptr), depth+1);
+               if (res == NULL)
+                       return NULL;
 
                /* fill up the step in the path at the current position */
                field    = get_Sel_entity(ptr);
@@ -396,17 +385,310 @@ static compound_graph_path *rec_get_accessed_path(ir_node *ptr, int depth) {
                        assert(get_Sel_n_indexs(ptr) == 1 && "multi dim arrays not implemented");
                        set_compound_graph_path_array_index(res, pos, get_Sel_array_index_long(ptr, 0));
                }
+       } else if (is_Add(ptr)) {
+               ir_node *l = get_Add_left(ptr);
+               ir_node *r = get_Add_right(ptr);
+               ir_mode *mode;
+
+               if (is_Const(r)) {
+                       ptr = l;
+                       tv  = get_Const_tarval(r);
+               } else {
+                       ptr = r;
+                       tv  = get_Const_tarval(l);
+               }
+ptr_arith:
+               mode = get_tarval_mode(tv);
+
+               /* ptr must be a Sel or a SymConst, this was checked in find_constant_entity() */
+               if (is_Sel(ptr)) {
+                       field = get_Sel_entity(ptr);
+               } else {
+                       field = get_SymConst_entity(ptr);
+               }
+               idx = 0;
+               for (ent = field;;) {
+                       unsigned size;
+                       tarval   *sz, *tv_index, *tlower, *tupper;
+                       long     index;
+                       ir_node  *bound;
+
+                       tp = get_entity_type(ent);
+                       if (! is_Array_type(tp))
+                               break;
+                       ent = get_array_element_entity(tp);
+                       size = get_type_size_bytes(get_entity_type(ent));
+                       sz   = new_tarval_from_long(size, mode);
+
+                       tv_index = tarval_div(tv, sz);
+                       tv       = tarval_mod(tv, sz);
+
+                       if (tv_index == tarval_bad || tv == tarval_bad)
+                               return NULL;
+
+                       assert(get_array_n_dimensions(tp) == 1 && "multiarrays not implemented");
+                       bound  = get_array_lower_bound(tp, 0);
+                       tlower = computed_value(bound);
+                       bound  = get_array_upper_bound(tp, 0);
+                       tupper = computed_value(bound);
+
+                       if (tlower == tarval_bad || tupper == tarval_bad)
+                               return NULL;
+
+                       if (tarval_cmp(tv_index, tlower) & pn_Cmp_Lt)
+                               return NULL;
+                       if (tarval_cmp(tupper, tv_index) & pn_Cmp_Lt)
+                               return NULL;
+
+                       /* ok, bounds check finished */
+                       index = get_tarval_long(tv_index);
+                       ++idx;
+               }
+               if (! tarval_is_null(tv)) {
+                       /* access to some struct/union member */
+                       return NULL;
+               }
+
+               /* should be at least ONE array */
+               if (idx == 0)
+                       return NULL;
+
+               res = rec_get_accessed_path(ptr, depth + idx);
+               if (res == NULL)
+                       return NULL;
+
+               path_len = get_compound_graph_path_length(res);
+               pos      = path_len - depth - idx;
+
+               for (ent = field;;) {
+                       unsigned size;
+                       tarval   *sz, *tv_index;
+                       long     index;
+
+                       tp = get_entity_type(ent);
+                       if (! is_Array_type(tp))
+                               break;
+                       ent = get_array_element_entity(tp);
+                       set_compound_graph_path_node(res, pos, ent);
+
+                       size = get_type_size_bytes(get_entity_type(ent));
+                       sz   = new_tarval_from_long(size, mode);
+
+                       tv_index = tarval_div(tv, sz);
+                       tv       = tarval_mod(tv, sz);
+
+                       /* worked above, should work again */
+                       assert(tv_index != tarval_bad && tv != tarval_bad);
+
+                       /* bounds already checked above */
+                       index = get_tarval_long(tv_index);
+                       set_compound_graph_path_array_index(res, pos, index);
+                       ++pos;
+               }
+       } else if (is_Sub(ptr)) {
+               ir_node *l = get_Sub_left(ptr);
+               ir_node *r = get_Sub_right(ptr);
+
+               ptr = l;
+               tv  = get_Const_tarval(r);
+               tv  = tarval_neg(tv);
+               goto ptr_arith;
        }
        return res;
 }  /* rec_get_accessed_path */
 
-/** 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.
+/**
+ * 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);
 }  /* get_accessed_path */
 
+typedef struct path_entry {
+       ir_entity         *ent;
+       struct path_entry *next;
+       long              index;
+} path_entry;
+
+static ir_node *rec_find_compound_ent_value(ir_node *ptr, path_entry *next) {
+       path_entry       entry, *p;
+       ir_entity        *ent, *field;
+       ir_initializer_t *initializer;
+       tarval           *tv;
+       ir_type          *tp;
+       unsigned         n;
+
+       entry.next = next;
+       if (is_SymConst(ptr)) {
+               /* found the root */
+               ent         = get_SymConst_entity(ptr);
+               initializer = get_entity_initializer(ent);
+               for (p = next; p != NULL;) {
+                       if (initializer->kind != IR_INITIALIZER_COMPOUND)
+                               return NULL;
+                       n  = get_initializer_compound_n_entries(initializer);
+                       tp = get_entity_type(ent);
+
+                       if (is_Array_type(tp)) {
+                               ent = get_array_element_entity(tp);
+                               if (ent != p->ent) {
+                                       /* a missing [0] */
+                                       if (0 >= n)
+                                               return NULL;
+                                       initializer = get_initializer_compound_value(initializer, 0);
+                                       continue;
+                               }
+                       }
+                       if (p->index >= n)
+                               return NULL;
+                       initializer = get_initializer_compound_value(initializer, p->index);
+
+                       ent = p->ent;
+                       p   = p->next;
+               }
+               tp = get_entity_type(ent);
+               while (is_Array_type(tp)) {
+                       ent = get_array_element_entity(tp);
+                       tp = get_entity_type(ent);
+                       /* a missing [0] */
+                       n  = get_initializer_compound_n_entries(initializer);
+                       if (0 >= n)
+                               return NULL;
+                       initializer = get_initializer_compound_value(initializer, 0);
+               }
+
+               switch (initializer->kind) {
+               case IR_INITIALIZER_CONST:
+                       return get_initializer_const_value(initializer);
+               case IR_INITIALIZER_TARVAL:
+               case IR_INITIALIZER_NULL:
+               default:
+                       return NULL;
+               }
+       } else if (is_Sel(ptr)) {
+               entry.ent = field = get_Sel_entity(ptr);
+               tp = get_entity_owner(field);
+               if (is_Array_type(tp)) {
+                       assert(get_Sel_n_indexs(ptr) == 1 && "multi dim arrays not implemented");
+                       entry.index = get_Sel_array_index_long(ptr, 0) - get_array_lower_bound_int(tp, 0);
+               } else {
+                       int i, n_members = get_compound_n_members(tp);
+                       for (i = 0; i < n_members; ++i) {
+                               if (get_compound_member(tp, i) == field)
+                                       break;
+                       }
+                       if (i >= n_members) {
+                               /* not found: should NOT happen */
+                               return NULL;
+                       }
+                       entry.index = i;
+               }
+               return rec_find_compound_ent_value(get_Sel_ptr(ptr), &entry);
+       }  else if (is_Add(ptr)) {
+               ir_node  *l = get_Add_left(ptr);
+               ir_node  *r = get_Add_right(ptr);
+               ir_mode  *mode;
+               unsigned pos;
+
+               if (is_Const(r)) {
+                       ptr = l;
+                       tv  = get_Const_tarval(r);
+               } else {
+                       ptr = r;
+                       tv  = get_Const_tarval(l);
+               }
+ptr_arith:
+               mode = get_tarval_mode(tv);
+
+               /* ptr must be a Sel or a SymConst, this was checked in find_constant_entity() */
+               if (is_Sel(ptr)) {
+                       field = get_Sel_entity(ptr);
+               } else {
+                       field = get_SymConst_entity(ptr);
+               }
+
+               /* count needed entries */
+               pos = 0;
+               for (ent = field;;) {
+                       tp = get_entity_type(ent);
+                       if (! is_Array_type(tp))
+                               break;
+                       ent = get_array_element_entity(tp);
+                       ++pos;
+               }
+               /* should be at least ONE entry */
+               if (pos == 0)
+                       return NULL;
+
+               /* allocate the right number of entries */
+               NEW_ARR_A(path_entry, p, pos);
+
+               /* fill them up */
+               pos = 0;
+               for (ent = field;;) {
+                       unsigned size;
+                       tarval   *sz, *tv_index, *tlower, *tupper;
+                       long     index;
+                       ir_node  *bound;
+
+                       tp = get_entity_type(ent);
+                       if (! is_Array_type(tp))
+                               break;
+                       ent = get_array_element_entity(tp);
+                       p[pos].ent  = ent;
+                       p[pos].next = &p[pos + 1];
+
+                       size = get_type_size_bytes(get_entity_type(ent));
+                       sz   = new_tarval_from_long(size, mode);
+
+                       tv_index = tarval_div(tv, sz);
+                       tv       = tarval_mod(tv, sz);
+
+                       if (tv_index == tarval_bad || tv == tarval_bad)
+                               return NULL;
+
+                       assert(get_array_n_dimensions(tp) == 1 && "multiarrays not implemented");
+                       bound  = get_array_lower_bound(tp, 0);
+                       tlower = computed_value(bound);
+                       bound  = get_array_upper_bound(tp, 0);
+                       tupper = computed_value(bound);
+
+                       if (tlower == tarval_bad || tupper == tarval_bad)
+                               return NULL;
+
+                       if (tarval_cmp(tv_index, tlower) & pn_Cmp_Lt)
+                               return NULL;
+                       if (tarval_cmp(tupper, tv_index) & pn_Cmp_Lt)
+                               return NULL;
+
+                       /* ok, bounds check finished */
+                       index = get_tarval_long(tv_index);
+                       p[pos].index = index;
+                       ++pos;
+               }
+               if (! tarval_is_null(tv)) {
+                       /* hmm, wrong access */
+                       return NULL;
+               }
+               p[pos - 1].next = next;
+               return rec_find_compound_ent_value(ptr, p);
+       } else if (is_Sub(ptr)) {
+               ir_node *l = get_Sub_left(ptr);
+               ir_node *r = get_Sub_right(ptr);
+
+               ptr = l;
+               tv  = get_Const_tarval(r);
+               tv  = tarval_neg(tv);
+               goto ptr_arith;
+       }
+       return NULL;
+}
+
+static ir_node *find_compound_ent_value(ir_node *ptr) {
+       return rec_find_compound_ent_value(ptr, NULL);
+}
+
 /* forward */
 static void reduce_adr_usage(ir_node *ptr);
 
@@ -428,7 +710,7 @@ static void handle_load_update(ir_node *load) {
                exchange(info->projs[pn_Load_M], mem);
                if (info->projs[pn_Load_X_regular])
                        exchange(info->projs[pn_Load_X_regular], new_r_Jmp(current_ir_graph, get_nodes_block(load)));
-               exchange(load, new_Bad());
+               kill_node(load);
                reduce_adr_usage(ptr);
        }
 }  /* handle_load_update */
@@ -472,9 +754,30 @@ static int can_use_stored_value(ir_mode *old_mode, ir_mode *new_mode) {
 }  /* can_use_stored_value */
 
 /**
- * Follow the memory chain as long as there are only Loads
- * and alias free Stores and try to replace current Load or Store
- * by a previous ones.
+ * Check whether a Call is at least pure, ie. does only read memory.
+ */
+static unsigned is_Call_pure(ir_node *call) {
+       ir_type *call_tp = get_Call_type(call);
+       unsigned prop = get_method_additional_properties(call_tp);
+
+       /* check first the call type */
+       if ((prop & (mtp_property_const|mtp_property_pure)) == 0) {
+               /* try the called entity */
+               ir_node *ptr = get_Call_ptr(call);
+
+               if (is_Global(ptr)) {
+                       ir_entity *ent = get_Global_entity(ptr);
+
+                       prop = get_entity_additional_properties(ent);
+               }
+       }
+       return (prop & (mtp_property_const|mtp_property_pure)) != 0;
+}  /* is_Call_pure */
+
+/**
+ * Follow the memory chain as long as there are only Loads,
+ * alias free Stores, and constant Calls and try to replace the
+ * current Load by a previous ones.
  * Note that in unreachable loops it might happen that we reach
  * load again, as well as we can fall into a cycle.
  * We break such cycles using a special visited flag.
@@ -539,7 +842,7 @@ static unsigned follow_Mem_chain(ir_node *load, ir_node *curr) {
                                if (info->projs[pn_Load_res])
                                        exchange(info->projs[pn_Load_res], value);
 
-                               exchange(load, new_Bad());
+                               kill_node(load);
                                reduce_adr_usage(ptr);
                                return res | DF_CHANGED;
                        }
@@ -588,7 +891,7 @@ static unsigned follow_Mem_chain(ir_node *load, ir_node *curr) {
                                        res |= CF_CHANGED;
                                }
 
-                               exchange(load, new_Bad());
+                               kill_node(load);
                                reduce_adr_usage(ptr);
                                return res |= DF_CHANGED;
                        }
@@ -602,11 +905,20 @@ static unsigned follow_Mem_chain(ir_node *load, ir_node *curr) {
                                get_irn_mode(get_Store_value(pred)),
                                ptr, load_mode);
                        /* if the might be an alias, we cannot pass this Store */
-                       if (rel != no_alias)
+                       if (rel != ir_no_alias)
                                break;
                        pred = skip_Proj(get_Store_mem(pred));
-               } else if (get_irn_op(pred) == op_Load) {
+               } else if (is_Load(pred)) {
                        pred = skip_Proj(get_Load_mem(pred));
+               } else if (is_Call(pred)) {
+                       if (is_Call_pure(pred)) {
+                               /* The called graph is at least pure, so there are no Store's
+                                  in it. We can handle it like a Load and skip it. */
+                               pred = skip_Proj(get_Call_mem(pred));
+                       } else {
+                               /* there might be Store's in the graph, stop here */
+                               break;
+                       }
                } else {
                        /* follow only Load chains */
                        break;
@@ -707,7 +1019,7 @@ static unsigned optimize_load(ir_node *load)
                        exchange(info->projs[pn_Load_X_regular], new_r_Jmp(current_ir_graph, get_nodes_block(load)));
                        res |= CF_CHANGED;
                }
-               exchange(load, new_Bad());
+               kill_node(load);
                reduce_adr_usage(ptr);
                return res | DF_CHANGED;
        }
@@ -733,7 +1045,7 @@ static unsigned optimize_load(ir_node *load)
                if (info->projs[pn_Load_res])
                        exchange(info->projs[pn_Load_res], new_node);
 
-               exchange(load, new_Bad());
+               kill_node(load);
                reduce_adr_usage(ptr);
                return res | DF_CHANGED;
        }
@@ -783,34 +1095,26 @@ static unsigned optimize_load(ir_node *load)
                                                        res |= DF_CHANGED;
                                                }
                                        }
-                                       exchange(load, new_Bad());
+                                       kill_node(load);
                                        reduce_adr_usage(ptr);
                                        return res;
                                } else {
-                                       compound_graph_path *path = get_accessed_path(ptr);
-
-                                       if (path) {
-                                               ir_node *c;
-
-                                               assert(is_proper_compound_graph_path(path, get_compound_graph_path_length(path)-1));
-                                               /*
-                                               {
-                                                       int j;
-                                                       for (j = 0; j < get_compound_graph_path_length(path); ++j) {
-                                                               ir_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");
-                                               }
-                                               */
-
-                                               c = get_compound_ent_value_by_path(ent, path);
-                                               free_compound_graph_path(path);
+                                       ir_node *c = NULL;
+                                       if (ent->has_initializer) {
+                                               /* new style initializer */
+                                               c = find_compound_ent_value(ptr);
+                                       } else {
+                                               /* old style initializer */
+                                               compound_graph_path *path = get_accessed_path(ptr);
 
-                                               /* printf("  cons: "); DDMN(c); */
+                                               if (path) {
+                                                       assert(is_proper_compound_graph_path(path, get_compound_graph_path_length(path)-1));
 
+                                                       c = get_compound_ent_value_by_path(ent, path);
+                                                       free_compound_graph_path(path);
+                                               }
+                                       }
+                                       if (c != NULL) {
                                                if (info->projs[pn_Load_M]) {
                                                        exchange(info->projs[pn_Load_M], mem);
                                                        res |= DF_CHANGED;
@@ -819,7 +1123,7 @@ static unsigned optimize_load(ir_node *load)
                                                        exchange(info->projs[pn_Load_res], copy_const_value(get_irn_dbg_info(load), c));
                                                        res |= DF_CHANGED;
                                                }
-                                               exchange(load, new_Bad());
+                                               kill_node(load);
                                                reduce_adr_usage(ptr);
                                                return res;
                                        } else {
@@ -828,8 +1132,8 @@ static unsigned optimize_load(ir_node *load)
                                                Reflectiontest.
                                                printf(">>>>>>>>>>>>> Found access to constant entity %s in function %s\n", get_entity_name(ent),
                                                get_entity_name(get_irg_entity(current_ir_graph)));
-                                               printf("  load: "); DDMN(load);
-                                               printf("  ptr:  "); DDMN(ptr);
+                                               ir_printf("  load: %+F\n", load);
+                                               ir_printf("  ptr:  %+F\n", ptr);
                                                */
                                        }
                                }
@@ -894,7 +1198,7 @@ static unsigned follow_Mem_chain_for_Store(ir_node *store, ir_node *curr) {
                    get_nodes_MacroBlock(pred) == mblk &&
                    is_completely_overwritten(get_irn_mode(get_Store_value(pred)), mode)) {
                        /*
-                        * a Store after a Store in the same block -- a write after write.
+                        * a Store after a Store in the same MacroBlock -- a write after write.
                         * We may remove the first Store, if it does not have an exception handler.
                         *
                         * TODO: What, if both have the same exception handler ???
@@ -902,20 +1206,22 @@ static unsigned follow_Mem_chain_for_Store(ir_node *store, ir_node *curr) {
                        if (get_Store_volatility(pred) != volatility_is_volatile && !pred_info->projs[pn_Store_X_except]) {
                                DBG_OPT_WAW(pred, store);
                                exchange(pred_info->projs[pn_Store_M], get_Store_mem(pred));
-                               exchange(pred, new_Bad());
+                               kill_node(pred);
                                reduce_adr_usage(ptr);
                                return DF_CHANGED;
                        }
                } else if (is_Load(pred) && get_Load_ptr(pred) == ptr &&
                           value == pred_info->projs[pn_Load_res]) {
                        /*
-                        * a Store of a value after a Load -- a write after read.
-                        * We may remove the second Store, if it does not have an exception handler.
+                        * a Store of a value just loaded from the same address
+                        * -- a write after read.
+                        * We may remove the Store, if it does not have an exception
+                        * handler.
                         */
                        if (! info->projs[pn_Store_X_except]) {
                                DBG_OPT_WAR(store, pred);
                                exchange(info->projs[pn_Store_M], mem);
-                               exchange(store, new_Bad());
+                               kill_node(store);
                                reduce_adr_usage(ptr);
                                return DF_CHANGED;
                        }
@@ -929,10 +1235,16 @@ static unsigned follow_Mem_chain_for_Store(ir_node *store, ir_node *curr) {
                                get_irn_mode(get_Store_value(pred)),
                                ptr, mode);
                        /* if the might be an alias, we cannot pass this Store */
-                       if (rel != no_alias)
+                       if (rel != ir_no_alias)
                                break;
                        pred = skip_Proj(get_Store_mem(pred));
-               } else if (get_irn_op(pred) == op_Load) {
+               } else if (is_Load(pred)) {
+                       ir_alias_relation rel = get_alias_relation(
+                               current_ir_graph, get_Load_ptr(pred), get_Load_mode(pred),
+                               ptr, mode);
+                       if (rel != ir_no_alias)
+                               break;
+
                        pred = skip_Proj(get_Load_mem(pred));
                } else {
                        /* follow only Load chains */
@@ -980,6 +1292,7 @@ static unsigned optimize_store(ir_node *store) {
 
        /* follow the memory chain as long as there are only Loads */
        INC_MASTER();
+
        return follow_Mem_chain_for_Store(store, skip_Proj(mem));
 }  /* optimize_store */
 
@@ -1029,7 +1342,7 @@ static unsigned optimize_phi(ir_node *phi, walk_env_t *wenv)
 
        store = skip_Proj(projM);
        old_store = store;
-       if (get_irn_op(store) != op_Store)
+       if (!is_Store(store))
                return 0;
 
        block = get_nodes_block(store);
@@ -1305,9 +1618,12 @@ struct phi_entry {
 };
 
 /**
- * Move loops out of loops if possible
+ * Move loops out of loops if possible.
+ *
+ * @param pscc   the loop described by an SCC
+ * @param env    the loop environment
  */
-static void move_loads_in_loops(scc *pscc, loop_env *env) {
+static void move_loads_out_of_loops(scc *pscc, loop_env *env) {
        ir_node   *phi, *load, *next, *other, *next_other;
        ir_entity *ent;
        int       j;
@@ -1355,10 +1671,10 @@ static void move_loads_in_loops(scc *pscc, loop_env *env) {
                        if (info->projs[pn_Load_res] == NULL || info->projs[pn_Load_X_regular] != NULL || info->projs[pn_Load_X_except] != NULL)
                                continue;
 
-                       /* for now, we can only handle Load(SymConst) */
-                       if (! is_SymConst(ptr) || get_SymConst_kind(ptr) != symconst_addr_ent)
+                       /* for now, we can only handle Load(Global) */
+                       if (! is_Global(ptr))
                                continue;
-                       ent = get_SymConst_entity(ptr);
+                       ent = get_Global_entity(ptr);
                        load_mode = get_Load_mode(load);
                        for (other = pscc->head; other != NULL; other = next_other) {
                                node_entry *ne = get_irn_ne(other, env);
@@ -1371,9 +1687,10 @@ static void move_loads_in_loops(scc *pscc, loop_env *env) {
                                                get_irn_mode(get_Store_value(other)),
                                                ptr, load_mode);
                                        /* if the might be an alias, we cannot pass this Store */
-                                       if (rel != no_alias)
+                                       if (rel != ir_no_alias)
                                                break;
                                }
+                               /* only pure Calls are allowed here, so ignore them */
                        }
                        if (other == NULL) {
                                ldst_info_t *ninfo;
@@ -1414,7 +1731,7 @@ static void move_loads_in_loops(scc *pscc, loop_env *env) {
                        }
                }
        }
-}  /* move_loads_in_loops */
+}  /* move_loads_out_of_loops */
 
 /**
  * Process a loop SCC.
@@ -1458,8 +1775,15 @@ static void process_loop(scc *pscc, loop_env *env) {
                next = e->next;
                switch (get_irn_opcode(irn)) {
                case iro_Call:
+                       if (is_Call_pure(irn)) {
+                               /* pure calls can be treated like loads */
+                               only_phi = 0;
+                               break;
+                       }
+                       /* non-pure calls must be handle like may-alias Stores */
+                       goto fail;
                case iro_CopyB:
-                       /* cannot handle Calls or CopyB yet */
+                       /* cannot handle CopyB yet */
                        goto fail;
                case iro_Load:
                        process = 1;
@@ -1529,7 +1853,7 @@ static void process_loop(scc *pscc, loop_env *env) {
        }
        DB((dbg, LEVEL_2, "\n"));
 
-       move_loads_in_loops(pscc, env);
+       move_loads_out_of_loops(pscc, env);
 
 fail:
        ;
@@ -1661,6 +1985,7 @@ static void do_dfs(ir_graph *irg, loop_env *env) {
        for (i = get_Block_n_cfgpreds(endblk) - 1; i >= 0; --i) {
                ir_node *pred = get_Block_cfgpred(endblk, i);
 
+               pred = skip_Proj(pred);
                if (is_Return(pred))
                        dfs(get_Return_mem(pred), env);
                else if (is_Raise(pred))
@@ -1686,7 +2011,7 @@ static void do_dfs(ir_graph *irg, loop_env *env) {
 /**
  * Initialize new phase data. We do this always explicit, so return NULL here
  */
-static void *init_loop_data(ir_phase *ph, ir_node *irn, void *data) {
+static void *init_loop_data(ir_phase *ph, const ir_node *irn, void *data) {
        (void)ph;
        (void)irn;
        (void)data;