move load mode shrinking into ldst phase
[libfirm] / ir / opt / opt_ldst.c
1 /*
2  * Copyright (C) 1995-2011 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Dataflow driven Load/Store optimizations, uses some ideas from
23  *          VanDrunen's LEPRE
24  * @author  Michael Beck
25  */
26 #include "config.h"
27
28 #include "irnode_t.h"
29 #include "irflag_t.h"
30 #include "array_t.h"
31 #include "ircons.h"
32 #include "irdom.h"
33 #include "irgmod.h"
34 #include "irgwalk.h"
35 #include "irouts.h"
36 #include "irgraph.h"
37 #include "irgopt.h"
38 #include "iropt.h"
39 #include "iroptimize.h"
40 #include "irnodehashmap.h"
41 #include "raw_bitset.h"
42 #include "debug.h"
43 #include "error.h"
44 #include "irpass.h"
45
46 /* maximum number of output Proj's */
47 #define MAX_PROJ ((long)pn_Load_max > (long)pn_Store_max ? (long)pn_Load_max : (long)pn_Store_max)
48
49 /**
50  * Mapping an address to an dense ID.
51  */
52 typedef struct address_entry_t {
53         unsigned id;          /**< The ID */
54 } address_entry;
55
56 /**
57  * Memop-flags.
58  */
59 enum memop_flags {
60         FLAG_KILL_ALL    = 1, /**< KILL all addresses */
61         FLAG_KILLED_NODE = 2, /**< this node was killed */
62         FLAG_EXCEPTION   = 4, /**< this node has exception flow */
63         FLAG_IGNORE      = 8, /**< ignore this node (volatile or other) */
64 };
65
66 /**
67  * A value: This represents a value stored at a given address in
68  * memory. Do not confuse with values from value numbering.
69  */
70 typedef struct value_t value_t;
71 struct value_t {
72         ir_node  *address;    /**< the address of this value */
73         ir_node  *value;      /**< the value itself */
74         ir_mode  *mode;       /**< the mode of the value */
75         unsigned id;          /**< address id */
76 };
77
78 /**
79  * A memop describes an memory-related operation.
80  * These are Loads/Store and all other ops that might modify
81  * memory (Calls, CopyB) or causing exceptions.
82  */
83 typedef struct memop_t memop_t;
84 struct memop_t {
85         value_t  value;      /**< the value of this memop: only defined for Load/Store */
86         ir_node  *node;      /**< the memory op itself */
87         ir_node  *mem;       /**< the memory FROM this node */
88         ir_node  *replace;   /**< the replacement node if this memop is replaced */
89         memop_t  *next;      /**< links to the next memory op in the block in forward order. */
90         memop_t  *prev;      /**< links to the previous memory op in the block in forward order. */
91         unsigned flags;      /**< memop flags */
92         ir_node  *projs[MAX_PROJ+1]; /**< Projs of this memory op */
93 };
94
95 /**
96  * Additional data for every basic block.
97  */
98 typedef struct block_t block_t;
99 struct block_t {
100         memop_t  *memop_forward;     /**< topologically sorted list of memory ops in this block */
101         memop_t  *memop_backward;    /**< last memop in the list */
102         unsigned *avail_out;         /**< out-set of available addresses */
103         memop_t  **id_2_memop_avail; /**< maps avail address ids to memops */
104         unsigned *anticL_in;         /**< in-set of anticipated Load addresses */
105         memop_t  **id_2_memop_antic; /**< maps anticipated address ids to memops */
106         ir_node  *block;             /**< the associated block */
107         block_t  *forward_next;      /**< next block entry for forward iteration */
108         block_t  *backward_next;     /**< next block entry for backward iteration */
109         memop_t  *avail;             /**< used locally for the avail map */
110         memop_t  **trans_results;    /**< used to cached translated nodes due antic calculation. */
111 };
112
113 /**
114  * Metadata for this pass.
115  */
116 typedef struct ldst_env_t {
117         struct obstack   obst;             /**< obstack for temporary data */
118         ir_nodehashmap_t adr_map;          /**< Map addresses to */
119         block_t         *forward;          /**< Inverse post-order list of all blocks Start->End */
120         block_t         *backward;         /**< Inverse post-order list of all blocks End->Start */
121         ir_node         *start_bl;         /**< start block of the current graph */
122         ir_node         *end_bl;           /**< end block of the current graph */
123         unsigned        *curr_set;         /**< current set of addresses */
124         memop_t         **curr_id_2_memop; /**< current map of address ids to memops */
125         unsigned        curr_adr_id;       /**< number for address mapping */
126         unsigned        n_mem_ops;         /**< number of memory operations (Loads/Stores) */
127         size_t          rbs_size;          /**< size of all bitsets in bytes */
128         int             max_cfg_preds;     /**< maximum number of block cfg predecessors */
129         int             changed;           /**< Flags for changed graph state */
130 #ifdef DEBUG_libfirm
131         ir_node         **id_2_address;    /**< maps an id to the used address */
132 #endif
133 } ldst_env;
134
135 /* the one and only environment */
136 static ldst_env env;
137
138 #ifdef DEBUG_libfirm
139
140 static firm_dbg_module_t *dbg;
141
142 /**
143  * Dumps the block list.
144  *
145  * @param ldst environment
146  */
147 static void dump_block_list(ldst_env *env)
148 {
149         block_t *entry;
150         memop_t *op;
151         int     i;
152
153         for (entry = env->forward; entry != NULL; entry = entry->forward_next) {
154                 DB((dbg, LEVEL_2, "%+F {", entry->block));
155
156                 i = 0;
157                 for (op = entry->memop_forward; op != NULL; op = op->next) {
158                         if (i == 0) {
159                                 DB((dbg, LEVEL_2, "\n\t"));
160                         }
161                         DB((dbg, LEVEL_2, "%+F", op->node));
162                         if ((op->flags & FLAG_KILL_ALL) == FLAG_KILL_ALL)
163                                 DB((dbg, LEVEL_2, "X"));
164                         else if (op->flags & FLAG_KILL_ALL)
165                                 DB((dbg, LEVEL_2, "K"));
166                         DB((dbg, LEVEL_2, ", "));
167
168                         i = (i + 1) & 3;
169                 }
170                 DB((dbg, LEVEL_2, "\n}\n\n"));
171         }
172 }  /* dump_block_list */
173
174 /**
175  * Dumps the current set.
176  *
177  * @param bl   current block
178  * @param s    name of the set
179  */
180 static void dump_curr(block_t *bl, const char *s)
181 {
182         size_t end = env.rbs_size - 1;
183         size_t pos;
184         int    i;
185
186         DB((dbg, LEVEL_2, "%s[%+F] = {", s, bl->block));
187         i = 0;
188         for (pos = rbitset_next(env.curr_set, 0, 1); pos < end; pos = rbitset_next(env.curr_set, pos + 1, 1)) {
189                 memop_t *op = env.curr_id_2_memop[pos];
190
191                 if (i == 0) {
192                         DB((dbg, LEVEL_2, "\n\t"));
193                 }
194
195                 DB((dbg, LEVEL_2, "<%+F, %+F>, ", op->value.address, op->value.value));
196                 i = (i + 1) & 3;
197         }
198         DB((dbg, LEVEL_2, "\n}\n"));
199 }  /* dump_curr */
200
201 #else
202 static void dump_block_list(ldst_env *env)
203 {
204         (void) env;
205 }
206 static void dump_curr(block_t *bl, const char *s)
207 {
208         (void) bl;
209         (void) s;
210 }
211 #endif /* DEBUG_libfirm */
212
213 /** Get the block entry for a block node */
214 static block_t *get_block_entry(const ir_node *block)
215 {
216         assert(is_Block(block));
217
218         return (block_t*)get_irn_link(block);
219 }  /* get_block_entry */
220
221 /** Get the memop entry for a memory operation node */
222 static memop_t *get_irn_memop(const ir_node *irn)
223 {
224         assert(! is_Block(irn));
225         return (memop_t*)get_irn_link(irn);
226 }  /* get_irn_memop */
227
228 /**
229  * Walk over the memory edges from definition to users.
230  * This ensures, that even operation without memory output are found.
231  *
232  * @param irn   start node
233  * @param pre   pre walker function
234  * @param post  post walker function
235  * @param ctx   context parameter for the walker functions
236  */
237 static void walk_memory(ir_node *irn, irg_walk_func *pre, irg_walk_func *post, void *ctx)
238 {
239         int     i;
240         ir_mode *mode;
241
242         mark_irn_visited(irn);
243
244         if (pre)
245                 pre(irn, ctx);
246
247         mode = get_irn_mode(irn);
248         if (mode == mode_M) {
249                 /* every successor uses memory */
250                 for (i = get_irn_n_outs(irn) - 1; i >= 0; --i) {
251                         ir_node *succ = get_irn_out(irn, i);
252
253                         if (! irn_visited(succ))
254                                 walk_memory(succ, pre, post, ctx);
255                 }
256         } else if (mode == mode_T) {
257                 /* only some Proj's uses memory */
258                 for (i = get_irn_n_outs(irn) - 1; i >= 0; --i) {
259                         ir_node *proj = get_irn_out(irn, i);
260
261                         if (get_irn_mode(proj) == mode_M && ! irn_visited(proj))
262                                 walk_memory(proj, pre, post, ctx);
263                 }
264         }
265         if (post)
266                 post(irn, ctx);
267 }  /* walk_memory */
268
269 /**
270  * Walks over all memory nodes of a graph.
271  *
272  * @param irg   a graph
273  * @param pre   pre walker function
274  * @param post  post walker function
275  * @param ctx   context parameter for the walker functions
276  */
277 static void walk_memory_irg(ir_graph *irg, irg_walk_func pre, irg_walk_func post, void *ctx)
278 {
279         inc_irg_visited(irg);
280
281         ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
282
283         /*
284          * there are two possible sources for memory: initial_mem and nomem
285          * we ignore nomem as this should NOT change the memory
286          */
287         walk_memory(get_irg_initial_mem(irg), pre, post, ctx);
288
289         ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
290 }  /* walk_memory_irg */
291
292 /**
293  * Register an address and allocate a (sparse, 0..n) ID for it.
294  *
295  * @param adr  the IR-node representing the address
296  *
297  * @return the allocated id
298  */
299 static unsigned register_address(ir_node *adr)
300 {
301         address_entry *entry;
302
303         /* skip Confirms and Casts */
304 restart:
305         if (is_Confirm(adr)) {
306                 adr = get_Confirm_value(adr);
307                 goto restart;
308         }
309         if (is_Cast(adr)) {
310                 adr = get_Cast_op(adr);
311                 goto restart;
312         }
313
314         entry = ir_nodehashmap_get(address_entry, &env.adr_map, adr);
315
316         if (entry == NULL) {
317                 /* new address */
318                 entry = OALLOC(&env.obst, address_entry);
319
320                 entry->id = env.curr_adr_id++;
321                 ir_nodehashmap_insert(&env.adr_map, adr, entry);
322
323                 DB((dbg, LEVEL_3, "ADDRESS %+F has ID %u\n", adr, entry->id));
324 #ifdef DEBUG_libfirm
325                 ARR_APP1(ir_node *, env.id_2_address, adr);
326 #endif
327         }
328         return entry->id;
329 }  /* register_address */
330
331
332 /**
333  * translate an address through a Phi node into a given predecessor
334  * block.
335  *
336  * @param address  the address
337  * @param block    the block
338  * @param pos      the position of the predecessor in block
339  */
340 static ir_node *phi_translate(ir_node *address, const ir_node *block, int pos)
341 {
342         if (is_Phi(address) && get_nodes_block(address) == block)
343                 address = get_Phi_pred(address, pos);
344         return address;
345 }  /* phi_translate */
346
347 /**
348  * Walker: allocate an block entry for every block
349  * and register all potential addresses.
350  */
351 static void prepare_blocks(ir_node *irn, void *ctx)
352 {
353         (void)ctx;
354
355         if (is_Block(irn)) {
356                 block_t *entry = OALLOC(&env.obst, block_t);
357                 int     n;
358
359                 entry->memop_forward    = NULL;
360                 entry->memop_backward   = NULL;
361                 entry->avail_out        = NULL;
362                 entry->id_2_memop_avail = NULL;
363                 entry->anticL_in        = NULL;
364                 entry->id_2_memop_antic = NULL;
365                 entry->block            = irn;
366                 entry->forward_next     = NULL;
367                 entry->backward_next    = NULL;
368                 entry->avail            = NULL;
369                 entry->trans_results    = NULL;
370                 set_irn_link(irn, entry);
371
372                 set_Block_phis(irn, NULL);
373
374                 /* use block marks to track unreachable blocks */
375                 set_Block_mark(irn, 0);
376
377                 n = get_Block_n_cfgpreds(irn);
378                 if (n > env.max_cfg_preds)
379                         env.max_cfg_preds = n;
380         } else {
381                 ir_mode *mode = get_irn_mode(irn);
382
383                 if (mode_is_reference(mode)) {
384                         /*
385                          * Register ALL possible addresses: this is overkill yet but
386                          * simpler then doing it for all possible translated addresses
387                          * (which would be sufficient in the moment.
388                          */
389                         (void)register_address(irn);
390                 }
391         }
392 }  /* prepare_blocks */
393
394 /**
395  * Post-Walker, link in all Phi's
396  */
397 static void link_phis(ir_node *irn, void *ctx)
398 {
399         (void)ctx;
400
401         if (is_Phi(irn)) {
402                 ir_node *block = get_nodes_block(irn);
403                 add_Block_phi(block, irn);
404         }
405 }  /* link_phis */
406
407 /**
408  * Block walker: creates the inverse post-order list for the CFG.
409  */
410 static void inverse_post_order(ir_node *block, void *ctx)
411 {
412         block_t *entry = get_block_entry(block);
413
414         (void)ctx;
415
416         /* mark this block IS reachable from start */
417         set_Block_mark(block, 1);
418
419         /* create the list in inverse order */
420         entry->forward_next = env.forward;
421         env.forward         = entry;
422
423         /* remember the first visited (last in list) entry, needed for later */
424         if (env.backward == NULL)
425                 env.backward = entry;
426 }  /* inverse_post_order */
427
428 /**
429  * Block walker: create backward links for the memops of a block.
430  */
431 static void collect_backward(ir_node *block, void *ctx)
432 {
433         block_t *entry = get_block_entry(block);
434         memop_t *last, *op;
435
436         (void)ctx;
437
438         /*
439          * Do NOT link in the end block yet. We want it to be
440          * the first in the list. This is NOT guaranteed by the walker
441          * if we have endless loops.
442          */
443         if (block != env.end_bl) {
444                 entry->backward_next = env.backward;
445
446                 /* create the list in inverse order */
447                 env.backward = entry;
448         }
449
450         /* create backward links for all memory ops */
451         last = NULL;
452         for (op = entry->memop_forward; op != NULL; op = op->next) {
453                 op->prev = last;
454                 last     = op;
455         }
456         entry->memop_backward = last;
457 }  /* collect_backward */
458
459 /**
460  * Allocate a memop.
461  *
462  * @param irn  the IR-node representing the memop or NULL
463  *             if this is a translated (virtual) memop
464  *
465  * @return the allocated memop
466  */
467 static memop_t *alloc_memop(ir_node *irn)
468 {
469         memop_t *m = OALLOC(&env.obst, memop_t);
470
471         m->value.address = NULL;
472         m->value.value   = NULL;
473         m->value.mode    = NULL;
474
475         m->node          = irn;
476         m->mem           = NULL;
477         m->replace       = NULL;
478         m->next          = NULL;
479         m->flags         = 0;
480
481         memset(m->projs, 0, sizeof(m->projs));
482
483         if (irn != NULL)
484                 set_irn_link(irn, m);
485         return m;
486 }  /* alloc_memop */
487
488 /**
489  * Create a memop for a Phi-replacement.
490  *
491  * @param op   the memop to clone
492  * @param phi  the Phi-node representing the new value
493  */
494 static memop_t *clone_memop_phi(memop_t *op, ir_node *phi)
495 {
496         memop_t *m = OALLOC(&env.obst, memop_t);
497
498         m->value         = op->value;
499         m->value.value   = phi;
500
501         m->node          = phi;
502         m->replace       = NULL;
503         m->next          = NULL;
504         m->flags         = 0;
505
506         set_irn_link(phi, m);
507         return m;
508 }  /* clone_memop_phi */
509
510 /**
511  * Return the memory properties of a call node.
512  *
513  * @param call  the call node
514  *
515  * return a bitset of mtp_property_const and mtp_property_pure
516  */
517 static unsigned get_Call_memory_properties(ir_node *call)
518 {
519         ir_type *call_tp = get_Call_type(call);
520         unsigned prop = get_method_additional_properties(call_tp);
521
522         /* check first the call type */
523         if ((prop & (mtp_property_const|mtp_property_pure)) == 0) {
524                 /* try the called entity */
525                 ir_node *ptr = get_Call_ptr(call);
526
527                 if (is_SymConst_addr_ent(ptr)) {
528                         ir_entity *ent = get_SymConst_entity(ptr);
529
530                         prop = get_entity_additional_properties(ent);
531                 }
532         }
533         return prop & (mtp_property_const|mtp_property_pure);
534 }  /* get_Call_memory_properties */
535
536 /**
537  * Returns an entity if the address ptr points to a constant one.
538  *
539  * @param ptr  the address
540  *
541  * @return an entity or NULL
542  */
543 static ir_entity *find_constant_entity(ir_node *ptr)
544 {
545         for (;;) {
546                 if (is_SymConst(ptr) && get_SymConst_kind(ptr) == symconst_addr_ent) {
547                         return get_SymConst_entity(ptr);
548                 } else if (is_Sel(ptr)) {
549                         ir_entity *ent = get_Sel_entity(ptr);
550                         ir_type   *tp  = get_entity_owner(ent);
551
552                         /* Do not fiddle with polymorphism. */
553                         if (is_Class_type(get_entity_owner(ent)) &&
554                                 ((get_entity_n_overwrites(ent)    != 0) ||
555                                 (get_entity_n_overwrittenby(ent) != 0)   ) )
556                                 return NULL;
557
558                         if (is_Array_type(tp)) {
559                                 /* check bounds */
560                                 int i, n;
561
562                                 for (i = 0, n = get_Sel_n_indexs(ptr); i < n; ++i) {
563                                         ir_node   *bound;
564                                         ir_tarval *tlower, *tupper;
565                                         ir_node   *index = get_Sel_index(ptr, i);
566                                         ir_tarval *tv     = computed_value(index);
567
568                                         /* check if the index is constant */
569                                         if (tv == tarval_bad)
570                                                 return NULL;
571
572                                         bound  = get_array_lower_bound(tp, i);
573                                         tlower = computed_value(bound);
574                                         bound  = get_array_upper_bound(tp, i);
575                                         tupper = computed_value(bound);
576
577                                         if (tlower == tarval_bad || tupper == tarval_bad)
578                                                 return NULL;
579
580                                         if (tarval_cmp(tv, tlower) == ir_relation_less)
581                                                 return NULL;
582                                         if (tarval_cmp(tupper, tv) == ir_relation_less)
583                                                 return NULL;
584
585                                         /* ok, bounds check finished */
586                                 }
587                         }
588
589                         if (get_entity_linkage(ent) == IR_LINKAGE_CONSTANT)
590                                 return ent;
591
592                         /* try next */
593                         ptr = get_Sel_ptr(ptr);
594                 } else if (is_Add(ptr)) {
595                         ir_node *l = get_Add_left(ptr);
596                         ir_node *r = get_Add_right(ptr);
597
598                         if (get_irn_mode(l) == get_irn_mode(ptr) && is_Const(r))
599                                 ptr = l;
600                         else if (get_irn_mode(r) == get_irn_mode(ptr) && is_Const(l))
601                                 ptr = r;
602                         else
603                                 return NULL;
604
605                         /* for now, we support only one addition, reassoc should fold all others */
606                         if (! is_SymConst(ptr) && !is_Sel(ptr))
607                                 return NULL;
608                 } else if (is_Sub(ptr)) {
609                         ir_node *l = get_Sub_left(ptr);
610                         ir_node *r = get_Sub_right(ptr);
611
612                         if (get_irn_mode(l) == get_irn_mode(ptr) && is_Const(r))
613                                 ptr = l;
614                         else
615                                 return NULL;
616                         /* for now, we support only one subtraction, reassoc should fold all others */
617                         if (! is_SymConst(ptr) && !is_Sel(ptr))
618                                 return NULL;
619                 } else
620                         return NULL;
621         }
622 }  /* find_constant_entity */
623
624 /**
625  * Return the Selection index of a Sel node from dimension n
626  */
627 static long get_Sel_array_index_long(ir_node *n, int dim)
628 {
629         ir_node *index = get_Sel_index(n, dim);
630         assert(is_Const(index));
631         return get_tarval_long(get_Const_tarval(index));
632 }  /* get_Sel_array_index_long */
633
634 typedef struct path_entry {
635         ir_entity         *ent;
636         struct path_entry *next;
637         size_t            index;
638 } path_entry;
639
640 static ir_node *rec_find_compound_ent_value(ir_node *ptr, path_entry *next)
641 {
642         path_entry       entry, *p;
643         ir_entity        *ent, *field;
644         ir_initializer_t *initializer;
645         ir_tarval        *tv;
646         ir_type          *tp;
647         size_t           n;
648
649         entry.next = next;
650         if (is_SymConst(ptr)) {
651                 /* found the root */
652                 ent         = get_SymConst_entity(ptr);
653                 initializer = get_entity_initializer(ent);
654                 for (p = next; p != NULL;) {
655                         if (initializer->kind != IR_INITIALIZER_COMPOUND)
656                                 return NULL;
657                         n  = get_initializer_compound_n_entries(initializer);
658                         tp = get_entity_type(ent);
659
660                         if (is_Array_type(tp)) {
661                                 ent = get_array_element_entity(tp);
662                                 if (ent != p->ent) {
663                                         /* a missing [0] */
664                                         if (0 >= n)
665                                                 return NULL;
666                                         initializer = get_initializer_compound_value(initializer, 0);
667                                         continue;
668                                 }
669                         }
670                         if (p->index >= n)
671                                 return NULL;
672                         initializer = get_initializer_compound_value(initializer, p->index);
673
674                         ent = p->ent;
675                         p   = p->next;
676                 }
677                 tp = get_entity_type(ent);
678                 while (is_Array_type(tp)) {
679                         ent = get_array_element_entity(tp);
680                         tp = get_entity_type(ent);
681                         /* a missing [0] */
682                         n  = get_initializer_compound_n_entries(initializer);
683                         if (0 >= n)
684                                 return NULL;
685                         initializer = get_initializer_compound_value(initializer, 0);
686                 }
687
688                 switch (initializer->kind) {
689                 case IR_INITIALIZER_CONST:
690                         return get_initializer_const_value(initializer);
691                 case IR_INITIALIZER_TARVAL:
692                 case IR_INITIALIZER_NULL:
693                 default:
694                         return NULL;
695                 }
696         } else if (is_Sel(ptr)) {
697                 entry.ent = field = get_Sel_entity(ptr);
698                 tp = get_entity_owner(field);
699                 if (is_Array_type(tp)) {
700                         assert(get_Sel_n_indexs(ptr) == 1 && "multi dim arrays not implemented");
701                         entry.index = get_Sel_array_index_long(ptr, 0) - get_array_lower_bound_int(tp, 0);
702                 } else {
703                         size_t i, n_members = get_compound_n_members(tp);
704                         for (i = 0; i < n_members; ++i) {
705                                 if (get_compound_member(tp, i) == field)
706                                         break;
707                         }
708                         if (i >= n_members) {
709                                 /* not found: should NOT happen */
710                                 return NULL;
711                         }
712                         entry.index = i;
713                 }
714                 return rec_find_compound_ent_value(get_Sel_ptr(ptr), &entry);
715         }  else if (is_Add(ptr)) {
716                 ir_mode *mode;
717                 unsigned pos;
718
719                 {
720                         ir_node *l = get_Add_left(ptr);
721                         ir_node *r = get_Add_right(ptr);
722                         if (is_Const(r)) {
723                                 ptr = l;
724                                 tv  = get_Const_tarval(r);
725                         } else {
726                                 ptr = r;
727                                 tv  = get_Const_tarval(l);
728                         }
729                 }
730 ptr_arith:
731                 mode = get_tarval_mode(tv);
732
733                 /* ptr must be a Sel or a SymConst, this was checked in find_constant_entity() */
734                 if (is_Sel(ptr)) {
735                         field = get_Sel_entity(ptr);
736                 } else {
737                         field = get_SymConst_entity(ptr);
738                 }
739
740                 /* count needed entries */
741                 pos = 0;
742                 for (ent = field;;) {
743                         tp = get_entity_type(ent);
744                         if (! is_Array_type(tp))
745                                 break;
746                         ent = get_array_element_entity(tp);
747                         ++pos;
748                 }
749                 /* should be at least ONE entry */
750                 if (pos == 0)
751                         return NULL;
752
753                 /* allocate the right number of entries */
754                 NEW_ARR_A(path_entry, p, pos);
755
756                 /* fill them up */
757                 pos = 0;
758                 for (ent = field;;) {
759                         unsigned  size;
760                         ir_tarval *sz, *tv_index, *tlower, *tupper;
761                         size_t    index;
762                         ir_node   *bound;
763
764                         tp = get_entity_type(ent);
765                         if (! is_Array_type(tp))
766                                 break;
767                         ent = get_array_element_entity(tp);
768                         p[pos].ent  = ent;
769                         p[pos].next = &p[pos + 1];
770
771                         size = get_type_size_bytes(get_entity_type(ent));
772                         sz   = new_tarval_from_long(size, mode);
773
774                         tv_index = tarval_div(tv, sz);
775                         tv       = tarval_mod(tv, sz);
776
777                         if (tv_index == tarval_bad || tv == tarval_bad)
778                                 return NULL;
779
780                         assert(get_array_n_dimensions(tp) == 1 && "multiarrays not implemented");
781                         bound  = get_array_lower_bound(tp, 0);
782                         tlower = computed_value(bound);
783                         bound  = get_array_upper_bound(tp, 0);
784                         tupper = computed_value(bound);
785
786                         if (tlower == tarval_bad || tupper == tarval_bad)
787                                 return NULL;
788
789                         if (tarval_cmp(tv_index, tlower) == ir_relation_less)
790                                 return NULL;
791                         if (tarval_cmp(tupper, tv_index) == ir_relation_less)
792                                 return NULL;
793
794                         /* ok, bounds check finished */
795                         index = get_tarval_long(tv_index);
796                         p[pos].index = index;
797                         ++pos;
798                 }
799                 if (! tarval_is_null(tv)) {
800                         /* hmm, wrong access */
801                         return NULL;
802                 }
803                 p[pos - 1].next = next;
804                 return rec_find_compound_ent_value(ptr, p);
805         } else if (is_Sub(ptr)) {
806                 ir_node *l = get_Sub_left(ptr);
807                 ir_node *r = get_Sub_right(ptr);
808
809                 ptr = l;
810                 tv  = get_Const_tarval(r);
811                 tv  = tarval_neg(tv);
812                 goto ptr_arith;
813         }
814         return NULL;
815 }  /* rec_find_compound_ent_value */
816
817 static ir_node *find_compound_ent_value(ir_node *ptr)
818 {
819         return rec_find_compound_ent_value(ptr, NULL);
820 }  /* find_compound_ent_value */
821
822 /**
823  * Mark a Load memop to be replace by a definition
824  *
825  * @param op  the Load memop
826  */
827 static void mark_replace_load(memop_t *op, ir_node *def)
828 {
829         op->replace = def;
830         op->flags |= FLAG_KILLED_NODE;
831         env.changed = 1;
832 }  /* mark_replace_load */
833
834 /**
835  * Mark a Store memop to be removed.
836  *
837  * @param op  the Store memop
838  */
839 static void mark_remove_store(memop_t *op)
840 {
841         op->flags |= FLAG_KILLED_NODE;
842         env.changed = 1;
843 }  /* mark_remove_store */
844
845 /**
846  * Update a memop for a Load.
847  *
848  * @param m  the memop
849  */
850 static void update_Load_memop(memop_t *m)
851 {
852         int       i;
853         ir_node   *load = m->node;
854         ir_node   *ptr;
855         ir_entity *ent;
856
857         if (get_Load_volatility(load) == volatility_is_volatile)
858                 m->flags |= FLAG_IGNORE;
859
860         ptr = get_Load_ptr(load);
861
862         m->value.address = ptr;
863
864         for (i = get_irn_n_outs(load) - 1; i >= 0; --i) {
865                 ir_node *proj = get_irn_out(load, i);
866                 long    pn;
867
868                 /* beware of keep edges */
869                 if (is_End(proj))
870                         continue;
871
872                 pn = get_Proj_proj(proj);
873                 m->projs[pn] = proj;
874                 switch (pn) {
875                 case pn_Load_res:
876                         m->value.value = proj;
877                         m->value.mode  = get_irn_mode(proj);
878                         break;
879                 case pn_Load_X_except:
880                         m->flags |= FLAG_EXCEPTION;
881                         break;
882                 case pn_Load_M:
883                         m->mem = proj;
884                         break;
885                 case pn_Load_X_regular:
886                         break;
887                 default:
888                         panic("Unsupported Proj from Load %+F", proj);
889                 }
890         }
891
892         /* check if we can determine the entity that will be loaded */
893         ent = find_constant_entity(ptr);
894
895         if (ent != NULL && get_entity_visibility(ent) != ir_visibility_external) {
896                 /* a static allocation that is not external: there should be NO exception
897                  * when loading even if we cannot replace the load itself. */
898                 ir_node *value = NULL;
899
900                 /* no exception, clear the m fields as it might be checked later again */
901                 if (m->projs[pn_Load_X_except]) {
902                         ir_graph *irg = get_irn_irg(ptr);
903                         exchange(m->projs[pn_Load_X_except], new_r_Bad(irg, mode_X));
904                         m->projs[pn_Load_X_except] = NULL;
905                         m->flags &= ~FLAG_EXCEPTION;
906                         env.changed = 1;
907                 }
908                 if (m->projs[pn_Load_X_regular]) {
909                         exchange(m->projs[pn_Load_X_regular], new_r_Jmp(get_nodes_block(load)));
910                         m->projs[pn_Load_X_regular] = NULL;
911                         env.changed = 1;
912                 }
913
914                 if (get_entity_linkage(ent) & IR_LINKAGE_CONSTANT) {
915                         if (ent->initializer) {
916                                 /* new style initializer */
917                                 value = find_compound_ent_value(ptr);
918                         }
919                         if (value != NULL)
920                                 value = can_replace_load_by_const(load, value);
921                 }
922
923                 if (value != NULL) {
924                         /* we completely replace the load by this value */
925                         DB((dbg, LEVEL_1, "Replacing Load %+F by constant %+F\n", m->node, value));
926                         mark_replace_load(m, value);
927                         return;
928                 }
929         }
930
931         if (m->value.value != NULL && !(m->flags & FLAG_IGNORE)) {
932                 /* only create an address if this node is NOT killed immediately or ignored */
933                 m->value.id = register_address(ptr);
934                 ++env.n_mem_ops;
935         } else {
936                 /* no user, KILL it */
937                 mark_replace_load(m, NULL);
938         }
939 }  /* update_Load_memop */
940
941 /**
942  * Update a memop for a Store.
943  *
944  * @param m  the memop
945  */
946 static void update_Store_memop(memop_t *m)
947 {
948         int     i;
949         ir_node *store = m->node;
950         ir_node *adr   = get_Store_ptr(store);
951
952         if (get_Store_volatility(store) == volatility_is_volatile) {
953                 m->flags |= FLAG_IGNORE;
954         } else {
955                 /* only create an address if this node is NOT ignored */
956                 m->value.id = register_address(adr);
957                 ++env.n_mem_ops;
958         }
959
960         m->value.address = adr;
961
962         for (i = get_irn_n_outs(store) - 1; i >= 0; --i) {
963                 ir_node *proj = get_irn_out(store, i);
964                 long    pn;
965
966                 /* beware of keep edges */
967                 if (is_End(proj))
968                         continue;
969
970                 pn = get_Proj_proj(proj);
971                 m->projs[pn] = proj;
972                 switch (pn) {
973                 case pn_Store_X_except:
974                         m->flags |= FLAG_EXCEPTION;
975                         break;
976                 case pn_Store_M:
977                         m->mem = proj;
978                         break;
979                 case pn_Store_X_regular:
980                         break;
981                 default:
982                         panic("Unsupported Proj from Store %+F", proj);
983                 }
984         }
985         m->value.value = get_Store_value(store);
986         m->value.mode  = get_irn_mode(m->value.value);
987 }  /* update_Store_memop */
988
989 /**
990  * Update a memop for a Call.
991  *
992  * @param m  the memop
993  */
994 static void update_Call_memop(memop_t *m)
995 {
996         ir_node  *call = m->node;
997         unsigned prop  = get_Call_memory_properties(call);
998         int      i;
999
1000         if (prop & mtp_property_const) {
1001                 /* A constant call did NOT use memory at all, we
1002                    can kick it from the list. */
1003         } else if (prop & mtp_property_pure) {
1004                 /* pure calls READ memory */
1005                 m->flags = 0;
1006         } else
1007                 m->flags = FLAG_KILL_ALL;
1008
1009         for (i = get_irn_n_outs(call) - 1; i >= 0; --i) {
1010                 ir_node *proj = get_irn_out(call, i);
1011
1012                 /* beware of keep edges */
1013                 if (is_End(proj))
1014                         continue;
1015
1016                 switch (get_Proj_proj(proj)) {
1017                 case pn_Call_X_except:
1018                         m->flags |= FLAG_EXCEPTION;
1019                         break;
1020                 case pn_Call_M:
1021                         m->mem = proj;
1022                         break;
1023                 }
1024         }
1025 }  /* update_Call_memop */
1026
1027 /**
1028  * Update a memop for a Div/Mod.
1029  *
1030  * @param m  the memop
1031  */
1032 static void update_Div_memop(memop_t *m)
1033 {
1034         ir_node *div = m->node;
1035         int     i;
1036
1037         for (i = get_irn_n_outs(div) - 1; i >= 0; --i) {
1038                 ir_node *proj = get_irn_out(div, i);
1039
1040                 /* beware of keep edges */
1041                 if (is_End(proj))
1042                         continue;
1043
1044                 switch (get_Proj_proj(proj)) {
1045                 case pn_Div_X_except:
1046                         m->flags |= FLAG_EXCEPTION;
1047                         break;
1048                 case pn_Div_M:
1049                         m->mem = proj;
1050                         break;
1051                 }
1052         }
1053 }
1054
1055 static void update_Mod_memop(memop_t *m)
1056 {
1057         ir_node *div = m->node;
1058         int     i;
1059
1060         for (i = get_irn_n_outs(div) - 1; i >= 0; --i) {
1061                 ir_node *proj = get_irn_out(div, i);
1062
1063                 /* beware of keep edges */
1064                 if (is_End(proj))
1065                         continue;
1066
1067                 switch (get_Proj_proj(proj)) {
1068                 case pn_Mod_X_except:
1069                         m->flags |= FLAG_EXCEPTION;
1070                         break;
1071                 case pn_Mod_M:
1072                         m->mem = proj;
1073                         break;
1074                 }
1075         }
1076 }
1077
1078 /**
1079  * Update a memop for a Phi.
1080  *
1081  * @param m  the memop
1082  */
1083 static void update_Phi_memop(memop_t *m)
1084 {
1085         /* the Phi is its own mem */
1086         m->mem = m->node;
1087 }  /* update_Phi_memop */
1088
1089 /**
1090  * Memory walker: collect all memory ops and build topological lists.
1091  */
1092 static void collect_memops(ir_node *irn, void *ctx)
1093 {
1094         memop_t  *op;
1095         ir_node  *block;
1096         block_t  *entry;
1097
1098         (void) ctx;
1099         if (is_Proj(irn)) {
1100                 /* we can safely ignore ProjM's except the initial memory */
1101                 ir_graph *irg = get_irn_irg(irn);
1102                 if (irn != get_irg_initial_mem(irg))
1103                         return;
1104         }
1105
1106         op    = alloc_memop(irn);
1107         block = get_nodes_block(irn);
1108         entry = get_block_entry(block);
1109
1110         if (is_Phi(irn)) {
1111                 update_Phi_memop(op);
1112                 /* Phis must be always placed first */
1113                 op->next = entry->memop_forward;
1114                 entry->memop_forward = op;
1115                 if (entry->memop_backward == NULL)
1116                         entry->memop_backward = op;
1117         } else {
1118                 switch (get_irn_opcode(irn)) {
1119                 case iro_Load:
1120                         update_Load_memop(op);
1121                         break;
1122                 case iro_Store:
1123                         update_Store_memop(op);
1124                         break;
1125                 case iro_Call:
1126                         update_Call_memop(op);
1127                         break;
1128                 case iro_Sync:
1129                 case iro_Pin:
1130                         op->mem = irn;
1131                         break;
1132                 case iro_Proj:
1133                         /* initial memory */
1134                         op->mem = irn;
1135                         break;
1136                 case iro_Return:
1137                 case iro_End:
1138                         /* we can those to find the memory edge */
1139                         break;
1140                 case iro_Div:
1141                         update_Div_memop(op);
1142                         break;
1143                 case iro_Mod:
1144                         update_Mod_memop(op);
1145                         break;
1146
1147                 case iro_Builtin:
1148                         /* TODO: handle some builtins */
1149                 default:
1150                         /* unsupported operation */
1151                         op->flags = FLAG_KILL_ALL;
1152                 }
1153
1154
1155                 /* all other should be placed last */
1156                 if (entry->memop_backward == NULL) {
1157                         entry->memop_forward = entry->memop_backward = op;
1158                 } else {
1159                         entry->memop_backward->next = op;
1160                         entry->memop_backward       = op;
1161                 }
1162         }
1163 }  /* collect_memops */
1164
1165 /**
1166  * Find an address in the current set.
1167  *
1168  * @param value  the value to be searched for
1169  *
1170  * @return a memop for the value or NULL if the value does
1171  *         not exists in the set or cannot be converted into
1172  *         the requested mode
1173  */
1174 static memop_t *find_address(const value_t *value)
1175 {
1176         if (rbitset_is_set(env.curr_set, value->id)) {
1177                 memop_t *res = env.curr_id_2_memop[value->id];
1178
1179                 if (res->value.mode == value->mode)
1180                         return res;
1181                 /* allow hidden casts */
1182                 if (get_mode_arithmetic(res->value.mode) == irma_twos_complement &&
1183                     get_mode_arithmetic(value->mode) == irma_twos_complement &&
1184                     get_mode_size_bits(res->value.mode) == get_mode_size_bits(value->mode))
1185                         return res;
1186         }
1187         return NULL;
1188 }  /* find_address */
1189
1190 /**
1191  * Find an address in the avail_out set.
1192  *
1193  * @param bl     the block
1194  */
1195 static memop_t *find_address_avail(const block_t *bl, unsigned id, const ir_mode *mode)
1196 {
1197         if (rbitset_is_set(bl->avail_out, id)) {
1198                 memop_t *res = bl->id_2_memop_avail[id];
1199
1200                 if (res->value.mode == mode)
1201                         return res;
1202                 /* allow hidden casts */
1203                 if (get_mode_arithmetic(res->value.mode) == irma_twos_complement &&
1204                     get_mode_arithmetic(mode) == irma_twos_complement &&
1205                     get_mode_size_bits(res->value.mode) == get_mode_size_bits(mode))
1206                         return res;
1207         }
1208         return NULL;
1209 }  /* find_address_avail */
1210
1211 /**
1212  * Kill all addresses from the current set.
1213  */
1214 static void kill_all(void)
1215 {
1216         rbitset_clear_all(env.curr_set, env.rbs_size);
1217
1218         /* set sentinel */
1219         rbitset_set(env.curr_set, env.rbs_size - 1);
1220 }  /* kill_all */
1221
1222 /**
1223  * Kill memops that are not alias free due to a Store value from the current set.
1224  *
1225  * @param value  the Store value
1226  */
1227 static void kill_memops(const value_t *value)
1228 {
1229         size_t end = env.rbs_size - 1;
1230         size_t pos;
1231
1232         for (pos = rbitset_next(env.curr_set, 0, 1); pos < end; pos = rbitset_next(env.curr_set, pos + 1, 1)) {
1233                 memop_t *op = env.curr_id_2_memop[pos];
1234
1235                 if (ir_no_alias != get_alias_relation(value->address, value->mode,
1236                                                           op->value.address, op->value.mode)) {
1237                         rbitset_clear(env.curr_set, pos);
1238                         env.curr_id_2_memop[pos] = NULL;
1239                         DB((dbg, LEVEL_2, "KILLING %+F because of possible alias address %+F\n", op->node, value->address));
1240                 }
1241         }
1242 }  /* kill_memops */
1243
1244 /**
1245  * Add the value of a memop to the current set.
1246  *
1247  * @param op  the memory op
1248  */
1249 static void add_memop(memop_t *op)
1250 {
1251         rbitset_set(env.curr_set, op->value.id);
1252         env.curr_id_2_memop[op->value.id] = op;
1253 }  /* add_memop */
1254
1255 /**
1256  * Add the value of a memop to the avail_out set.
1257  *
1258  * @param bl  the block
1259  * @param op  the memory op
1260  */
1261 static void add_memop_avail(block_t *bl, memop_t *op)
1262 {
1263         rbitset_set(bl->avail_out, op->value.id);
1264         bl->id_2_memop_avail[op->value.id] = op;
1265 }  /* add_memop_avail */
1266
1267 /**
1268  * Check, if we can convert a value of one mode to another mode
1269  * without changing the representation of bits.
1270  *
1271  * @param from  the original mode
1272  * @param to    the destination mode
1273  */
1274 static int can_convert_to(const ir_mode *from, const ir_mode *to)
1275 {
1276         if (get_mode_arithmetic(from) == irma_twos_complement &&
1277             get_mode_arithmetic(to) == irma_twos_complement &&
1278             get_mode_size_bits(from) == get_mode_size_bits(to))
1279                 return 1;
1280         return 0;
1281 }  /* can_convert_to */
1282
1283 /**
1284  * Add a Conv to the requested mode if needed.
1285  *
1286  * @param irn   the IR-node to convert
1287  * @param mode  the destination mode
1288  *
1289  * @return the possible converted node or NULL
1290  *         if the conversion is not possible
1291  */
1292 static ir_node *conv_to(ir_node *irn, ir_mode *mode)
1293 {
1294         ir_mode *other = get_irn_mode(irn);
1295         if (other != mode) {
1296                 /* different modes: check if conversion is possible without changing the bits */
1297                 if (can_convert_to(other, mode)) {
1298                         ir_node *block = get_nodes_block(irn);
1299                         return new_r_Conv(block, irn, mode);
1300                 }
1301                 /* otherwise not possible ... yet */
1302                 return NULL;
1303         }
1304         return irn;
1305 }  /* conv_to */
1306
1307 /**
1308  * Update the address of an value if this address was a load result
1309  * and the load is killed now.
1310  *
1311  * @param value  the value whose address is updated
1312  */
1313 static void update_address(value_t *value)
1314 {
1315         if (is_Proj(value->address)) {
1316                 ir_node *load = get_Proj_pred(value->address);
1317
1318                 if (is_Load(load)) {
1319                         const memop_t *op = get_irn_memop(load);
1320
1321                         if (op->flags & FLAG_KILLED_NODE)
1322                                 value->address = op->replace;
1323                 }
1324         }
1325 }  /* update_address */
1326
1327 /**
1328  * Do forward dataflow analysis on the given block and calculate the
1329  * GEN and KILL in the current (avail) set.
1330  *
1331  * @param bl  the block
1332  */
1333 static void calc_gen_kill_avail(block_t *bl)
1334 {
1335         memop_t *op;
1336         ir_node *def;
1337
1338         for (op = bl->memop_forward; op != NULL; op = op->next) {
1339                 switch (get_irn_opcode(op->node)) {
1340                 case iro_Phi:
1341                         /* meet */
1342                         break;
1343                 case iro_Sync:
1344                         /* join */
1345                         break;
1346                 case iro_Load:
1347                         if (! (op->flags & (FLAG_KILLED_NODE|FLAG_IGNORE))) {
1348                                 /* do we have this already? */
1349                                 memop_t *other;
1350
1351                                 update_address(&op->value);
1352                                 other = find_address(&op->value);
1353                                 if (other != NULL && other != op) {
1354                                         def = conv_to(other->value.value, op->value.mode);
1355                                         if (def != NULL) {
1356 #ifdef DEBUG_libfirm
1357                                                 if (is_Store(other->node)) {
1358                                                         /* RAW */
1359                                                         DB((dbg, LEVEL_1, "RAW %+F <- %+F(%+F)\n", op->node, def, other->node));
1360                                                 } else {
1361                                                         /* RAR */
1362                                                         DB((dbg, LEVEL_1, "RAR %+F <- %+F(%+F)\n", op->node, def, other->node));
1363                                                 }
1364 #endif
1365                                                 mark_replace_load(op, def);
1366                                                 /* do NOT change the memop table */
1367                                                 continue;
1368                                         }
1369                                 }
1370                                 /* add this value */
1371                                 add_memop(op);
1372                         }
1373                         break;
1374                 case iro_Store:
1375                         if (! (op->flags & FLAG_KILLED_NODE)) {
1376                                 /* do we have this store already */
1377                                 memop_t *other;
1378
1379                                 update_address(&op->value);
1380                                 other = find_address(&op->value);
1381                                 if (other != NULL) {
1382                                         if (is_Store(other->node)) {
1383                                                 if (op != other && !(other->flags & FLAG_IGNORE) &&
1384                                                     get_nodes_block(other->node) == get_nodes_block(op->node)) {
1385                                                         /*
1386                                                          * A WAW in the same block we can kick the first store.
1387                                                          * This is a shortcut: we know that the second Store will be anticipated
1388                                                          * then in an case.
1389                                                          */
1390                                                         DB((dbg, LEVEL_1, "WAW %+F <- %+F\n", other->node, op->node));
1391                                                         mark_remove_store(other);
1392                                                         /* FIXME: a Load might be get freed due to this killed store */
1393                                                 }
1394                                         } else if (other->value.value == op->value.value && !(op->flags & FLAG_IGNORE)) {
1395                                                 /* WAR */
1396                                                 DB((dbg, LEVEL_1, "WAR %+F <- %+F\n", op->node, other->node));
1397                                                 mark_remove_store(op);
1398                                                 /* do NOT change the memop table */
1399                                                 continue;
1400                                         }
1401                                 }
1402                                 /* KILL all possible aliases */
1403                                 kill_memops(&op->value);
1404                                 /* add this value */
1405                                 add_memop(op);
1406                         }
1407                         break;
1408                 default:
1409                         if (op->flags & FLAG_KILL_ALL)
1410                                 kill_all();
1411                 }
1412         }
1413 }  /* calc_gen_kill_avail */
1414
1415 #define BYTE_SIZE(x)  (((x) + 7) >> 3)
1416
1417 /**
1418  * Do forward dataflow analysis on a given block to calculate the avail_out set
1419  * for this block only.
1420  *
1421  * @param block  the block
1422  */
1423 static void forward_avail(block_t *bl)
1424 {
1425         /* fill the data from the current block */
1426         env.curr_id_2_memop = bl->id_2_memop_avail;
1427         env.curr_set        = bl->avail_out;
1428
1429         calc_gen_kill_avail(bl);
1430         dump_curr(bl, "Avail_out");
1431 }  /* forward_avail */
1432
1433 /**
1434  * Do backward dataflow analysis on a given block to calculate the antic set
1435  * of Loaded addresses.
1436  *
1437  * @param bl  the block
1438  *
1439  * @return non-zero if the set has changed since last iteration
1440  */
1441 static int backward_antic(block_t *bl)
1442 {
1443         memop_t *op;
1444         ir_node *block = bl->block;
1445         int     n = get_Block_n_cfg_outs(block);
1446
1447         if (n == 1) {
1448                 ir_node  *succ    = get_Block_cfg_out(block, 0);
1449                 block_t  *succ_bl = get_block_entry(succ);
1450                 int      pred_pos = get_Block_cfgpred_pos(succ, block);
1451                 size_t   end      = env.rbs_size - 1;
1452                 size_t   pos;
1453
1454                 kill_all();
1455
1456                 if (bl->trans_results == NULL) {
1457                         /* allocate the translate cache */
1458                         bl->trans_results = OALLOCNZ(&env.obst, memop_t*, env.curr_adr_id);
1459                 }
1460
1461                 /* check for partly redundant values */
1462                 for (pos = rbitset_next(succ_bl->anticL_in, 0, 1);
1463                      pos < end;
1464                      pos = rbitset_next(succ_bl->anticL_in, pos + 1, 1)) {
1465                         /*
1466                          * do Phi-translation here: Note that at this point the nodes are
1467                          * not changed, so we can safely cache the results.
1468                          * However: Loads of Load results ARE bad, because we have no way
1469                           to translate them yet ...
1470                          */
1471                         memop_t *op = bl->trans_results[pos];
1472                         if (op == NULL) {
1473                                 /* not yet translated */
1474                                 ir_node *adr, *trans_adr;
1475
1476                                 op  = succ_bl->id_2_memop_antic[pos];
1477                                 adr = op->value.address;
1478
1479                                 trans_adr = phi_translate(adr, succ, pred_pos);
1480                                 if (trans_adr != adr) {
1481                                         /* create a new entry for the translated one */
1482                                         memop_t *new_op;
1483
1484                                         new_op = alloc_memop(NULL);
1485                                         new_op->value.address = trans_adr;
1486                                         new_op->value.id      = register_address(trans_adr);
1487                                         new_op->value.mode    = op->value.mode;
1488                                         new_op->node          = op->node; /* we need the node to decide if Load/Store */
1489                                         new_op->flags         = op->flags;
1490
1491                                         bl->trans_results[pos] = new_op;
1492                                         op = new_op;
1493                                 }
1494                         }
1495                         env.curr_id_2_memop[op->value.id] = op;
1496                         rbitset_set(env.curr_set, op->value.id);
1497                 }
1498         } else if (n > 1) {
1499                 ir_node *succ    = get_Block_cfg_out(block, 0);
1500                 block_t *succ_bl = get_block_entry(succ);
1501                 int i;
1502
1503                 rbitset_copy(env.curr_set, succ_bl->anticL_in, env.rbs_size);
1504                 memcpy(env.curr_id_2_memop, succ_bl->id_2_memop_antic, env.rbs_size * sizeof(env.curr_id_2_memop[0]));
1505
1506                 /* Hmm: probably we want kill merges of Loads ans Stores here */
1507                 for (i = n - 1; i > 0; --i) {
1508                         ir_node *succ    = get_Block_cfg_out(bl->block, i);
1509                         block_t *succ_bl = get_block_entry(succ);
1510
1511                         rbitset_and(env.curr_set, succ_bl->anticL_in, env.rbs_size);
1512                 }
1513         } else {
1514                 /* block ends with a noreturn call */
1515                 kill_all();
1516         }
1517
1518         dump_curr(bl, "AnticL_out");
1519
1520         for (op = bl->memop_backward; op != NULL; op = op->prev) {
1521                 switch (get_irn_opcode(op->node)) {
1522                 case iro_Phi:
1523                         /* meet */
1524                         break;
1525                 case iro_Sync:
1526                         /* join */
1527                         break;
1528                 case iro_Load:
1529                         if (! (op->flags & (FLAG_KILLED_NODE|FLAG_IGNORE))) {
1530                                 /* always add it */
1531                                 add_memop(op);
1532                         }
1533                         break;
1534                 case iro_Store:
1535                         if (! (op->flags & FLAG_KILLED_NODE)) {
1536                                 /* a Store: check which memops must be killed */
1537                                 kill_memops(&op->value);
1538                         }
1539                         break;
1540                 default:
1541                         if (op->flags & FLAG_KILL_ALL)
1542                                 kill_all();
1543                 }
1544         }
1545
1546         memcpy(bl->id_2_memop_antic, env.curr_id_2_memop, env.rbs_size * sizeof(env.curr_id_2_memop[0]));
1547         if (! rbitsets_equal(bl->anticL_in, env.curr_set, env.rbs_size)) {
1548                 /* changed */
1549                 rbitset_copy(bl->anticL_in, env.curr_set, env.rbs_size);
1550                 dump_curr(bl, "AnticL_in*");
1551                 return 1;
1552         }
1553         dump_curr(bl, "AnticL_in");
1554         return 0;
1555 }  /* backward_antic */
1556
1557 /**
1558  * Replace a Load memop by a already known value.
1559  *
1560  * @param op  the Load memop
1561  */
1562 static void replace_load(memop_t *op)
1563 {
1564         ir_node *load = op->node;
1565         ir_node *def  = skip_Id(op->replace);
1566         ir_node *proj;
1567         ir_mode *mode;
1568
1569         if (def != NULL)
1570                 DB((dbg, LEVEL_1, "Replacing %+F by definition %+F\n", load, is_Proj(def) ? get_Proj_pred(def) : def));
1571         else {
1572                 if (op->flags & FLAG_EXCEPTION) {
1573                         /* bad: this node is unused and executed for exception only */
1574                         DB((dbg, LEVEL_1, "Unused %+F executed for exception only ...\n", load));
1575                         return;
1576                 }
1577                 DB((dbg, LEVEL_1, "Killing unused %+F\n", load));
1578         }
1579
1580         if (op->mem != NULL) {
1581                 /* in rare cases a Load might have NO memory */
1582                 exchange(op->mem, get_Load_mem(load));
1583         }
1584         proj = op->projs[pn_Load_res];
1585         if (proj != NULL) {
1586                 mode = get_irn_mode(proj);
1587                 if (get_irn_mode(def) != mode) {
1588                         /* a hidden cast */
1589                         dbg_info *db    = get_irn_dbg_info(load);
1590                         ir_node  *block = get_nodes_block(proj);
1591                         def = new_rd_Conv(db, block, def, mode);
1592                 }
1593                 exchange(proj, def);
1594         }
1595         proj = op->projs[pn_Load_X_except];
1596         if (proj != NULL) {
1597                 ir_graph *irg = get_irn_irg(load);
1598                 exchange(proj, new_r_Bad(irg, mode_X));
1599         }
1600         proj = op->projs[pn_Load_X_regular];
1601         if (proj != NULL) {
1602                 exchange(proj, new_r_Jmp(get_nodes_block(load)));
1603         }
1604 }  /* replace_load */
1605
1606 /**
1607  * Remove a Store memop.
1608  *
1609  * @param op  the Store memop
1610  */
1611 static void remove_store(memop_t *op)
1612 {
1613         ir_node *store = op->node;
1614         ir_node *proj;
1615
1616         DB((dbg, LEVEL_1, "Removing %+F\n", store));
1617
1618         if (op->mem != NULL) {
1619                 /* in rare cases a Store might have no memory */
1620                 exchange(op->mem, get_Store_mem(store));
1621         }
1622         proj = op->projs[pn_Store_X_except];
1623         if (proj != NULL) {
1624                 ir_graph *irg = get_irn_irg(store);
1625                 exchange(proj, new_r_Bad(irg, mode_X));
1626         }
1627         proj = op->projs[pn_Store_X_regular];
1628         if (proj != NULL) {
1629                 exchange(proj, new_r_Jmp(get_nodes_block(store)));
1630         }
1631 }  /* remove_store */
1632
1633
1634 /**
1635  * Do all necessary replacements for a given block.
1636  *
1637  * @param bl  the block
1638  */
1639 static void do_replacements(block_t *bl)
1640 {
1641         memop_t *op;
1642
1643         for (op = bl->memop_forward; op != NULL; op = op->next) {
1644                 if (op->flags & FLAG_KILLED_NODE) {
1645                         switch (get_irn_opcode(op->node)) {
1646                         case iro_Load:
1647                                 replace_load(op);
1648                                 break;
1649                         case iro_Store:
1650                                 remove_store(op);
1651                                 break;
1652                         }
1653                 }
1654         }
1655 }  /* do_replacements */
1656
1657 /**
1658  * Calculate the Avail_out sets for all basic blocks.
1659  */
1660 static void calcAvail(void)
1661 {
1662         memop_t  **tmp_memop = env.curr_id_2_memop;
1663         unsigned *tmp_set    = env.curr_set;
1664         block_t  *bl;
1665
1666         /* calculate avail_out */
1667         DB((dbg, LEVEL_2, "Calculate Avail_out\n"));
1668
1669         /* iterate over all blocks in in any order, skip the start block */
1670         for (bl = env.forward->forward_next; bl != NULL; bl = bl->forward_next) {
1671                 forward_avail(bl);
1672         }
1673
1674         /* restore the current sets */
1675         env.curr_id_2_memop = tmp_memop;
1676         env.curr_set        = tmp_set;
1677 }  /* calcAvail */
1678
1679 /**
1680  * Calculate the Antic_in sets for all basic blocks.
1681  */
1682 static void calcAntic(void)
1683 {
1684         int i, need_iter;
1685
1686         /* calculate antic_out */
1687         DB((dbg, LEVEL_2, "Calculate Antic_in\n"));
1688         i = 0;
1689         do {
1690                 block_t *bl;
1691
1692                 DB((dbg, LEVEL_2, "Iteration %d:\n=========\n", i));
1693
1694                 need_iter = 0;
1695
1696                 /* over all blocks in reverse post order */
1697                 for (bl = env.backward->backward_next; bl != NULL; bl = bl->backward_next) {
1698                         need_iter |= backward_antic(bl);
1699                 }
1700                 ++i;
1701         } while (need_iter);
1702         DB((dbg, LEVEL_2, "Get anticipated Load set after %d iterations\n", i));
1703 }  /* calcAntic */
1704
1705 /**
1706  * Return the node representing the last memory in a block.
1707  *
1708  * @param bl  the block
1709  */
1710 static ir_node *find_last_memory(block_t *bl)
1711 {
1712         for (;;) {
1713                 if (bl->memop_backward != NULL) {
1714                         return bl->memop_backward->mem;
1715                 }
1716                 /* if there is NO memory in this block, go to the dominator */
1717                 bl = get_block_entry(get_Block_idom(bl->block));
1718         }
1719 }  /* find_last_memory */
1720
1721 /**
1722  * Reroute all memory users of old memory
1723  * to a new memory IR-node.
1724  *
1725  * @param omem  the old memory IR-node
1726  * @param nmem  the new memory IR-node
1727  */
1728 static void reroute_all_mem_users(ir_node *omem, ir_node *nmem)
1729 {
1730         int i;
1731
1732         for (i = get_irn_n_outs(omem) - 1; i >= 0; --i) {
1733                 int     n_pos;
1734                 ir_node *user = get_irn_out_ex(omem, i, &n_pos);
1735
1736                 set_irn_n(user, n_pos, nmem);
1737         }
1738
1739         /* all edges previously point to omem now point to nmem */
1740         nmem->out = omem->out;
1741 }  /* reroute_all_mem_users */
1742
1743 /**
1744  * Reroute memory users of old memory that are dominated by a given block
1745  * to a new memory IR-node.
1746  *
1747  * @param omem     the old memory IR-node
1748  * @param nmem     the new memory IR-node
1749  * @param pass_bl  the block the memory must pass
1750  */
1751 static void reroute_mem_through(ir_node *omem, ir_node *nmem, ir_node *pass_bl)
1752 {
1753         int             i, j, n = get_irn_n_outs(omem);
1754         ir_def_use_edge *edges = NEW_ARR_D(ir_def_use_edge, &env.obst, n + 1);
1755
1756         for (i = j = 0; i < n; ++i) {
1757                 int     n_pos;
1758                 ir_node *user   = get_irn_out_ex(omem, i, &n_pos);
1759                 ir_node *use_bl = get_nodes_block(user);
1760
1761
1762                 if (is_Phi(user)) {
1763                         use_bl = get_Block_cfgpred_block(use_bl, n_pos);
1764                 }
1765                 if (block_dominates(pass_bl, use_bl)) {
1766                         /* found an user that is dominated */
1767                         ++j;
1768                         edges[j].pos = n_pos;
1769                         edges[j].use = user;
1770
1771                         set_irn_n(user, n_pos, nmem);
1772                 }
1773         }
1774
1775         /* Modify the out structure: we create a new out edge array on our
1776            temporary obstack here. This should be no problem, as we invalidate the edges
1777            at the end either. */
1778         /* first entry is used for the length */
1779         edges[0].pos = j;
1780         nmem->out = edges;
1781 }  /* reroute_mem_through */
1782
1783 /**
1784  * insert Loads, making partly redundant Loads fully redundant
1785  */
1786 static int insert_Load(block_t *bl)
1787 {
1788         ir_node  *block = bl->block;
1789         int      i, n = get_Block_n_cfgpreds(block);
1790         size_t   end = env.rbs_size - 1;
1791
1792         DB((dbg, LEVEL_3, "processing %+F\n", block));
1793
1794         if (n == 0) {
1795                 /* might still happen for an unreachable block (end for instance) */
1796                 return 0;
1797         }
1798
1799         if (n > 1) {
1800                 ir_node **ins;
1801                 size_t    pos;
1802
1803                 NEW_ARR_A(ir_node *, ins, n);
1804
1805                 rbitset_set_all(env.curr_set, env.rbs_size);
1806
1807                 /* More than one predecessors, calculate the join for all avail_outs ignoring unevaluated
1808                    Blocks. These put in Top anyway. */
1809                 for (i = n - 1; i >= 0; --i) {
1810                         ir_node *pred = skip_Proj(get_Block_cfgpred(block, i));
1811                         ir_node *blk  = get_nodes_block(pred);
1812                         block_t *pred_bl;
1813
1814                         pred_bl = get_block_entry(blk);
1815                         rbitset_and(env.curr_set, pred_bl->avail_out, env.rbs_size);
1816
1817                         if (is_Load(pred) || is_Store(pred)) {
1818                                 /* We reached this block by an exception from a Load or Store:
1819                                  * the memop creating the exception was NOT completed than, kill it
1820                                  */
1821                                 memop_t *exc_op = get_irn_memop(pred);
1822                                 rbitset_clear(env.curr_set, exc_op->value.id);
1823                         }
1824
1825                 }
1826                 /*
1827                  * Ensure that all values are in the map: build Phi's if necessary:
1828                  * Note: the last bit is the sentinel and ALWAYS set, so end with -2.
1829                  */
1830                 for (pos = 0; pos < env.rbs_size - 1; ++pos) {
1831                         if (! rbitset_is_set(env.curr_set, pos))
1832                                 env.curr_id_2_memop[pos] = NULL;
1833                         else {
1834                                 ir_node *pred    = get_Block_cfgpred_block(bl->block, 0);
1835                                 block_t *pred_bl = get_block_entry(pred);
1836                                 int     need_phi = 0;
1837                                 memop_t *first   = NULL;
1838                                 ir_mode *mode    = NULL;
1839
1840                                 for (i = 0; i < n; ++i) {
1841                                         memop_t *mop;
1842
1843                                         pred    = get_Block_cfgpred_block(bl->block, i);
1844                                         pred_bl = get_block_entry(pred);
1845
1846                                         mop = pred_bl->id_2_memop_avail[pos];
1847                                         if (first == NULL) {
1848                                                 first = mop;
1849                                                 ins[0] = first->value.value;
1850                                                 mode = get_irn_mode(ins[0]);
1851
1852                                                 /* no Phi needed so far */
1853                                                 env.curr_id_2_memop[pos] = first;
1854                                         } else {
1855                                                 ins[i] = conv_to(mop->value.value, mode);
1856                                                 if (ins[i] != ins[0]) {
1857                                                         if (ins[i] == NULL) {
1858                                                                 /* conversion failed */
1859                                                                 env.curr_id_2_memop[pos] = NULL;
1860                                                                 rbitset_clear(env.curr_set, pos);
1861                                                                 break;
1862                                                         }
1863                                                         need_phi = 1;
1864                                                 }
1865                                         }
1866                                 }
1867                                 if (need_phi) {
1868                                         /* build a Phi  */
1869                                         ir_node *phi = new_r_Phi(bl->block, n, ins, mode);
1870                                         memop_t *phiop = alloc_memop(phi);
1871
1872                                         phiop->value = first->value;
1873                                         phiop->value.value = phi;
1874
1875                                         /* no need to link it in, as it is a DATA phi */
1876
1877                                         env.curr_id_2_memop[pos] = phiop;
1878
1879                                         DB((dbg, LEVEL_3, "Created new %+F on merging value for address %+F\n", phi, first->value.address));
1880                                 }
1881                         }
1882                 }
1883         } else {
1884                 /* only one predecessor, simply copy the map */
1885                 ir_node *pred    = get_Block_cfgpred_block(bl->block, 0);
1886                 block_t *pred_bl = get_block_entry(pred);
1887
1888                 rbitset_copy(env.curr_set, pred_bl->avail_out, env.rbs_size);
1889
1890                 memcpy(env.curr_id_2_memop, pred_bl->id_2_memop_avail, env.rbs_size * sizeof(bl->id_2_memop_avail[0]));
1891         }
1892
1893         if (n > 1) {
1894                 size_t pos;
1895
1896                 /* check for partly redundant values */
1897                 for (pos = rbitset_next(bl->anticL_in, 0, 1);
1898                      pos < end;
1899                      pos = rbitset_next(bl->anticL_in, pos + 1, 1)) {
1900                         memop_t *op = bl->id_2_memop_antic[pos];
1901                         int     have_some, all_same;
1902                         ir_node *first;
1903
1904                         if (rbitset_is_set(env.curr_set, pos)) {
1905                                 /* already avail */
1906                                 continue;
1907                         }
1908
1909                         assert(is_Load(op->node));
1910
1911                         DB((dbg, LEVEL_3, "anticipated %+F\n", op->node));
1912
1913                         have_some  = 0;
1914                         all_same   = 1;
1915                         first      = 0;
1916                         for (i = n - 1; i >= 0; --i) {
1917                                 ir_node *pred    = get_Block_cfgpred_block(block, i);
1918                                 block_t *pred_bl = get_block_entry(pred);
1919                                 ir_mode *mode    = op->value.mode;
1920                                 memop_t *e;
1921                                 ir_node *adr;
1922
1923                                 adr = phi_translate(op->value.address, block, i);
1924                                 DB((dbg, LEVEL_3, ".. using address %+F in pred %d\n", adr, i));
1925                                 e   = find_address_avail(pred_bl, register_address(adr), mode);
1926                                 if (e == NULL) {
1927                                         ir_node *ef_block = get_nodes_block(adr);
1928                                         if (! block_dominates(ef_block, pred)) {
1929                                                 /* cannot place a copy here */
1930                                                 have_some = 0;
1931                                                 DB((dbg, LEVEL_3, "%+F cannot be moved into predecessor %+F\n", op->node, pred));
1932                                                 break;
1933                                         }
1934                                         DB((dbg, LEVEL_3, "%+F is not available in predecessor %+F\n", op->node, pred));
1935                                         pred_bl->avail = NULL;
1936                                         all_same       = 0;
1937                                 } else {
1938                                         if (e->value.mode != mode && !can_convert_to(e->value.mode, mode)) {
1939                                                 /* cannot create a Phi due to different modes */
1940                                                 have_some = 0;
1941                                                 break;
1942                                         }
1943                                         pred_bl->avail = e;
1944                                         have_some      = 1;
1945                                         DB((dbg, LEVEL_3, "%+F is available for %+F in predecessor %+F\n", e->node, op->node, pred));
1946                                         if (first == NULL)
1947                                                 first = e->node;
1948                                         else if (first != e->node)
1949                                                 all_same = 0;
1950                                 }
1951                         }
1952                         if (have_some && !all_same) {
1953                                 ir_mode *mode = op->value.mode;
1954                                 ir_node **in, *phi;
1955                                 memop_t *phi_op;
1956
1957                                 NEW_ARR_A(ir_node *, in, n);
1958
1959                                 for (i = n - 1; i >= 0; --i) {
1960                                         ir_node *pred    = get_Block_cfgpred_block(block, i);
1961                                         block_t *pred_bl = get_block_entry(pred);
1962
1963                                         if (pred_bl->avail == NULL) {
1964                                                 /* create a new Load here and make to make it fully redundant */
1965                                                 dbg_info *db       = get_irn_dbg_info(op->node);
1966                                                 ir_node  *last_mem = find_last_memory(pred_bl);
1967                                                 ir_node  *load, *def, *adr;
1968                                                 memop_t  *new_op;
1969
1970                                                 assert(last_mem != NULL);
1971                                                 adr  = phi_translate(op->value.address, block, i);
1972                                                 load = new_rd_Load(db, pred, last_mem, adr, mode, cons_none);
1973                                                 def  = new_r_Proj(load, mode, pn_Load_res);
1974                                                 DB((dbg, LEVEL_1, "Created new %+F in %+F for party redundant %+F\n", load, pred, op->node));
1975
1976                                                 new_op                = alloc_memop(load);
1977                                                 new_op->mem           = new_r_Proj(load, mode_M, pn_Load_M);
1978                                                 new_op->value.address = adr;
1979                                                 new_op->value.id      = op->value.id;
1980                                                 new_op->value.mode    = mode;
1981                                                 new_op->value.value   = def;
1982
1983                                                 new_op->projs[pn_Load_M]   = new_op->mem;
1984                                                 new_op->projs[pn_Load_res] = def;
1985
1986                                                 new_op->prev = pred_bl->memop_backward;
1987                                                 if (pred_bl->memop_backward != NULL)
1988                                                         pred_bl->memop_backward->next = new_op;
1989
1990                                                 pred_bl->memop_backward = new_op;
1991
1992                                                 if (pred_bl->memop_forward == NULL)
1993                                                         pred_bl->memop_forward = new_op;
1994
1995                                                 if (get_nodes_block(last_mem) == pred) {
1996                                                         /* We have add a new last memory op in pred block.
1997                                                            If pred had already a last mem, reroute all memory
1998                                                            users. */
1999                                                         reroute_all_mem_users(last_mem, new_op->mem);
2000                                                 } else {
2001                                                         /* reroute only those memory going through the pre block */
2002                                                         reroute_mem_through(last_mem, new_op->mem, pred);
2003                                                 }
2004
2005                                                 /* we added this load at the end, so it will be avail anyway */
2006                                                 add_memop_avail(pred_bl, new_op);
2007                                                 pred_bl->avail = new_op;
2008                                         }
2009                                         in[i] = conv_to(pred_bl->avail->value.value, mode);
2010                                 }
2011                                 phi = new_r_Phi(block, n, in, mode);
2012                                 DB((dbg, LEVEL_1, "Created new %+F in %+F for now redundant %+F\n", phi, block, op->node));
2013
2014                                 phi_op = clone_memop_phi(op, phi);
2015                                 add_memop(phi_op);
2016                         }
2017                 }
2018         }
2019
2020         /* recalculate avail by gen and kill */
2021         calc_gen_kill_avail(bl);
2022
2023         /* always update the map after gen/kill, as values might have been changed due to RAR/WAR/WAW */
2024         memcpy(bl->id_2_memop_avail, env.curr_id_2_memop, env.rbs_size * sizeof(env.curr_id_2_memop[0]));
2025
2026         if (!rbitsets_equal(bl->avail_out, env.curr_set, env.rbs_size)) {
2027                 /* the avail set has changed */
2028                 rbitset_copy(bl->avail_out, env.curr_set, env.rbs_size);
2029                 dump_curr(bl, "Avail_out*");
2030                 return 1;
2031         }
2032         dump_curr(bl, "Avail_out");
2033         return 0;
2034 }  /* insert_Load */
2035
2036 /**
2037  * Insert Loads upwards.
2038  */
2039 static void insert_Loads_upwards(void)
2040 {
2041         int i, need_iter;
2042         block_t *bl;
2043
2044         /* recalculate antic_out and insert Loads */
2045         DB((dbg, LEVEL_2, "Inserting Loads\n"));
2046
2047         i = 0;
2048         do {
2049                 DB((dbg, LEVEL_2, "Iteration %d:\n=========\n", i));
2050
2051                 need_iter = 0;
2052
2053                 /* over all blocks in reverse post order, skip the start block */
2054                 for (bl = env.forward->forward_next; bl != NULL; bl = bl->forward_next) {
2055                         need_iter |= insert_Load(bl);
2056                 }
2057                 ++i;
2058         } while (need_iter);
2059
2060         DB((dbg, LEVEL_2, "Finished Load inserting after %d iterations\n", i));
2061 }  /* insert_Loads_upwards */
2062
2063 void opt_ldst(ir_graph *irg)
2064 {
2065         block_t *bl;
2066
2067         FIRM_DBG_REGISTER(dbg, "firm.opt.ldst");
2068
2069         DB((dbg, LEVEL_1, "\nDoing Load/Store optimization on %+F\n", irg));
2070
2071         assure_irg_properties(irg,
2072                 IR_GRAPH_PROPERTY_NO_CRITICAL_EDGES /* we need landing pads */
2073                 | IR_GRAPH_PROPERTY_CONSISTENT_ENTITY_USAGE
2074                 | IR_GRAPH_PROPERTY_CONSISTENT_OUTS
2075                 | IR_GRAPH_PROPERTY_NO_UNREACHABLE_CODE
2076                 | IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE);
2077
2078         if (get_opt_alias_analysis()) {
2079                 assure_irp_globals_entity_usage_computed();
2080         }
2081
2082         obstack_init(&env.obst);
2083         ir_nodehashmap_init(&env.adr_map);
2084
2085         env.forward       = NULL;
2086         env.backward      = NULL;
2087         env.curr_adr_id   = 0;
2088         env.n_mem_ops     = 0;
2089         env.max_cfg_preds = 0;
2090         env.changed       = 0;
2091         env.start_bl      = get_irg_start_block(irg);
2092         env.end_bl        = get_irg_end_block(irg);
2093 #ifdef DEBUG_libfirm
2094         env.id_2_address  = NEW_ARR_F(ir_node *, 0);
2095 #endif
2096
2097         ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_BLOCK_MARK);
2098
2099         /* first step: allocate block entries. Note that some blocks might be
2100            unreachable here. Using the normal walk ensures that ALL blocks are initialized. */
2101         irg_walk_graph(irg, prepare_blocks, link_phis, NULL);
2102
2103         /* produce an inverse post-order list for the CFG: this links only reachable
2104            blocks */
2105         irg_out_block_walk(get_irg_start_block(irg), NULL, inverse_post_order, NULL);
2106
2107         if (! get_Block_mark(env.end_bl)) {
2108                 /*
2109                  * The end block is NOT reachable due to endless loops
2110                  * or no_return calls.
2111                  * Place the end block last.
2112                  * env.backward points to the last block in the list for this purpose.
2113                  */
2114                 env.backward->forward_next = get_block_entry(env.end_bl);
2115
2116                 set_Block_mark(env.end_bl, 1);
2117         }
2118
2119         /* second step: find and sort all memory ops */
2120         walk_memory_irg(irg, collect_memops, NULL, NULL);
2121
2122 #ifdef DEBUG_libfirm
2123         /* check that the backward map is correct */
2124         assert((unsigned)ARR_LEN(env.id_2_address) == env.curr_adr_id);
2125 #endif
2126
2127         if (env.n_mem_ops == 0) {
2128                 /* no memory ops */
2129                 goto no_changes;
2130         }
2131
2132         /* create the backward links. */
2133         env.backward = NULL;
2134         irg_block_walk_graph(irg, NULL, collect_backward, NULL);
2135
2136         /* link the end block in */
2137         bl = get_block_entry(env.end_bl);
2138         bl->backward_next = env.backward;
2139         env.backward      = bl;
2140
2141         /* check that we really start with the start / end block */
2142         assert(env.forward->block  == env.start_bl);
2143         assert(env.backward->block == env.end_bl);
2144
2145         /* create address sets: for now, only the existing addresses are allowed plus one
2146            needed for the sentinel */
2147         env.rbs_size = env.curr_adr_id + 1;
2148
2149         /* create the current set */
2150         env.curr_set = rbitset_obstack_alloc(&env.obst, env.rbs_size);
2151         rbitset_set(env.curr_set, env.rbs_size - 1);
2152         env.curr_id_2_memop = NEW_ARR_D(memop_t *, &env.obst, env.rbs_size);
2153         memset(env.curr_id_2_memop, 0, env.rbs_size * sizeof(env.curr_id_2_memop[0]));
2154
2155         for (bl = env.forward; bl != NULL; bl = bl->forward_next) {
2156                 /* set sentinel bits */
2157                 bl->avail_out  = rbitset_obstack_alloc(&env.obst, env.rbs_size);
2158                 rbitset_set(bl->avail_out, env.rbs_size - 1);
2159
2160                 bl->id_2_memop_avail = NEW_ARR_D(memop_t *, &env.obst, env.rbs_size);
2161                 memset(bl->id_2_memop_avail, 0, env.rbs_size * sizeof(bl->id_2_memop_avail[0]));
2162
2163                 bl->anticL_in  = rbitset_obstack_alloc(&env.obst, env.rbs_size);
2164                 rbitset_set(bl->anticL_in, env.rbs_size - 1);
2165
2166                 bl->id_2_memop_antic = NEW_ARR_D(memop_t *, &env.obst, env.rbs_size);
2167                 memset(bl->id_2_memop_antic, 0, env.rbs_size * sizeof(bl->id_2_memop_antic[0]));
2168         }
2169
2170         (void) dump_block_list;
2171
2172         calcAvail();
2173         calcAntic();
2174
2175         insert_Loads_upwards();
2176
2177         if (env.changed) {
2178                 /* over all blocks in reverse post order */
2179                 for (bl = env.forward; bl != NULL; bl = bl->forward_next) {
2180                         do_replacements(bl);
2181                 }
2182
2183                 /* not only invalidate but free them. We might allocate new out arrays
2184                    on our obstack which will be deleted yet. */
2185                 confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_CONTROL_FLOW);
2186         } else {
2187 no_changes:
2188                 confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_ALL);
2189         }
2190
2191         ir_free_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_BLOCK_MARK);
2192         ir_nodehashmap_destroy(&env.adr_map);
2193         obstack_free(&env.obst, NULL);
2194
2195 #ifdef DEBUG_libfirm
2196         DEL_ARR_F(env.id_2_address);
2197 #endif
2198 }  /* opt_ldst */
2199
2200 ir_graph_pass_t *opt_ldst_pass(const char *name)
2201 {
2202         return def_graph_pass(name ? name : "ldst_df", opt_ldst);
2203 }  /* opt_ldst_pass */