08d2e81db2c8df0039b6bec9c5e39541d069f857
[libfirm] / ir / opt / opt_ldst.c
1 /*
2  * Copyright (C) 1995-2008 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  * @version $Id$
26  */
27 #include "config.h"
28
29 #include "irnode_t.h"
30 #include "irflag_t.h"
31 #include "array_t.h"
32 #include "ircons.h"
33 #include "irdom.h"
34 #include "irgmod.h"
35 #include "irgwalk.h"
36 #include "irouts.h"
37 #include "irgraph.h"
38 #include "irgopt.h"
39 #include "irnodemap.h"
40 #include "raw_bitset.h"
41 #include "debug.h"
42 #include "error.h"
43
44 /**
45  * Mapping an address to an dense ID.
46  */
47 typedef struct address_entry_t {
48         unsigned id;          /**< The ID */
49 } address_entry;
50
51 /**
52  * Memop-flags.
53  */
54 enum memop_flags {
55         FLAG_KILL_LOADS  =  1, /**< KILL all Loads */
56         FLAG_KILL_STORES =  2, /**< KILL all Stores */
57         FLAG_KILLED_NODE =  4, /**< this node was killed */
58         FLAG_EXCEPTION   =  8, /**< this node has exception flow */
59         FLAG_IGNORE      = 16, /**< ignore this node (volatile or other) */
60         /** this memop KILLS all addresses */
61         FLAG_KILL_ALL    = FLAG_KILL_LOADS|FLAG_KILL_STORES
62 };
63
64 /**
65  * A value: This represents a value stored at a given address in
66  * memory. Do not confuse with values from value numbering.
67  */
68 typedef struct value_t value_t;
69 struct value_t {
70         ir_node  *address;    /**< the address of this value */
71         ir_node  *value;      /**< the value itself */
72         ir_mode  *mode;       /**< the mode of the value */
73         unsigned id;          /**< address id */
74 };
75
76 /**
77  * A memop describes an memory-related operation.
78  * These are Loads/Store and all other ops that might modify
79  * memory (Calls, CopyB) or causing exceptions.
80  */
81 typedef struct memop_t memop_t;
82 struct memop_t {
83         value_t  value;      /**< the value of this memop: only defined for Load/Store */
84         ir_node  *node;      /**< the memory op itself */
85         ir_node  *mem;       /**< the memory FROM this node */
86         ir_node  *replace;   /**< the replacement node if this memop is replaced */
87         memop_t  *next;      /**< links to the next memory op in the block in forward order. */
88         memop_t  *prev;      /**< links to the previous memory op in the block in forward order. */
89         unsigned flags;      /**< memop flags */
90 };
91
92 /**
93  * Additional data for every basic block.
94  */
95 typedef struct block_t block_t;
96 struct block_t {
97         memop_t  *memop_forward;     /**< topologically sorted list of memory ops in this block */
98         memop_t  *memop_backward;    /**< last memop in the list */
99         unsigned *avail_out;         /**< out-set of available addresses */
100         memop_t  **id_2_memop_avail; /**< maps avail address ids to memops */
101         unsigned *anticL_in;         /**< in-set of anticipated Load addresses */
102         memop_t  **id_2_memop;       /**< maps address ids to memops */
103         ir_node  *block;             /**< the associated block */
104         block_t  *forward_next;      /**< next block entry for forward iteration */
105         block_t  *backward_next;     /**< next block entry for backward iteration */
106         memop_t  *avail;             /**< used locally for the avail map */
107 };
108
109 /**
110  * Metadata for this pass.
111  */
112 typedef struct ldst_env_t {
113         struct obstack  obst;         /**< obstack for temporary data */
114         ir_nodemap_t    adr_map;      /**< Map addresses to */
115         block_t         *forward;     /**< Inverse post-order list of all blocks Start->End */
116         block_t         *backward;    /**< Inverse post-order list of all blocks End->Start */
117         ir_node         *start_bl;    /**< start block of the current graph */
118         ir_node         *end_bl;      /**< end block of the current graph */
119         unsigned        *curr_set;    /**< current set of addresses */
120         unsigned        curr_adr_id;  /**< number for address mapping */
121         unsigned        n_mem_ops;    /**< number of memory operations (Loads/Stores) */
122         unsigned        rbs_size;     /**< size of all bitsets in bytes */
123         int             changed;      /**< Flags for changed graph state */
124 } ldst_env;
125
126 #ifdef DEBUG_libfirm
127
128 static firm_dbg_module_t *dbg;
129
130 /* the one and only environment */
131 static ldst_env env;
132
133 /**
134  * Dumps the block list.
135  *
136  * @param ldst environment
137  */
138 static void dump_block_list(ldst_env *env) {
139         block_t *entry;
140         memop_t *op;
141         int     i;
142
143         for (entry = env->forward; entry != NULL; entry = entry->forward_next) {
144                 DB((dbg, LEVEL_2, "%+F {", entry->block));
145
146                 i = 0;
147                 for (op = entry->memop_forward; op != NULL; op = op->next) {
148                         if (i == 0) {
149                                 DB((dbg, LEVEL_2, "\n\t"));
150                         }                       DB((dbg, LEVEL_2, "%+F", op->node));
151                         if ((op->flags & FLAG_KILL_ALL) == FLAG_KILL_ALL)
152                                 DB((dbg, LEVEL_2, "X"));
153                         else if (op->flags & FLAG_KILL_LOADS)
154                                 DB((dbg, LEVEL_2, "L"));
155                         else if (op->flags & FLAG_KILL_STORES)
156                                 DB((dbg, LEVEL_2, "S"));
157                         DB((dbg, LEVEL_2, ", "));
158
159                         i = (i + 1) & 3;
160                 }
161                 DB((dbg, LEVEL_2, "\n}\n\n"));
162         }
163 }
164
165 /**
166  * Dumps the current set.
167  *
168  * @param bl   current block
169  * @param s    name of the set
170  */
171 static void dump_curr(block_t *bl, const char *s) {
172         unsigned pos = 0;
173         unsigned end = env.n_mem_ops * 2 - 1;
174         int      i;
175
176         DB((dbg, LEVEL_2, "%s[%+F] = {", s, bl->block));
177         i = 0;
178         for (pos = rbitset_next(env.curr_set, pos, 1); pos != end; pos = rbitset_next(env.curr_set, pos + 1, 1)) {
179                 memop_t *op = bl->id_2_memop[pos];
180
181                 if (i == 0) {
182                         DB((dbg, LEVEL_2, "\n\t"));
183                 }
184                 DB((dbg, LEVEL_2, "<%+F, %+F>, ", op->value.address, op->value.value));
185                 i = (i + 1) & 3;
186         }
187         DB((dbg, LEVEL_2, "\n}\n"));
188 }
189
190 #else
191 #define dump_block_list()
192 #define dump_curr(bl, s)
193 #endif /* DEBUG_libfirm */
194
195 /** Get the block entry for a block node */
196 static block_t *get_block_entry(const ir_node *block) {
197         assert(is_Block(block));
198
199         return get_irn_link(block);
200 }
201
202 /** Get the memop entry for a memory operation node */
203 static memop_t *get_irn_memop(const ir_node *irn) {
204         assert(! is_Block(irn));
205         return get_irn_link(irn);
206 }
207
208 /**
209  * Walk over the memory edges from definition to users.
210  *
211  * @param irn   start node
212  * @param pre   pre walker function
213  * @param post  post walker function
214  * @param ctx   context parameter for the walker functions
215  */
216 static void walk_memory(ir_node *irn, irg_walk_func *pre, irg_walk_func *post, void *ctx) {
217         int     i;
218         ir_mode *mode;
219
220         mark_irn_visited(irn);
221
222         if (pre)
223                 pre(irn, ctx);
224
225         mode = get_irn_mode(irn);
226         if (mode == mode_M) {
227                 /* every successor uses memory */
228                 for (i = get_irn_n_outs(irn) - 1; i >= 0; --i) {
229                         ir_node *succ = get_irn_out(irn, i);
230
231                         if (! irn_visited(succ))
232                                 walk_memory(succ, pre, post, ctx);
233                 }
234         } else if (mode == mode_T) {
235                 /* only some Proj's uses memory */
236                 for (i = get_irn_n_outs(irn) - 1; i >= 0; --i) {
237                         ir_node *proj = get_irn_out(irn, i);
238
239                         if (get_irn_mode(proj) == mode_M && ! irn_visited(proj))
240                                 walk_memory(proj, pre, post, ctx);
241                 }
242         }
243         if (post)
244                 post(irn, ctx);
245 }
246
247 /**
248  * Walks over all memory nodes of a graph.
249  *
250  * @param irg   a graph
251  * @param pre   pre walker function
252  * @param post  post walker function
253  * @param ctx   context parameter for the walker functions
254  */
255 static void walk_memory_irg(ir_graph *irg, irg_walk_func pre, irg_walk_func post, void *ctx) {
256         inc_irg_visited(irg);
257
258         ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
259
260         /*
261          * there are two possible sources for memory: initial_mem and nomem
262          * we ignore nomem as this should NOT change the memory
263          */
264         walk_memory(get_irg_initial_mem(irg), pre, post, ctx);
265
266         ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
267 }
268
269 /**
270  * Block walker: allocate an block entry for every block.
271  */
272 static void prepare_blocks(ir_node *block, void *ctx) {
273         block_t *entry = obstack_alloc(&env.obst, sizeof(*entry));
274
275         (void) ctx;
276
277         entry->memop_forward    = NULL;
278         entry->memop_backward   = NULL;
279         entry->avail_out        = NULL;
280         entry->id_2_memop_avail = NULL;
281         entry->anticL_in        = NULL;
282         entry->id_2_memop       = NULL;
283         entry->block            = block;
284         entry->forward_next     = env.forward;
285         entry->backward_next    = NULL;
286         entry->avail            = NULL;
287         set_irn_link(block, entry);
288
289         /* create the list in inverse order */
290         env.forward  = entry;
291         /* remember temporary the last one */
292         env.backward = entry;
293 }
294
295 /**
296  * Block walker: create backward links for the memops of a block.
297  */
298 static void collect_backward(ir_node *block, void *ctx) {
299         block_t *entry = get_block_entry(block);
300         memop_t *last, *op;
301
302         (void) ctx;
303         entry->backward_next = env.backward;
304
305         /* create the list in inverse order */
306         env.backward = entry;
307
308         /* create backward links for all memory ops */
309         last = NULL;
310         for (op = entry->memop_forward; op != NULL; op = op->next) {
311                 op->prev = last;
312                 last     = op;
313         }
314         entry->memop_backward = last;
315 }
316
317 /**
318  * Allocate a memop.
319  *
320  * @param irn  the IR-node representing the memop
321  */
322 static memop_t *alloc_memop(ir_node *irn) {
323         memop_t *m = obstack_alloc(&env.obst, sizeof(*m));
324
325         m->value.address = NULL;
326         m->value.value   = NULL;
327         m->value.mode    = NULL;
328
329         m->node          = irn;
330         m->replace       = NULL;
331         m->next          = NULL;
332         m->flags         = 0;
333
334         set_irn_link(irn, m);
335         return m;
336 }
337
338 /**
339  * Register an address and allocate an ID for it.
340  *
341  * @param adr  the IR-node representing the address
342  */
343 static unsigned register_address(ir_node *adr) {
344         address_entry *entry;
345
346         /* skip Confirms and Casts */
347 restart:
348         if (is_Confirm(adr)) {
349                 adr = get_Confirm_value(adr);
350                 goto restart;
351         }
352         if (is_Cast(adr)) {
353                 adr = get_Cast_op(adr);
354                 goto restart;
355         }
356
357         entry = ir_nodemap_get(&env.adr_map, adr);
358
359         if (entry == NULL) {
360                 /* new address */
361                 entry = obstack_alloc(&env.obst, sizeof(*entry));
362
363                 entry->id = env.curr_adr_id++;
364                 ir_nodemap_insert(&env.adr_map, adr, entry);
365         }
366         return entry->id;
367 }
368
369 /**
370  * Return the memory properties of a call node.
371  *
372  * @param call  the call node
373  *
374  * return a bitset of mtp_property_const and mtp_property_pure
375  */
376 static unsigned get_Call_memory_properties(ir_node *call) {
377         ir_type *call_tp = get_Call_type(call);
378         unsigned prop = get_method_additional_properties(call_tp);
379
380         /* check first the call type */
381         if ((prop & (mtp_property_const|mtp_property_pure)) == 0) {
382                 /* try the called entity */
383                 ir_node *ptr = get_Call_ptr(call);
384
385                 if (is_Global(ptr)) {
386                         ir_entity *ent = get_Global_entity(ptr);
387
388                         prop = get_entity_additional_properties(ent);
389                 }
390         }
391         return prop & (mtp_property_const|mtp_property_pure);
392 }
393
394 /**
395  * Update a memop for a Load.
396  *
397  * @param m  the memop
398  */
399 static void update_Load_memop(memop_t *m) {
400         int     i;
401         ir_node *load = m->node;
402         ir_node *adr  = get_Load_ptr(load);
403
404         if (get_Load_volatility(load) == volatility_is_volatile)
405                 m->flags |= FLAG_IGNORE;
406
407         m->value.address = adr;
408
409         for (i = get_irn_n_outs(load) - 1; i >= 0; --i) {
410                 ir_node *proj = get_irn_out(load, i);
411
412                 /* beware of keep edges */
413                 if (is_End(proj))
414                         continue;
415
416                 switch (get_Proj_proj(proj)) {
417                 case pn_Load_res:
418                         m->value.value = proj;
419                         m->value.mode  = get_irn_mode(proj);
420                         break;
421                 case pn_Load_X_except:
422                         m->flags |= FLAG_EXCEPTION;
423                         break;
424                 case pn_Load_M:
425                         m->mem = proj;
426                         break;
427                 }
428         }
429
430         if (m->value.value != NULL && !(m->flags & FLAG_IGNORE)) {
431                 /* only create an address if this node is NOT killed immediately or ignored */
432                 m->value.id = register_address(adr);
433                 ++env.n_mem_ops;
434         } else {
435                 /* no user, KILL it */
436                 m->flags |= FLAG_KILLED_NODE;
437         }
438 }
439
440 /**
441  * Update a memop for a Store.
442  *
443  * @param m  the memop
444  */
445 static void update_Store_memop(memop_t *m) {
446         int     i;
447         ir_node *store = m->node;
448         ir_node *adr   = get_Store_ptr(store);
449
450         if (get_Store_volatility(store) == volatility_is_volatile) {
451                 m->flags |= FLAG_IGNORE;
452         } else {
453                 /* only create an address if this node is NOT ignored */
454                 m->value.id = register_address(adr);
455                 ++env.n_mem_ops;
456         }
457
458         m->value.address = adr;
459
460         for (i = get_irn_n_outs(store) - 1; i >= 0; --i) {
461                 ir_node *proj = get_irn_out(store, i);
462
463                 /* beware of keep edges */
464                 if (is_End(proj))
465                         continue;
466
467                 switch (get_Proj_proj(proj)) {
468                 case pn_Store_X_except:
469                         m->flags |= FLAG_EXCEPTION;
470                         break;
471                 case pn_Store_M:
472                         m->mem = proj;
473                         break;
474                 }
475         }
476         m->value.value = get_Store_value(store);
477         m->value.mode  = get_irn_mode(m->value.value);
478 }
479
480 /**
481  * Update a memop for a Call.
482  *
483  * @param m  the memop
484  */
485 static void update_Call_memop(memop_t *m) {
486         ir_node  *call = m->node;
487         unsigned prop  = get_Call_memory_properties(call);
488         int      i;
489
490         if (prop & mtp_property_const) {
491                 /* A constant call did NOT use memory at all, we
492                    can kick it from the list. */
493         } else if (prop & mtp_property_pure) {
494                 /* pure calls READ memory */
495                 m->flags = FLAG_KILL_STORES;
496         } else
497                 m->flags = FLAG_KILL_ALL;
498
499         for (i = get_irn_n_outs(call) - 1; i >= 0; --i) {
500                 ir_node *proj = get_irn_out(call, i);
501
502                 /* beware of keep edges */
503                 if (is_End(proj))
504                         continue;
505
506                 switch (get_Proj_proj(proj)) {
507                 case pn_Call_X_except:
508                         m->flags |= FLAG_EXCEPTION;
509                         break;
510                 case pn_Call_M_regular:
511                         m->mem = proj;
512                         break;
513                 }
514         }
515 }
516
517 /**
518  * Update a memop for a Div/Mod/Quot/DivMod.
519  *
520  * @param m  the memop
521  */
522 static void update_DivOp_memop(memop_t *m) {
523         ir_node *div = m->node;
524         int     i;
525
526         for (i = get_irn_n_outs(div) - 1; i >= 0; --i) {
527                 ir_node *proj = get_irn_out(div, i);
528
529                 /* beware of keep edges */
530                 if (is_End(proj))
531                         continue;
532
533                 switch (get_Proj_proj(proj)) {
534                 case pn_Generic_X_except:
535                         m->flags |= FLAG_EXCEPTION;
536                         break;
537                 case pn_Generic_M_regular:
538                         m->mem = proj;
539                         break;
540                 }
541         }
542 }
543
544 /**
545  * Update a memop for a Phi.
546  *
547  * @param m  the memop
548  */
549 static void update_Phi_memop(memop_t *m) {
550         /* the Phi is it's own mem */
551         m->mem = m->node;
552 }
553
554 /**
555  * Memory walker: collect all memory ops and build topological lists.
556  */
557 static void collect_memops(ir_node *irn, void *ctx) {
558         memop_t  *op;
559         ir_node  *block;
560         block_t  *entry;
561
562         (void) ctx;
563         if (is_Proj(irn)) {
564                 /* we can safely ignore ProjM's except the initial memory */
565                 if (irn != get_irg_initial_mem(current_ir_graph))
566                         return;
567         }
568
569         op    = alloc_memop(irn);
570         block = get_nodes_block(irn);
571         entry = get_block_entry(block);
572
573         if (is_Phi(irn)) {
574                 update_Phi_memop(op);
575                 /* Phis must be always placed first */
576                 op->next = entry->memop_forward;
577                 entry->memop_forward = op;
578                 if (entry->memop_backward == NULL)
579                         entry->memop_backward = op;
580         } else {
581                 switch (get_irn_opcode(irn)) {
582                 case iro_Load:
583                         update_Load_memop(op);
584                         break;
585                 case iro_Store:
586                         update_Store_memop(op);
587                         break;
588                 case iro_Call:
589                         update_Call_memop(op);
590                         break;
591                 case iro_Sync:
592                 case iro_Pin:
593                         op->mem = irn;
594                         break;
595                 case iro_Proj:
596                         /* initial memory */
597                         op->mem = irn;
598                         break;
599                 case iro_Return:
600                 case iro_End:
601                         /* we can those to find the memory edge */
602                         break;
603                 case iro_Div:
604                 case iro_DivMod:
605                 case iro_Quot:
606                 case iro_Mod:
607                         update_DivOp_memop(op);
608                         break;
609
610                 case iro_Builtin:
611                         /* TODO: handle some builtins */
612                 default:
613                         /* unsupported operation */
614                         op->flags = FLAG_KILL_ALL;
615                 }
616
617
618                 /* all other should be placed last */
619                 if (entry->memop_backward == NULL) {
620                         entry->memop_forward = entry->memop_backward = op;
621                 } else {
622                         entry->memop_backward->next = op;
623                         entry->memop_backward       = op;
624                 }
625         }
626 }
627
628 /**
629  * Find an address in the current set.
630  *
631  * @param bl     the block
632  * @param value  the value to be searched for
633  */
634 static memop_t *find_address(const block_t *bl, const value_t *value) {
635         if (rbitset_is_set(env.curr_set, value->id)) {
636                 memop_t *res = bl->id_2_memop[value->id];
637
638                 if (res->value.mode == value->mode)
639                         return res;
640                 /* allow hidden casts */
641                 if (get_mode_arithmetic(res->value.mode) == irma_twos_complement &&
642                     get_mode_arithmetic(value->mode) == irma_twos_complement &&
643                     get_mode_size_bits(res->value.mode) == get_mode_size_bits(value->mode))
644                         return res;
645         }
646         return NULL;
647 }
648
649 /**
650  * Find an address in the avail_out set.
651  *
652  * @param bl     the block
653  * @param value  the value to be searched for
654  */
655 static memop_t *find_address_avail(const block_t *bl, const value_t *value) {
656         if (rbitset_is_set(bl->avail_out, value->id)) {
657                 memop_t *res = bl->id_2_memop_avail[value->id];
658
659                 if (res->value.mode == value->mode)
660                         return res;
661                 /* allow hidden casts */
662                 if (get_mode_arithmetic(res->value.mode) == irma_twos_complement &&
663                     get_mode_arithmetic(value->mode) == irma_twos_complement &&
664                     get_mode_size_bits(res->value.mode) == get_mode_size_bits(value->mode))
665                         return res;
666         }
667         return NULL;
668 }
669
670 /**
671  * Kill all Loads from the current set.
672  *
673  * @param bl  the current block
674  */
675 static void kill_all_loads(block_t *bl) {
676         unsigned pos = 0;
677         unsigned end = env.n_mem_ops * 2 - 1;
678
679         for (pos = rbitset_next(env.curr_set, pos, 1); pos != end; pos = rbitset_next(env.curr_set, pos + 1, 1)) {
680                 memop_t *op = bl->id_2_memop[pos];
681
682                 if (! is_Store(op->node))
683                         rbitset_clear(env.curr_set, pos);
684         }
685 }
686
687 /**
688  * Kill all Stores from the current set.
689  *
690  * @param bl  the current block
691  */
692 static void kill_all_stores(block_t *bl) {
693         unsigned pos = 0;
694         unsigned end = env.n_mem_ops * 2 - 1;
695
696         for (pos = rbitset_next(env.curr_set, pos, 1); pos != end; pos = rbitset_next(env.curr_set, pos + 1, 1)) {
697                 memop_t *op = bl->id_2_memop[pos];
698
699                 if (is_Store(op->node))
700                         rbitset_clear(env.curr_set, pos);
701         }
702 }
703
704 /**
705  * Kill all addresses from the current set.
706  */
707 static void kill_all(void) {
708         rbitset_clear_all(env.curr_set, env.rbs_size);
709
710         /* set sentinel */
711         rbitset_set(env.curr_set, env.rbs_size - 1);
712 }
713
714
715 /**
716  * Kill Stores that are not alias free due to a Load value from the current set.
717  *
718  * @param bl     the block
719  * @param value  the Load value
720  */
721 static void kill_stores(block_t *bl, const value_t *value) {
722         unsigned pos = 0;
723         unsigned end = env.n_mem_ops * 2 - 1;
724
725         for (pos = rbitset_next(env.curr_set, pos, 1); pos != end; pos = rbitset_next(env.curr_set, pos + 1, 1)) {
726                 memop_t *op = bl->id_2_memop[pos];
727
728                 if (is_Store(op->node)) {
729                         if (ir_no_alias != get_alias_relation(current_ir_graph, value->address, value->mode,
730                                                               op->value.address, op->value.mode)) {
731                                 rbitset_clear(env.curr_set, pos);
732                                 bl->id_2_memop[pos] = NULL;
733                         }
734                 }
735         }
736 }
737
738 /**
739  * Kill memops that are not alias free due to a Store value from the current set.
740  *
741  * @param bl     the block
742  * @param value  the Store value
743  */
744 static void kill_memops(block_t *bl, const value_t *value) {
745         unsigned pos = 0;
746         unsigned end = env.n_mem_ops * 2 - 1;
747
748         for (pos = rbitset_next(env.curr_set, pos, 1); pos != end; pos = rbitset_next(env.curr_set, pos + 1, 1)) {
749                 memop_t *op = bl->id_2_memop[pos];
750
751                 if (ir_no_alias != get_alias_relation(current_ir_graph, value->address, value->mode,
752                                                           op->value.address, op->value.mode)) {
753                         rbitset_clear(env.curr_set, pos);
754                         bl->id_2_memop[pos] = NULL;
755                 }
756         }
757 }
758
759 /**
760  * Add the value of a memop to the current set.
761  *
762  * @param bl  the block
763  * @param op  the memory op
764  */
765 static void add_memop(block_t *bl, memop_t *op) {
766         rbitset_set(env.curr_set, op->value.id);
767         bl->id_2_memop[op->value.id] = op;
768 }
769
770 /**
771  * Add the value of a memop to the avail_out set.
772  *
773  * @param bl  the block
774  * @param op  the memory op
775  */
776 static void add_memop_avail(block_t *bl, memop_t *op) {
777         rbitset_set(bl->avail_out, op->value.id);
778         bl->id_2_memop_avail[op->value.id] = op;
779 }
780
781 /**
782  * build a phi definition for a value in the given block
783  *
784  * @param block  the block
785  * @param value  the value
786  *
787  * @return the definition
788  */
789 static ir_node *build_phi_definition(ir_node *block, const value_t *value) {
790         ir_node **in, *phi;
791         int     i, n;
792         memop_t *mop;
793
794         /* no: we need a new Phi */
795         n = get_Block_n_cfgpreds(block);
796
797         while (n == 1) {
798                 block = get_Block_cfgpred_block(block, 0);
799                 n     = get_Block_n_cfgpreds(block);
800                 mop   = find_address(get_block_entry(block), value);
801
802                 assert(mop != NULL);
803                 value = &mop->value;
804         }
805
806         NEW_ARR_A(ir_node *, in, n);
807         for (i = n - 1; i >= 0; --i) {
808                 ir_node *pred_bl = get_Block_cfgpred_block(block, i);
809                 ir_node *def_bl;
810
811                 mop    = find_address(get_block_entry(pred_bl), value);
812                 def_bl = get_nodes_block(mop->value.value);
813
814                 if (block_dominates(def_bl, pred_bl))
815                         in[i] = mop->value.value;
816                 else
817                         in[i] = build_phi_definition(pred_bl, &mop->value);
818         }
819
820         phi = new_r_Phi(current_ir_graph, block, n, in, value->mode);
821         DB((dbg, LEVEL_2, "Created new Phi %+F for value %+F in block %+F\n", phi, value->value, block));
822         return phi;
823 }
824
825 /**
826  * find a definition for a value in the given block or above.
827  *
828  * @param block  the block
829  * @param op     the memop: the definition must dominate it
830  * @param value  the value
831  *
832  * @return the definition
833  */
834 static ir_node *find_definition(ir_node *block, const memop_t *op, const value_t *value) {
835         ir_node *def_block = get_nodes_block(value->value);
836
837         if (def_block == block) {
838                 /* the value is in our block: check, if it is above in the memory list */
839                 const memop_t *p;
840
841                 for (p = op->prev; p != NULL; p = p->prev) {
842                         if (!(p->flags & FLAG_KILLED_NODE) &&
843                             p->value.address == value->address) {
844                                 /* found */
845                                 assert(p->value.value == value->value);
846                                 return p->value.value;
847                         }
848                 }
849         } else if (block_dominates(def_block, block)) {
850                 /* strictly dominates */
851                 return value->value;
852         }
853
854         return build_phi_definition(block, value);
855 }
856
857 /**
858  * Mark a Load memop to be replace by a definition
859  *
860  * @param op  the Load memop
861  */
862 static void mark_replace_load(memop_t *op, ir_node *def) {
863         op->replace = def;
864         op->flags |= FLAG_KILLED_NODE;
865         env.changed = 1;
866 }
867
868 /**
869  * Mark a Store memop to be removed.
870  *
871  * @param op  the Store memop
872  */
873 static void mark_remove_store(memop_t *op) {
874         op->flags |= FLAG_KILLED_NODE;
875         env.changed = 1;
876 }
877
878 #define BYTE_SIZE(x)  (((x) + 7) >> 3)
879
880 /**
881  * Do forward dataflow analysis on a given block to calculate the avail_out set.
882  *
883  * @param bl  the block
884  *
885  * @return non-zero if the set has changed since last iteration
886  */
887 static int forward_avail(block_t *bl) {
888         memop_t *op;
889         int     n;
890         ir_node *def;
891         ir_node *pred    = get_Block_cfgpred_block(bl->block, 0);
892         block_t *pred_bl = get_block_entry(pred);
893
894         rbitset_cpy(env.curr_set, pred_bl->avail_out, env.rbs_size);
895
896         n = get_Block_n_cfgpreds(bl->block);
897         if (n > 1) {
898                 int i, pos;
899
900                 /* more than one predecessors, calculate the join */
901                 for (i = n - 1; i > 0; --i) {
902                         ir_node *pred    = skip_Proj(get_Block_cfgpred(bl->block, i));
903                         block_t *pred_bl = get_block_entry(get_nodes_block(pred));
904
905                         rbitset_and(env.curr_set, pred_bl->avail_out, env.rbs_size);
906
907                         if (is_Load(pred) || is_Store(pred)) {
908                                 /* We reached this block by an exception from a Load or Store:
909                                  * the memop was NOT completed than, kill it
910                                  */
911                                 memop_t *exc_op = get_irn_memop(pred);
912                                 rbitset_clear(env.curr_set, exc_op->value.id);
913                         }
914
915                 }
916                 /* sure that all values are in the map */
917                 for (pos = env.rbs_size - 1; pos >= 0; --pos) {
918                         if (! rbitset_is_set(env.curr_set, pos))
919                                 bl->id_2_memop[pos] = NULL;
920                         else {
921                                 for (i = n - 1; i >= 0; --i) {
922                                         ir_node *pred    = get_Block_cfgpred_block(bl->block, i);
923                                         block_t *pred_bl = get_block_entry(pred);
924
925                                         if (pred_bl->id_2_memop[pos] != NULL) {
926                                                 bl->id_2_memop[pos] = pred_bl->id_2_memop[pos];
927                                                 break;
928                                         }
929                                 }
930                         }
931                 }
932         } else {
933                 /* only one predecessor, simply copy the map */
934                 memcpy(bl->id_2_memop, pred_bl->id_2_memop, env.rbs_size * sizeof(bl->id_2_memop[0]));
935         }
936
937         dump_curr(bl, "Avail_in");
938
939         for (op = bl->memop_forward; op != NULL; op = op->next) {
940                 switch (get_irn_opcode(op->node)) {
941                 case iro_Phi:
942                         /* meet */
943                         break;
944                 case iro_Sync:
945                         /* join */
946                         break;
947                 case iro_Load:
948                         if (! (op->flags & (FLAG_KILLED_NODE|FLAG_IGNORE))) {
949                                 /* do we have this already? */
950                                 memop_t *other = find_address(bl, &op->value);
951                                 if (other != NULL) {
952                                         def = find_definition(bl->block, op, &other->value);
953                                         if (is_Store(other->node)) {
954                                                 /* RAW */
955                                                 DB((dbg, LEVEL_1, "RAW %+F <- %+F(%+F)\n", op->node, def, other->node));
956                                         } else {
957                                                 /* RAR */
958                                                 DB((dbg, LEVEL_1, "RAR %+F <- %+F(%+F)\n", op->node, def, other->node));
959                                         }
960                                         mark_replace_load(op, def);
961                                 } else {
962                                         /* add this value */
963                                         kill_stores(bl, &op->value);
964                                         add_memop(bl, op);
965                                 }
966                         }
967                         break;
968                 case iro_Store:
969                         if (! (op->flags & (FLAG_KILLED_NODE|FLAG_IGNORE))) {
970                                 /* do we have this store already */
971                                 memop_t *other = find_address(bl, &op->value);
972                                 if (other != NULL) {
973                                         if (is_Store(other->node) &&
974                                             get_nodes_block(other->node) == get_nodes_block(op->node)) {
975                                                 /*
976                                                  * A WAW in the same block we can kick the first store.
977                                                  * This is a shortcut: we know that the second Store will be anticipated
978                                                  * then in an case.
979                                                  */
980                                                 DB((dbg, LEVEL_1, "WAW %+F <- %+F\n", op->node, other->node));
981                                                 mark_remove_store(other);
982                                                 /* FIXME: a Load might be get freed due to this killed store */
983                                         } else if (other->value.value == op->value.value) {
984                                                 /* WAR */
985                                                 DB((dbg, LEVEL_1, "WAR %+F <- %+F\n", op->node, other->node));
986                                                 mark_remove_store(op);
987                                         } else {
988                                                 /* we overwrite the value that was loaded */
989                                                 add_memop(bl, op);
990                                         }
991                                 } else {
992                                         /* add this value */
993                                         kill_memops(bl, &op->value);
994                                         add_memop(bl, op);
995                                 }
996                         }
997                         break;
998                 default:
999                         switch (op->flags & (FLAG_KILL_LOADS|FLAG_KILL_STORES)) {
1000                         case FLAG_KILL_LOADS|FLAG_KILL_STORES:
1001                                 kill_all();
1002                                 break;
1003                         case FLAG_KILL_LOADS:
1004                                 kill_all_loads(bl);
1005                                 break;
1006                         case FLAG_KILL_STORES:
1007                                 kill_all_stores(bl);
1008                                 break;
1009                         case 0:
1010                                 break;
1011                         }
1012                 }
1013         }
1014         if (!rbitset_equal(bl->avail_out, env.curr_set, env.rbs_size)) {
1015                 /* changed */
1016                 rbitset_cpy(bl->avail_out, env.curr_set, env.rbs_size);
1017                 dump_curr(bl, "Avail_out*");
1018                 return 1;
1019         }
1020         dump_curr(bl, "Avail_out");
1021         return 0;
1022 }
1023
1024 /**
1025  * Do backward dataflow analysis on a given block to calculate the antic set
1026  * of Loaded addresses.
1027  *
1028  * @param bl  the block
1029  *
1030  * @return non-zero if the set has changed since last iteration
1031  */
1032 static int backward_antic(block_t *bl) {
1033         memop_t *op;
1034         ir_node *succ    = get_Block_cfg_out(bl->block, 0);
1035         block_t *succ_bl = get_block_entry(succ);
1036         int     n;
1037
1038         rbitset_cpy(env.curr_set, succ_bl->anticL_in, env.rbs_size);
1039         memcpy(bl->id_2_memop, succ_bl->id_2_memop, env.rbs_size * sizeof(bl->id_2_memop[0]));
1040
1041         n = get_Block_n_cfg_outs(bl->block);
1042         if (n > 1) {
1043                 int i;
1044
1045                 for (i = n - 1; i > 0; --i) {
1046                         ir_node *succ    = get_Block_cfg_out(bl->block, i);
1047                         block_t *succ_bl = get_block_entry(succ);
1048
1049                         rbitset_and(env.curr_set, succ_bl->anticL_in, env.rbs_size);
1050                 }
1051         }
1052
1053 #if 0
1054         /* cleanup: kill those Loads which address is not available */
1055         for (pos = rbitset_next(env.curr_set, pos, 1); pos != end; pos = rbitset_next(env.curr_set, pos + 1, 1)) {
1056                 memop_t *op     = succ_bl->id_2_memop[pos];
1057                 ir_node *ptr    = get_Load_ptr(op->node);
1058                 ir_node *ptr_bl = get_nodes_block(ptr);
1059
1060                 if (!block_dominates(ptr_bl, bl->block))
1061                         rbitset_clear(env.curr_set, pos);
1062         }
1063 #endif
1064
1065         dump_curr(bl, "AnticL_out");
1066
1067         for (op = bl->memop_backward; op != NULL; op = op->prev) {
1068                 switch (get_irn_opcode(op->node)) {
1069                 case iro_Phi:
1070                         /* meet */
1071                         break;
1072                 case iro_Sync:
1073                         /* join */
1074                         break;
1075                 case iro_Load:
1076                         if (! (op->flags & (FLAG_KILLED_NODE|FLAG_IGNORE))) {
1077                                 /* always add it */
1078                                 add_memop(bl, op);
1079                         }
1080                         break;
1081                 case iro_Store:
1082                         if (! (op->flags & (FLAG_KILLED_NODE|FLAG_IGNORE))) {
1083                                 /* a Store: check which memops must be killed */
1084                                 kill_memops(bl, &op->value);
1085                         }
1086                         break;
1087                 default:
1088                         switch (op->flags & (FLAG_KILL_LOADS|FLAG_KILL_STORES)) {
1089                         case FLAG_KILL_LOADS|FLAG_KILL_STORES:
1090                                 kill_all();
1091                                 break;
1092                         case FLAG_KILL_LOADS:
1093                                 kill_all_loads(bl);
1094                                 break;
1095                         case FLAG_KILL_STORES:
1096                                 kill_all_stores(bl);
1097                                 break;
1098                         case 0:
1099                                 break;
1100                         }
1101                 }
1102         }
1103         dump_curr(bl, "AnticL_in");
1104         if (! rbitset_equal(bl->anticL_in, env.curr_set, env.rbs_size)) {
1105                 /* changed */
1106                 rbitset_cpy(bl->anticL_in, env.curr_set, env.rbs_size);
1107                 return 1;
1108         }
1109         return 0;
1110 }
1111
1112 /**
1113  * Replace a Load memop by a already known value.
1114  *
1115  * @param op  the Load memop
1116  */
1117 static void replace_load(memop_t *op) {
1118         ir_node *load = op->node;
1119         ir_node *def  = skip_Id(op->replace);
1120         int     i;
1121         ir_mode *mode;
1122
1123         if (def != NULL)
1124                 DB((dbg, LEVEL_1, "Replacing %+F by definition %+F\n", load, is_Proj(def) ? get_Proj_pred(def) : def));
1125         else {
1126                 if (op->flags & FLAG_EXCEPTION) {
1127                         /* bad: this node is unused and executed for exception only */
1128                         DB((dbg, LEVEL_1, "Unused %+F executed for exception only ...\n", load));
1129                         return;
1130                 }
1131                 DB((dbg, LEVEL_1, "Killing unused %+F\n", load));
1132         }
1133         for (i = get_irn_n_outs(load) - 1; i >= 0; --i) {
1134                 ir_node *proj = get_irn_out(load, i);
1135
1136                 switch (get_Proj_proj(proj)) {
1137                 case pn_Load_M:
1138                         exchange(proj, get_Load_mem(load));
1139                         break;
1140                 case pn_Load_res:
1141                         mode = get_irn_mode(proj);
1142                         if (get_irn_mode(def) != mode) {
1143                                 /* a hidden cast */
1144                                 dbg_info *db    = get_irn_dbg_info(load);
1145                                 ir_node  *block = get_nodes_block(proj);
1146                                 def = new_rd_Conv(db, current_ir_graph, block, def, mode);
1147                         }
1148                         exchange(proj, def);
1149                         break;
1150                 case pn_Load_X_except:
1151                         exchange(proj, new_Bad());
1152                         break;
1153                 case pn_Load_X_regular:
1154                         exchange(proj, new_r_Jmp(current_ir_graph, get_nodes_block(load)));
1155                         break;
1156                 default:
1157                         panic("Unknown Proj from Load");
1158                 }
1159         }
1160 }
1161
1162 /**
1163  * Remove a Store memop.
1164  *
1165  * @param op  the Store memop
1166  */
1167 static void remove_store(memop_t *op) {
1168         ir_node *store = op->node;
1169         int     i;
1170
1171         DB((dbg, LEVEL_1, "Removing %+F\n", store));
1172         for (i = get_irn_n_outs(store) - 1; i >= 0; --i) {
1173                 ir_node *proj = get_irn_out(store, i);
1174
1175                 switch (get_Proj_proj(proj)) {
1176                 case pn_Store_M:
1177                         exchange(proj, get_Store_mem(store));
1178                         break;
1179                 case pn_Store_X_except:
1180                         exchange(proj, new_Bad());
1181                         break;
1182                 case pn_Store_X_regular:
1183                         exchange(proj, new_r_Jmp(current_ir_graph, get_nodes_block(store)));
1184                         break;
1185                 default:
1186                         panic("Unknown Proj from Store");
1187                 }
1188         }
1189 }
1190
1191
1192 /**
1193  * Do all necessary replacements for a given block.
1194  *
1195  * @param bl  the block
1196  */
1197 static void do_replacements(block_t *bl) {
1198         memop_t *op;
1199
1200         for (op = bl->memop_forward; op != NULL; op = op->next) {
1201                 if (op->flags & FLAG_KILLED_NODE) {
1202                         switch (get_irn_opcode(op->node)) {
1203                         case iro_Load:
1204                                 replace_load(op);
1205                                 break;
1206                         case iro_Store:
1207                                 remove_store(op);
1208                                 break;
1209                         }
1210                 }
1211         }
1212 }
1213
1214 /**
1215  * Calculate the Avail_out sets for all basic blocks.
1216  */
1217 static void calcAvail(void) {
1218         int i, need_iter;
1219         block_t *bl;
1220
1221         /* calculate avail_out */
1222         DB((dbg, LEVEL_2, "Calculate Avail_out\n"));
1223         i = 0;
1224         do {
1225                 DB((dbg, LEVEL_2, "Iteration %d:\n=========\n", i));
1226
1227                 need_iter = 0;
1228
1229                 /* over all blocks in reverse post order, skip the start block */
1230                 for (bl = env.forward->forward_next; bl != NULL; bl = bl->forward_next) {
1231                         need_iter |= forward_avail(bl);
1232                 }
1233                 ++i;
1234         } while (need_iter);
1235
1236         /* copy the content of the id_2_memop map into the id_2_memop_avail map
1237            as it must be preserved for later use */
1238         for (bl = env.forward->forward_next; bl != NULL; bl = bl->forward_next) {
1239                 memop_t **t = bl->id_2_memop_avail;
1240
1241                 bl->id_2_memop_avail = bl->id_2_memop;
1242                 bl->id_2_memop       = t;
1243         }
1244         DB((dbg, LEVEL_2, "Get avail set after %d iterations\n\n", i));
1245 }
1246
1247 /**
1248  * Calculate the Antic_in sets for all basic blocks.
1249  */
1250 static void calcAntic(void) {
1251         int i, need_iter;
1252
1253         /* calculate antic_out */
1254         DB((dbg, LEVEL_2, "Calculate Antic_in\n"));
1255         i = 0;
1256         do {
1257                 block_t *bl;
1258
1259                 DB((dbg, LEVEL_2, "Iteration %d:\n=========\n", i));
1260
1261                 need_iter = 0;
1262
1263                 /* over all blocks in reverse post order */
1264                 for (bl = env.backward->backward_next; bl != NULL; bl = bl->backward_next) {
1265                         need_iter |= backward_antic(bl);
1266                 }
1267                 ++i;
1268         } while (need_iter);
1269         DB((dbg, LEVEL_2, "Get anticipated Load set after %d iterations\n", i));
1270 }
1271
1272 /**
1273  * Return the node representing the last memory in a block.
1274  *
1275  * @param bl  the block
1276  */
1277 static ir_node *find_first_memory(block_t *bl) {
1278         for (;;) {
1279                 if (bl->memop_forward != NULL) {
1280                         return bl->memop_forward->node;
1281                 }
1282                 /* if there is NO memory in this block, go to the post dominator */
1283                 bl = get_block_entry(get_Block_ipostdom(bl->block));
1284         }
1285 }
1286
1287 /**
1288  * Return the node representing the last memory in a block.
1289  *
1290  * @param bl  the block
1291  */
1292 static ir_node *find_last_memory(block_t *bl) {
1293         for (;;) {
1294                 if (bl->memop_backward != NULL) {
1295                         return bl->memop_backward->mem;
1296                 }
1297                 /* if there is NO memory in this block, go to the dominator */
1298                 bl = get_block_entry(get_Block_idom(bl->block));
1299         }
1300 }
1301
1302 /**
1303  * Reroute all memory users of old memory
1304  * to a new memory IR-node.
1305  *
1306  * @param omem  the old memory IR-node
1307  * @param nmem  the new memory IR-node
1308  */
1309 static void reroute_all_mem_users(ir_node *omem, ir_node *nmem) {
1310         int i;
1311
1312         for (i = get_irn_n_outs(omem) - 1; i >= 0; --i) {
1313                 int     n_pos;
1314                 ir_node *user = get_irn_out_ex(omem, i, &n_pos);
1315
1316                 set_irn_n(user, n_pos, nmem);
1317         }
1318
1319         /* all edges previously point to omem now point to nmem */
1320         nmem->out = omem->out;
1321 }
1322
1323 /**
1324  * Reroute memory users of old memory that are dominated by a given block
1325  * to a new memory IR-node.
1326  *
1327  * @param omem     the old memory IR-node
1328  * @param nmem     the new memory IR-node
1329  * @param pass_bl  the block the memory must pass
1330  */
1331 static void reroute_mem_through(ir_node *omem, ir_node *nmem, ir_node *pass_bl) {
1332         int             i, j, n = get_irn_n_outs(omem);
1333         ir_def_use_edge *edges = NEW_ARR_D(ir_def_use_edge, &env.obst, n + 1);
1334
1335         for (i = j = 0; i < n; ++i) {
1336                 int     n_pos;
1337                 ir_node *user   = get_irn_out_ex(omem, i, &n_pos);
1338                 ir_node *use_bl = get_nodes_block(user);
1339
1340
1341                 if (is_Phi(user)) {
1342                         use_bl = get_Block_cfgpred_block(use_bl, n_pos);
1343                 }
1344                 if (block_dominates(pass_bl, use_bl)) {
1345                         /* found an user that is dominated */
1346                         ++j;
1347                         edges[j].pos = n_pos;
1348                         edges[j].use = user;
1349
1350                         set_irn_n(user, n_pos, nmem);
1351                 }
1352         }
1353
1354         /* Modify the out structure: we create a new out edge array on our
1355            temporary obstack here. This should be no problem, as we invalidate the edges
1356            at the end either. */
1357         /* first entry is used for the length */
1358         edges[0].pos = j;
1359         nmem->out = edges;
1360 }
1361
1362
1363 /**
1364  * insert
1365  */
1366 static void insert_Load(ir_node *block, void *ctx) {
1367         int     *new_stuff = ctx;
1368         block_t *bl;
1369         int     i, n = get_Block_n_cfgpreds(block);
1370         unsigned pos = 0;
1371         unsigned end = env.n_mem_ops * 2 - 1;
1372
1373         if (n <= 1)
1374                 return;
1375
1376         bl = get_block_entry(block);
1377
1378         for (pos = rbitset_next(bl->anticL_in, pos, 1); pos != end; pos = rbitset_next(bl->anticL_in, pos + 1, 1)) {
1379                 memop_t *op = bl->id_2_memop[pos];
1380                 int     have_some, all_same;
1381                 ir_node *first;
1382
1383                 assert(is_Load(op->node));
1384
1385                 if (op->flags & FLAG_KILLED_NODE)
1386                         continue;
1387
1388                 have_some  = 0;
1389                 all_same   = 1;
1390                 first      = 0;
1391                 for (i = n - 1; i >= 0; --i) {
1392                         ir_node *pred    = get_Block_cfgpred_block(block, i);
1393                         block_t *pred_bl = get_block_entry(pred);
1394                         memop_t *e       = find_address_avail(pred_bl, &op->value);
1395
1396                         if (e == NULL) {
1397                                 ir_node *block = get_nodes_block(op->value.address);
1398                                 if (! block_dominates(block, pred)) {
1399                                         /* cannot place a copy here */
1400                                         have_some = 0;
1401                                         break;
1402                                 }
1403                                 pred_bl->avail = NULL;
1404                                 all_same       = 0;
1405                         } else {
1406                                 pred_bl->avail = e;
1407                                 have_some      = 1;
1408                                 if (first == NULL)
1409                                         first = e->node;
1410                                 else if (first != e->node)
1411                                         all_same = 0;
1412                         }
1413                 }
1414                 if (have_some && !all_same) {
1415                         ir_mode *mode = op->value.mode;
1416                         ir_node **in, *phi;
1417
1418                         NEW_ARR_A(ir_node *, in, n);
1419
1420                         for (i = n - 1; i >= 0; --i) {
1421                                 ir_node *pred    = get_Block_cfgpred_block(block, i);
1422                                 block_t *pred_bl = get_block_entry(pred);
1423
1424                                 if (pred_bl->avail == NULL) {
1425                                         /* create a new Load here and make to make it fully redundant */
1426                                         dbg_info *db       = get_irn_dbg_info(op->node);
1427                                         ir_node  *last_mem = find_last_memory(pred_bl);
1428                                         ir_node  *load, *def;
1429                                         memop_t  *new_op;
1430
1431                                         assert(last_mem != NULL);
1432                                         load = new_rd_Load(db, current_ir_graph, pred, last_mem, op->value.address, mode, cons_none);
1433                                         def  = new_r_Proj(current_ir_graph, pred, load, mode, pn_Load_res);
1434                                         DB((dbg, LEVEL_1, "Created new %+F for party redundant %+F\n", load, op->node));
1435
1436                                         new_op                = alloc_memop(load);
1437                                         new_op->mem           = new_r_Proj(current_ir_graph, pred, load, mode_M, pn_Load_M);
1438                                         new_op->value.address = op->value.address;
1439                                         new_op->value.id      = op->value.id;
1440                                         new_op->value.mode    = mode;
1441                                         new_op->value.value   = def;
1442
1443                                         new_op->prev            = pred_bl->memop_backward;
1444                                         pred_bl->memop_backward = new_op;
1445
1446                                         if (get_nodes_block(last_mem) == pred) {
1447                                                 /* We have add a new last memory op in pred block.
1448                                                    If pred had already a last mem, reroute all memory
1449                                                    users. */
1450                                                 reroute_all_mem_users(last_mem, new_op->mem);
1451                                         } else {
1452                                                 /* reroute only those memory going through the pre block */
1453                                                 reroute_mem_through(last_mem, new_op->mem, pred);
1454                                         }
1455
1456                                         /* we added this load at the end, so it will be avail anyway */
1457                                         add_memop_avail(pred_bl, new_op);
1458                                         pred_bl->avail = new_op;
1459                                 }
1460                                 in[i] = pred_bl->avail->value.value;
1461                         }
1462                         phi = new_r_Phi(current_ir_graph, block, n, in, mode);
1463                         mark_replace_load(op, phi);
1464                         *new_stuff = 1;
1465
1466                         if (get_nodes_block(op->node) == block) {
1467                                 /* The redundant node was in the current block:
1468                                    In that case, DO NOT update avail_out. If it was NOT
1469                                    avail although it is executed in this bLock, it is killed by a later
1470                                    instruction.
1471                                  */
1472                         } else {
1473                                 /* The redundant node is NOT in the current block and anticipated.
1474                                    This can only happen IFF nothings kills the Load in the current block,
1475                                    so it will be avail in the next iteration.
1476                                  */
1477                                 add_memop_avail(bl, op);
1478
1479                                 /* TODO propagate it downwards */
1480                         }
1481                 }
1482         }
1483 }
1484
1485 /**
1486  * Insert Loads upwards.
1487  */
1488 static void insert_Loads_upwards(void) {
1489         int i, need_iter;
1490
1491         /* calculate antic_out */
1492         DB((dbg, LEVEL_2, "Inserting Loads\n"));
1493         i = 0;
1494         do {
1495                 DB((dbg, LEVEL_2, "Iteration %d:\n=========\n", i));
1496
1497                 need_iter = 0;
1498                 dom_tree_walk_irg(current_ir_graph, insert_Load, NULL, &need_iter);
1499                 ++i;
1500         } while (need_iter);
1501         DB((dbg, LEVEL_2, "Finished Load inserting after %d iterations\n", i));
1502 }
1503
1504 int opt_ldst(ir_graph *irg) {
1505         block_t  *bl;
1506         ir_graph *rem = current_ir_graph;
1507
1508         current_ir_graph = irg;
1509
1510         FIRM_DBG_REGISTER(dbg, "firm.opt.ldst");
1511
1512         DB((dbg, LEVEL_1, "\nDoing Load/Store optimization on %+F\n", irg));
1513
1514         /* we need landing pads */
1515         remove_critical_cf_edges(irg);
1516
1517         dump_ir_block_graph(irg, "-XXX");
1518
1519         if (get_opt_alias_analysis()) {
1520                 assure_irg_entity_usage_computed(irg);
1521                 assure_irp_globals_entity_usage_computed();
1522         }
1523
1524         obstack_init(&env.obst);
1525         ir_nodemap_init(&env.adr_map);
1526
1527         env.forward     = NULL;
1528         env.backward    = NULL;
1529         env.curr_adr_id = 0;
1530         env.n_mem_ops   = 0;
1531         env.changed     = 0;
1532         env.start_bl    = get_irg_start_block(irg);
1533         env.end_bl      = get_irg_end_block(irg);
1534
1535         assure_doms(irg);
1536         assure_irg_outs(irg);
1537
1538         ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
1539
1540         /* first step: allocate block entries: produces an
1541            inverse post-order list for the CFG */
1542         set_irn_link(env.end_bl, NULL);
1543         irg_out_block_walk(get_irg_start_block(irg), NULL, prepare_blocks, NULL);
1544
1545         if (get_block_entry(env.end_bl) == NULL) {
1546                 /*
1547                  * The end block is NOT reachable due to endless loops
1548                  * or no_return calls. Ensure that it is initialized.
1549                  * Note that this places the entry for the end block first, so we must fix this.
1550                  * env.backwards points to th last block for this purpose.
1551                  */
1552                 prepare_blocks(env.end_bl, NULL);
1553
1554                 bl               = env.forward;
1555                 env.forward      = bl->forward_next;
1556                 bl->forward_next = NULL;
1557
1558                 env.backward->forward_next = bl;
1559         }
1560
1561         /* second step: find and sort all memory ops */
1562         walk_memory_irg(irg, collect_memops, NULL, NULL);
1563
1564         if (env.n_mem_ops == 0) {
1565                 /* no memory ops */
1566                 goto end;
1567         }
1568
1569         /* create the backward links */
1570         env.backward = NULL;
1571         irg_block_walk_graph(irg, NULL, collect_backward, NULL);
1572
1573         /* check that we really start with the start / end block */
1574         assert(env.forward->block  == env.start_bl);
1575         assert(env.backward->block == env.end_bl);
1576
1577         /* create address sets: we know that 2 * n_mem_ops - 1 is an upper bound for all possible addresses */
1578         env.rbs_size = 2 * env.n_mem_ops;
1579
1580         /* create the current set */
1581         env.curr_set = rbitset_obstack_alloc(&env.obst, env.rbs_size);
1582         rbitset_set(env.curr_set, env.rbs_size - 1);
1583
1584         for (bl = env.forward; bl != NULL; bl = bl->forward_next) {
1585                 /* set sentinel bits */
1586                 bl->avail_out  = rbitset_obstack_alloc(&env.obst, env.rbs_size);
1587                 rbitset_set(bl->avail_out, env.rbs_size - 1);
1588
1589                 bl->id_2_memop_avail = NEW_ARR_D(memop_t *, &env.obst, env.rbs_size);
1590                 memset(bl->id_2_memop_avail, 0, env.rbs_size * sizeof(bl->id_2_memop[0]));
1591
1592                 bl->anticL_in  = rbitset_obstack_alloc(&env.obst, env.rbs_size);
1593                 rbitset_set(bl->anticL_in, env.rbs_size - 1);
1594
1595                 bl->id_2_memop = NEW_ARR_D(memop_t *, &env.obst, env.rbs_size);
1596                 memset(bl->id_2_memop, 0, env.rbs_size * sizeof(bl->id_2_memop[0]));
1597         }
1598
1599 //      dump_block_list(&env);
1600
1601         calcAvail();
1602         calcAntic();
1603
1604         insert_Loads_upwards();
1605
1606         if (env.changed) {
1607                 /* over all blocks in reverse post order */
1608                 for (bl = env.forward; bl != NULL; bl = bl->forward_next) {
1609                         do_replacements(bl);
1610                 }
1611
1612                 /* not only invalidate but free them. We might allocate new out arrays
1613                    on our obstack which will be deleted yet. */
1614                 free_irg_outs(irg);
1615                 set_irg_entity_usage_state(irg, ir_entity_usage_not_computed);
1616         }
1617 end:
1618
1619         ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
1620         ir_nodemap_destroy(&env.adr_map);
1621         obstack_free(&env.obst, NULL);
1622
1623         current_ir_graph = rem;
1624
1625         return env.changed != 0;
1626 }