Remove the obsolete .cvsignore files.
[libfirm] / ir / opt / opt_osr.c
1 /**
2  * Project:     libFIRM
3  * File name:   ir/opt/opt_osr.c
4  * Purpose:     Operator Strength Reduction, based on
5  *              Keith D. Cooper, L. Taylor Simpson, Christopher A. Vick
6  * Author:      Michael Beck
7  * Modified by:
8  * Created:     12.5.2006
9  * CVS-ID:      $Id$
10  * Copyright:   (c) 2006 Universität Karlsruhe
11  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
12  */
13 #ifdef HAVE_CONFIG_H
14 #include "config.h"
15 #endif
16
17 #include "opt_osr.h"
18 #include "irgraph.h"
19 #include "ircons.h"
20 #include "irop_t.h"
21 #include "irloop.h"
22 #include "irdom.h"
23 #include "irgmod.h"
24 #include "irflag_t.h"
25 #include "irgwalk.h"
26 #include "irouts.h"
27 #include "debug.h"
28 #include "obst.h"
29 #include "set.h"
30 #include "tv.h"
31 #include "hashptr.h"
32 #include "irtools.h"
33 #include "irloop_t.h"
34 #include "array.h"
35 #include "firmstat.h"
36 #include "xmalloc.h"
37
38 /** The debug handle. */
39 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
40
41 /** A scc. */
42 typedef struct scc {
43         ir_node *head;          /**< the head of the list */
44 } scc;
45
46 /** A node entry */
47 typedef struct node_entry {
48         unsigned DFSnum;    /**< the DFS number of this node */
49         unsigned low;       /**< the low number of this node */
50         ir_node  *header;   /**< the header of this node */
51         int      in_stack;  /**< flag, set if the node is on the stack */
52         ir_node  *next;     /**< link to the next node the the same scc */
53         scc      *pscc;     /**< the scc of this node */
54         unsigned POnum;     /**< the post order number for blocks */
55 } node_entry;
56
57 /** The environment. */
58 typedef struct iv_env {
59         struct obstack obst;    /**< an obstack for allocations */
60         ir_node  **stack;       /**< the node stack */
61         int      tos;           /**< tos index */
62         unsigned nextDFSnum;    /**< the current DFS number */
63         unsigned POnum;         /**< current post order number */
64         set      *quad_map;     /**< a map from (op, iv, rc) to node */
65         set      *lftr_edges;   /**< the set of lftr edges */
66         unsigned replaced;      /**< number of replaced ops */
67         unsigned lftr_replaced; /**< number of applied linear function test replacements */
68         unsigned flags;         /**< additional flags */
69         /** Function called to process a SCC. */
70         void (*process_scc)(scc *pscc, struct iv_env *env);
71 } iv_env;
72
73 /**
74  * An entry in the (op, node, node) -> node map.
75  */
76 typedef struct quadruple_t {
77         ir_opcode code;  /**< the opcode of the reduced operation */
78         ir_node   *op1;  /**< the first operand the reduced operation */
79         ir_node   *op2;  /**< the second operand of the reduced operation */
80
81         ir_node   *res; /**< the reduced operation */
82 } quadruple_t;
83
84 /**
85  * A LFTR edge.
86  */
87 typedef struct LFTR_edge {
88         ir_node   *src;   /**< the source node */
89         ir_node   *dst;   /**< the destination node */
90         ir_opcode code;   /**< the opcode that must be applied */
91         ir_node   *rc;    /**< the region const that must be applied */
92 } LFTR_edge;
93
94 /* forward */
95 static ir_node *reduce(ir_node *orig, ir_node *iv, ir_node *rc, iv_env *env);
96
97 /**
98  * Compare two LFTR edges.
99  */
100 static int LFTR_cmp(const void *e1, const void *e2, size_t size) {
101         const LFTR_edge *l1 = e1;
102         const LFTR_edge *l2 = e2;
103
104         return l1->src != l2->src;
105 }
106
107 #if 0
108 /**
109  * Find a LFTR edge.
110  */
111 static LFTR_edge *LFTR_find(ir_node *src, iv_env *env) {
112         LFTR_edge key;
113
114         key.src  = src;
115
116         return set_find(env->lftr_edges, &key, sizeof(key), HASH_PTR(src));
117 }
118 #endif
119
120 /**
121  * Add a LFTR edge.
122  */
123 static void LFTR_add(ir_node *src, ir_node *dst, ir_opcode code, ir_node *rc, iv_env *env) {
124         LFTR_edge key;
125
126         key.src  = src;
127         key.dst  = dst;
128         key.code = code;
129         key.rc   = rc;
130
131         /*
132          * There might be more than one edge here. This is rather bad
133          * because we currently store only one.
134          */
135 //      assert(LFTR_find(src, env) == NULL);
136         set_insert(env->lftr_edges, &key, sizeof(key), HASH_PTR(src));
137 }
138
139 /**
140  * Gets the node_entry of a node
141  */
142 static node_entry *get_irn_ne(ir_node *irn, iv_env *env) {
143         node_entry *e = get_irn_link(irn);
144
145         if (! e) {
146                 e = obstack_alloc(&env->obst, sizeof(*e));
147                 memset(e, 0, sizeof(*e));
148                 set_irn_link(irn, e);
149         }
150         return e;
151 }
152
153 /**
154  * Check if irn is an IV.
155  *
156  * @param irn  the node to check
157  * @param env  the environment
158  *
159  * @returns the header if it is one, NULL else
160  */
161 static ir_node *is_iv(ir_node *irn, iv_env *env) {
162         return get_irn_ne(irn, env)->header;
163 }
164
165 /**
166  * Check if irn is a region constant.
167  * The block or irn must strictly dominate the header block.
168  *
169  * @param irn           the node to check
170  * @param header_block  the header block of the induction variable
171  */
172 static int is_rc(ir_node *irn, ir_node *header_block) {
173         ir_node *block = get_nodes_block(irn);
174
175         return (block != header_block) && block_dominates(block, header_block);
176 }
177
178 /**
179  * Set compare function for the quad set.
180  */
181 static int quad_cmp(const void *e1, const void *e2, size_t size) {
182         const quadruple_t *c1 = e1;
183         const quadruple_t *c2 = e2;
184
185         return c1->code != c2->code || c1->op1 != c2->op1 || c1->op2 != c2->op2;
186 }
187
188 /**
189  * Check if an reduced operation was already calculated.
190  *
191  * @param code  the opcode of the operation
192  * @param op1   the first operand of the operation
193  * @param op2   the second operand of the operation
194  * @param env   the environment
195  *
196  * @return the already reduced node or NULL if this operation is not yet reduced
197  */
198 static ir_node *search(ir_opcode code, ir_node *op1, ir_node *op2, iv_env *env) {
199         quadruple_t key, *entry;
200
201         key.code = code;
202         key.op1 = op1;
203         key.op2 = op2;
204
205         entry = set_find(env->quad_map, &key, sizeof(key),
206                          (code * 9) ^ HASH_PTR(op1) ^HASH_PTR(op2));
207         if (entry)
208                 return entry->res;
209         return NULL;
210 }
211
212 /**
213  * Add an reduced operation.
214  *
215  * @param code    the opcode of the operation
216  * @param op1     the first operand of the operation
217  * @param op2     the second operand of the operation
218  * @param result  the result of the reduced operation
219  * @param env     the environment
220  */
221 static void add(ir_opcode code, ir_node *op1, ir_node *op2, ir_node *result, iv_env *env) {
222         quadruple_t key;
223
224         key.code = code;
225         key.op1  = op1;
226         key.op2  = op2;
227         key.res  = result;
228
229         set_insert(env->quad_map, &key, sizeof(key),
230                    (code * 9) ^ HASH_PTR(op1) ^HASH_PTR(op2));
231 }
232
233 /**
234  * Find a location where to place a bin-op whose operands are in
235  * block1 and block2.
236  *
237  * @param block1  the block of the first operand
238  * @param block2  the block of the second operand
239  *
240  * Note that we know here that such a place must exists. Moreover, this means
241  * that either block1 dominates block2 or vice versa. So, just return
242  * the "smaller" one.
243  */
244 static ir_node *find_location(ir_node *block1, ir_node *block2) {
245         if (block_dominates(block1, block2))
246                 return block2;
247         assert(block_dominates(block2, block1));
248         return block1;
249 }
250
251 /**
252  * Create a node that executes an op1 code op1 operation.
253  *
254  * @param code   the opcode to execute
255  * @param db     debug info to add to the new node
256  * @param op1    the first operand
257  * @param op2    the second operand
258  * @param mode   the mode of the new operation
259  *
260  * @return the newly created node
261  */
262 static ir_node *do_apply(ir_opcode code, dbg_info *db, ir_node *op1, ir_node *op2, ir_mode *mode) {
263         ir_graph *irg = current_ir_graph;
264         ir_node *result;
265         ir_node *block = find_location(get_nodes_block(op1), get_nodes_block(op2));
266
267         switch (code) {
268         case iro_Mul:
269                 result = new_rd_Mul(db, irg, block, op1, op2, mode);
270                 break;
271         case iro_Add:
272                 result = new_rd_Add(db, irg, block, op1, op2, mode);
273                 break;
274         case iro_Sub:
275                 result = new_rd_Sub(db, irg, block, op1, op2, mode);
276                 break;
277         default:
278                 assert(0);
279                 result = NULL;
280         }
281         return result;
282 }
283
284 /**
285  * The Apply operation.
286  *
287  * @param orig   the node that represent the original operation and determines
288  *               the opcode, debug-info and mode of a newly created one
289  * @param op1    the first operand
290  * @param op2    the second operand
291  * @param env    the environment
292  *
293  * @return the newly created node
294  */
295 static ir_node *apply(ir_node *orig, ir_node *op1, ir_node *op2, iv_env *env) {
296         ir_opcode code = get_irn_opcode(orig);
297         ir_node *result = search(code, op1, op2, env);
298
299         if (! result) {
300                 dbg_info *db = get_irn_dbg_info(orig);
301                 ir_node *op1_header = get_irn_ne(op1, env)->header;
302                 ir_node *op2_header = get_irn_ne(op2, env)->header;
303
304                 if (op1_header != NULL && is_rc(op2, op1_header)) {
305                         result = reduce(orig, op1, op2, env);
306                 }
307                 else if (op2_header != NULL && is_rc(op1, op2_header)) {
308                         result = reduce(orig, op2, op1, env);
309                 }
310                 else {
311                         result = do_apply(code, db, op1, op2, get_irn_mode(orig));
312                         get_irn_ne(result, env)->header = NULL;         }
313         }
314         return result;
315 }
316
317 /**
318  * The Reduce operation.
319  *
320  * @param orig   the node that represent the original operation and determines
321  *               the opcode, debug-info and mode of a newly created one
322  * @param iv     the induction variable
323  * @param rc     the region constant
324  * @param env    the environment
325  *
326  * @return the reduced node
327  */
328 static ir_node *reduce(ir_node *orig, ir_node *iv, ir_node *rc, iv_env *env) {
329         ir_opcode code = get_irn_opcode(orig);
330         ir_node *result = search(code, iv, rc, env);
331
332         if (! result) {
333                 node_entry *e, *iv_e;
334                 int i, n;
335                 ir_mode *mode = get_irn_mode(orig);
336
337                 result = exact_copy(iv);
338
339                 /* Beware: we must always create a new nduction variable with the same mode
340                    as the node we are replacing. Espicially this means the mode might be changed
341                    from P to I and back. This is always possible, because we have only Phi, Add
342                    and Sub nodes. */
343                 set_irn_mode(result, mode);
344                 add(code, iv, rc, result, env);
345                 DB((dbg, LEVEL_3, "   Created new %+F for %+F (%s %+F)\n", result, iv,
346                         get_irn_opname(orig), rc));
347
348                 iv_e = get_irn_ne(iv, env);
349                 e    = get_irn_ne(result, env);
350                 e->header = iv_e->header;
351
352                 /* create the LFTR edge */
353                 LFTR_add(iv, result, code, rc, env);
354
355                 n = get_irn_arity(result);
356                 for (i = 0; i < n; ++i) {
357                         ir_node *o = get_irn_n(result, i);
358
359                         e = get_irn_ne(o, env);
360                         if (e->header == iv_e->header)
361                                 o = reduce(orig, o, rc, env);
362                         else if (is_Phi(result))
363                                 o = apply(orig, o, rc, env);
364                         else {
365                                 if (code == iro_Mul)
366                                         o = apply(orig, o, rc, env);
367                         }
368                         set_irn_n(result, i, o);
369                 }
370         }
371         else {
372                 DB((dbg, LEVEL_3, "   Already Created %+F for %+F (%s %+F)\n", result, iv,
373                         get_irn_opname(orig), rc));
374         }
375         return result;
376 }
377
378 /**
379  * The Replace operation.
380  *
381  * @param irn   the node that will be replaced
382  * @param iv    the induction variable
383  * @param rc    the region constant
384  * @param env   the environment
385  */
386 static int replace(ir_node *irn, ir_node *iv, ir_node *rc, iv_env *env) {
387         ir_node *result;
388         ir_loop *iv_loop  = get_irn_loop(get_nodes_block(iv));
389         ir_loop *irn_loop = get_irn_loop(get_nodes_block(irn));
390
391         /* only replace nodes that are in the same (or deeper loops) */
392         if (get_loop_depth(irn_loop) >= get_loop_depth(iv_loop)) {
393                 DB((dbg, LEVEL_2, "  Replacing %+F\n", irn));
394
395                 result = reduce(irn, iv, rc, env);
396                 if (result != irn) {
397                         node_entry *e, *iv_e;
398
399                         hook_strength_red(current_ir_graph, irn);
400                         exchange(irn, result);
401                         e = get_irn_ne(result, env);
402                         iv_e = get_irn_ne(iv, env);
403                         e->header = iv_e->header;
404                 }
405                 return 1;
406         }
407         return 0;
408 }
409
410 /**
411  * Check if a node can be replaced (+, -, *).
412  *
413  * @param irn   the node to check
414  * @param env   the environment
415  *
416  * @return non-zero if irn should be Replace'd
417  */
418 static int check_replace(ir_node *irn, iv_env *env) {
419         ir_node   *left, *right, *iv, *rc;
420         ir_op     *op  = get_irn_op(irn);
421         ir_opcode code = get_op_code(op);
422         ir_node   *liv, *riv;
423
424         switch (code) {
425         case iro_Mul:
426         case iro_Add:
427         case iro_Sub:
428                 iv = rc = NULL;
429
430                 left  = get_binop_left(irn);
431                 right = get_binop_right(irn);
432
433                 liv = is_iv(left, env);
434                 riv = is_iv(right, env);
435                 if (liv && is_rc(right, liv)) {
436                         iv = left; rc = right;
437                 }
438                 else if (riv && is_op_commutative(op) &&
439                                     is_rc(left, riv)) {
440                         iv = right; rc = left;
441                 }
442
443                 if (iv) {
444                         if (code == iro_Mul && env->flags & osr_flag_ignore_x86_shift) {
445                                 if (is_Const(rc)) {
446                                         tarval *tv = get_Const_tarval(rc);
447
448                                         if (tarval_is_long(tv)) {
449                                                 long value = get_tarval_long(tv);
450
451                                                 if (value == 2 || value == 4 || value == 8) {
452                                                         /* do not reduce multiplications by 2, 4, 8 */
453                                                         break;
454                                                 }
455                                         }
456                                 }
457                         }
458
459                         return replace(irn, iv, rc, env);
460                 }
461                 break;
462         default:
463                 break;
464         }
465         return 0;
466 }
467
468 /**
469  * Check which SCC's are induction variables.
470  *
471  * @param pscc  a SCC
472  * @param env   the environment
473  */
474 static void classify_iv(scc *pscc, iv_env *env) {
475         ir_node *irn, *next, *header = NULL;
476         node_entry *b, *h = NULL;
477         int j, only_phi, num_outside;
478         ir_node *out_rc;
479
480         /* find the header block for this scc */
481         for (irn = pscc->head; irn; irn = next) {
482                 node_entry *e = get_irn_link(irn);
483                 ir_node *block = get_nodes_block(irn);
484
485                 next = e->next;
486                 b = get_irn_ne(block, env);
487
488                 if (header) {
489                         if (h->POnum < b->POnum) {
490                                 header = block;
491                                 h      = b;
492                         }
493                 }
494                 else {
495                         header = block;
496                         h      = b;
497                 }
498         }
499
500         /* check if this scc contains only Phi, Add or Sub nodes */
501         only_phi    = 1;
502         num_outside = 0;
503         out_rc      = NULL;
504         for (irn = pscc->head; irn; irn = next) {
505                 node_entry *e = get_irn_ne(irn, env);
506
507                 next = e->next;
508                 switch (get_irn_opcode(irn)) {
509                 case iro_Add:
510                 case iro_Sub:
511                         only_phi = 0;
512                         /* fall through */
513                 case iro_Phi:
514                         for (j = get_irn_arity(irn) - 1; j >= 0; --j) {
515                                 ir_node *pred  = get_irn_n(irn, j);
516                                 node_entry *pe = get_irn_ne(pred, env);
517
518                                 if (pe->pscc != e->pscc) {
519                                         /* not in the same SCC, must be a region const */
520                                         if (! is_rc(pred, header)) {
521                                                 /* not an induction variable */
522                                                 goto fail;
523                                         }
524                                         if (! out_rc) {
525                                                 out_rc = pred;
526                                                 ++num_outside;
527                                         } else if (out_rc != pred) {
528                                                 ++num_outside;
529                                         }
530                                 }
531                         }
532                         break;
533                 default:
534                         /* not an induction variable */
535                         goto fail;
536                 }
537         }
538         /* found an induction variable */
539         DB((dbg, LEVEL_2, "  Found an induction variable:\n  "));
540         if (only_phi && num_outside == 1) {
541                 /* a phi cycle with only one real predecessor can be collapsed */
542                 DB((dbg, LEVEL_2, "  Found an USELESS Phi cycle:\n  "));
543
544                 for (irn = pscc->head; irn; irn = next) {
545                         node_entry *e = get_irn_ne(irn, env);
546                         next = e->next;
547                         e->header = NULL;
548                         exchange(irn, out_rc);
549                 }
550                 ++env->replaced;
551                 return;
552         }
553
554         /* set the header for every node in this scc */
555         for (irn = pscc->head; irn; irn = next) {
556                 node_entry *e = get_irn_ne(irn, env);
557                 e->header = header;
558                 next = e->next;
559                 DB((dbg, LEVEL_2, " %+F,", irn));
560         }
561         DB((dbg, LEVEL_2, "\n"));
562         return;
563
564 fail:
565         for (irn = pscc->head; irn; irn = next) {
566                 node_entry *e = get_irn_ne(irn, env);
567
568                 next = e->next;
569                 if (! check_replace(irn, env))
570                         e->header = NULL;
571         }
572 }
573
574 /**
575  * Process a SCC for the operator strength reduction.
576  *
577  * @param pscc  the SCC
578  * @param env   the environment
579  */
580 static void process_scc(scc *pscc, iv_env *env) {
581         ir_node *head = pscc->head;
582         node_entry *e = get_irn_link(head);
583
584 #ifdef DEBUG_libfirm
585         {
586                 ir_node *irn, *next;
587
588                 DB((dbg, LEVEL_4, " SCC at %p:\n ", pscc));
589                 for (irn = pscc->head; irn; irn = next) {
590                         node_entry *e = get_irn_link(irn);
591
592                         next = e->next;
593
594                         DB((dbg, LEVEL_4, " %+F,", irn));
595                 }
596                 DB((dbg, LEVEL_4, "\n"));
597         }
598 #endif
599
600         if (e->next == NULL) {
601                 /* this SCC has only a single member */
602                 check_replace(head, env);
603         } else {
604                 classify_iv(pscc, env);
605         }
606 }
607
608 /**
609  * If an SCC is a Phi only cycle, remove it.
610  */
611 static void remove_phi_cycle(scc *pscc, iv_env *env) {
612         ir_node *irn, *next;
613         int j;
614         ir_node *out_rc;
615
616         /* check if this scc contains only Phi, Add or Sub nodes */
617         out_rc      = NULL;
618         for (irn = pscc->head; irn; irn = next) {
619                 node_entry *e = get_irn_ne(irn, env);
620
621                 next = e->next;
622                 if (! is_Phi(irn))
623                         return;
624
625                 for (j = get_irn_arity(irn) - 1; j >= 0; --j) {
626                         ir_node *pred  = get_irn_n(irn, j);
627                         node_entry *pe = get_irn_ne(pred, env);
628
629                         if (pe->pscc != e->pscc) {
630                                 /* not in the same SCC, must be the only input */
631                                 if (! out_rc) {
632                                         out_rc = pred;
633                                 } else if (out_rc != pred) {
634                                         return;
635                                 }
636                         }
637                 }
638         }
639         /* found a Phi cycle */
640         DB((dbg, LEVEL_2, "  Found an USELESS Phi cycle:\n  "));
641
642         for (irn = pscc->head; irn; irn = next) {
643                 node_entry *e = get_irn_ne(irn, env);
644                 next = e->next;
645                 e->header = NULL;
646                 exchange(irn, out_rc);
647         }
648         ++env->replaced;
649 }
650
651 /**
652  * Process a SCC for the Phi cycle removement.
653  *
654  * @param pscc  the SCC
655  * @param env   the environment
656  */
657 static void process_phi_only_scc(scc *pscc, iv_env *env) {
658         ir_node *head = pscc->head;
659         node_entry *e = get_irn_link(head);
660
661 #ifdef DEBUG_libfirm
662         {
663                 ir_node *irn, *next;
664
665                 DB((dbg, LEVEL_4, " SCC at %p:\n ", pscc));
666                 for (irn = pscc->head; irn; irn = next) {
667                         node_entry *e = get_irn_link(irn);
668
669                         next = e->next;
670
671                         DB((dbg, LEVEL_4, " %+F,", irn));
672                 }
673                 DB((dbg, LEVEL_4, "\n"));
674         }
675 #endif
676
677         if (e->next != NULL)
678                 remove_phi_cycle(pscc, env);
679 }
680
681
682 /**
683  * Push a node onto the stack.
684  *
685  * @param env   the environment
686  * @param n     the node to push
687  */
688 static void push(iv_env *env, ir_node *n) {
689         node_entry *e;
690
691         if (env->tos == ARR_LEN(env->stack)) {
692                 int nlen = ARR_LEN(env->stack) * 2;
693                 ARR_RESIZE(ir_node *, env->stack, nlen);
694         }
695         env->stack[env->tos++] = n;
696         e = get_irn_ne(n, env);
697         e->in_stack = 1;
698 }
699
700 /**
701  * pop a node from the stack
702  *
703  * @param env   the environment
704  *
705  * @return  The topmost node
706  */
707 static ir_node *pop(iv_env *env)
708 {
709         ir_node *n = env->stack[--env->tos];
710         node_entry *e = get_irn_ne(n, env);
711
712         e->in_stack = 0;
713         return n;
714 }
715
716 /**
717  * Do Tarjan's SCC algorithm and drive OSR.
718  *
719  * @param irn  start at this node
720  * @param env  the environment
721  */
722 static void dfs(ir_node *irn, iv_env *env)
723 {
724         int i, n;
725         node_entry *node = get_irn_ne(irn, env);
726
727         mark_irn_visited(irn);
728
729         /* do not put blocks into the scc */
730         if (is_Block(irn)) {
731                 n = get_irn_arity(irn);
732                 for (i = 0; i < n; ++i) {
733                         ir_node *pred = get_irn_n(irn, i);
734
735                         if (irn_not_visited(pred))
736                                 dfs(pred, env);
737                 }
738         }
739         else {
740                 ir_node *block = get_nodes_block(irn);
741
742                 node->DFSnum = env->nextDFSnum++;
743                 node->low    = node->DFSnum;
744                 push(env, irn);
745
746                 /* handle the block */
747                 if (irn_not_visited(block))
748                         dfs(block, env);
749
750                 n = get_irn_arity(irn);
751                 for (i = 0; i < n; ++i) {
752                         ir_node *pred = get_irn_n(irn, i);
753                         node_entry *o = get_irn_ne(pred, env);
754
755                         if (irn_not_visited(pred)) {
756                                 dfs(pred, env);
757                                 node->low = MIN(node->low, o->low);
758                         }
759                         if (o->DFSnum < node->DFSnum && o->in_stack)
760                                 node->low = MIN(o->DFSnum, node->low);
761                 }
762                 if (node->low == node->DFSnum) {
763                         scc *pscc = obstack_alloc(&env->obst, sizeof(*pscc));
764                         ir_node *x;
765
766                         pscc->head = NULL;
767                         do {
768                                 node_entry *e;
769
770                                 x = pop(env);
771                                 e = get_irn_ne(x, env);
772                                 e->pscc    = pscc;
773                                 e->next    = pscc->head;
774                                 pscc->head = x;
775                         } while (x != irn);
776
777                         env->process_scc(pscc, env);
778                 }
779         }
780 }
781
782 /**
783  * Do the DFS by starting at the End node of a graph.
784  *
785  * @param irg  the graph to process
786  * @param env  the environment
787  */
788 static void do_dfs(ir_graph *irg, iv_env *env) {
789         ir_graph *rem = current_ir_graph;
790         ir_node *end = get_irg_end(irg);
791         int i, n;
792
793         current_ir_graph = irg;
794         inc_irg_visited(irg);
795
796         /* visit all visible nodes */
797         dfs(end, env);
798
799         /* visit the keep-alives */
800         n = get_End_n_keepalives(end);
801         for (i = 0; i < n; ++i) {
802                 ir_node *ka = get_End_keepalive(end, i);
803
804                 if (irn_not_visited(ka))
805                         dfs(ka, env);
806         }
807
808         current_ir_graph = rem;
809 }
810
811 /**
812  * Post-block-walker: assign the post-order number.
813  */
814 static void assign_po(ir_node *block, void *ctx) {
815         iv_env *env = ctx;
816         node_entry *e = get_irn_ne(block, env);
817
818         e->POnum = env->POnum++;
819 }
820
821 #if 0
822 /**
823  * Follows the LFTR edges and return the last node in the chain.
824  *
825  * @param irn  the node that should be followed
826  * @param env  the IV environment
827  *
828  * @note
829  * In the current implementation only the last edge is stored, so
830  * only one chain exists. That's why we might miss some opportunities.
831  */
832 static ir_node *followEdges(ir_node *irn, iv_env *env) {
833         for (;;) {
834                 LFTR_edge *e = LFTR_find(irn, env);
835                 if (e)
836                         irn = e->dst;
837                 else
838                         return irn;
839         }
840 }
841
842 /**
843  * Apply one LFTR edge operation.
844  * Return NULL if the transformation cannot be done safely without
845  * an Overflow.
846  *
847  * @param rc   the IV node that should be translated
848  * @param e    the LFTR edge
849  * @param env  the IV environment
850  *
851  * @return the translated region constant or NULL
852  *         if the translation was not possible
853  *
854  * @note
855  * In the current implementation only the last edge is stored, so
856  * only one chain exists. That's why we might miss some opportunities.
857  */
858 static ir_node *applyOneEdge(ir_node *rc, LFTR_edge *e, iv_env *env) {
859         if (env->flags & osr_flag_lftr_with_ov_check) {
860                 tarval *tv_l, *tv_r, *tv;
861                 tarval_int_overflow_mode_t ovmode;
862
863                 /* overflow can only be decided for Consts */
864                 if (! is_Const(e->rc)) {
865                         DB((dbg, LEVEL_4, " = UNKNOWN (%+F)", e->rc));
866                         return NULL;
867                 }
868
869                 tv_l = get_Const_tarval(rc);
870                 tv_r = get_Const_tarval(e->rc);
871
872                 ovmode = tarval_get_integer_overflow_mode();
873                 tarval_set_integer_overflow_mode(TV_OVERFLOW_BAD);
874
875                 switch (e->code) {
876                 case iro_Mul:
877                         tv = tarval_mul(tv_l, tv_r);
878                         DB((dbg, LEVEL_4, " * %+F", tv_r));
879                         break;
880                 case iro_Add:
881                         tv = tarval_add(tv_l, tv_r);
882                         DB((dbg, LEVEL_4, " + %+F", tv_r));
883                         break;
884                 case iro_Sub:
885                         tv = tarval_sub(tv_l, tv_r);
886                         DB((dbg, LEVEL_4, " - %+F", tv_r));
887                         break;
888                 default:
889                         assert(0);
890                         tv = tarval_bad;
891                 }
892                 tarval_set_integer_overflow_mode(ovmode);
893
894                 if (tv == tarval_bad) {
895                         DB((dbg, LEVEL_4, " = OVERFLOW"));
896                         return NULL;
897                 }
898                 return new_r_Const(current_ir_graph, get_irn_n(rc, -1), get_tarval_mode(tv), tv);
899         }
900         return do_apply(e->code, NULL, rc, e->rc, get_irn_mode(rc));
901 }
902
903 /**
904  * Applies the operations represented by the LFTR edges to a
905  * region constant and returns the value.
906  * Return NULL if the transformation cannot be done safely without
907  * an Overflow.
908  *
909  * @param iv   the IV node that starts the LFTR edge chain
910  * @param rc   the region constant that should be translated
911  * @param env  the IV environment
912  *
913  * @return the translated region constant or NULL
914  *         if the translation was not possible
915  */
916 static ir_node *applyEdges(ir_node *iv, ir_node *rc, iv_env *env) {
917         ir_node *irn = iv;
918
919         if (env->flags & osr_flag_lftr_with_ov_check) {
920                 /* overflow can only be decided for Consts */
921                 if (! is_Const(rc)) {
922                         DB((dbg, LEVEL_4, " = UNKNOWN (%+F)\n", rc));
923                         return NULL;
924                 }
925                 DB((dbg, LEVEL_4, "%+F", get_Const_tarval(rc)));
926         }
927
928         for (irn = iv; rc;) {
929                 LFTR_edge *e = LFTR_find(irn, env);
930                 if (e) {
931                         rc = applyOneEdge(rc, e, env);
932                         irn = e->dst;
933                 }
934                 else
935                         break;
936         }
937         DB((dbg, LEVEL_3, "\n"));
938         return rc;
939 }
940
941 /**
942  * Walker, finds Cmp(iv, rc) or Cmp(rc, iv)
943  * and tries to optimize them.
944  */
945 static void do_lftr(ir_node *cmp, void *ctx) {
946         iv_env *env = ctx;
947         ir_node *left, *right, *liv, *riv;
948         ir_node *iv, *rc;
949         ir_node *nleft = NULL, *nright = NULL;
950
951         if (get_irn_op(cmp) != op_Cmp)
952                 return;
953
954         left  = get_Cmp_left(cmp);
955         right = get_Cmp_right(cmp);
956
957         liv = is_iv(left, env);
958         riv = is_iv(right, env);
959         if (liv && is_rc(right, liv)) {
960                 iv = left; rc = right;
961
962                 nright = applyEdges(iv, rc, env);
963                 if (nright && nright != rc) {
964                         nleft = followEdges(iv, env);
965                 }
966         }
967         else if (riv && is_rc(left, riv)) {
968                 iv = right; rc = left;
969
970                 nleft = applyEdges(iv, rc, env);
971                 if (nleft && nleft != rc) {
972                         nright = followEdges(iv, env);
973                 }
974         }
975
976         if (nleft && nright) {
977                 DB((dbg, LEVEL_2, "  LFTR for %+F\n", cmp));
978                 set_Cmp_left(cmp, nleft);
979                 set_Cmp_right(cmp, nright);
980                 ++env->lftr_replaced;
981         }
982 }
983
984 /**
985  * do linear function test replacement.
986  *
987  * @param irg   the graph that should be optimized
988  * @param env   the IV environment
989  */
990 static void lftr(ir_graph *irg, iv_env *env) {
991         irg_walk_graph(irg, NULL, do_lftr, env);
992 }
993 #endif
994
995 /**
996  * Pre-walker: set all node links to NULL and fix the
997  * block of Proj nodes.
998  */
999 static void clear_and_fix(ir_node *irn, void *env)
1000 {
1001         set_irn_link(irn, NULL);
1002
1003         if (is_Proj(irn)) {
1004                 ir_node *pred = get_Proj_pred(irn);
1005                 set_irn_n(irn, -1, get_irn_n(pred, -1));
1006         }
1007 }
1008
1009 /* Performs Operator Strength Reduction for the passed graph. */
1010 void opt_osr(ir_graph *irg, unsigned flags) {
1011         iv_env   env;
1012         ir_graph *rem;
1013
1014         if (! get_opt_strength_red()) {
1015                 /* only kill Phi cycles  */
1016                 remove_phi_cycles(irg);
1017                 return;
1018         }
1019
1020         rem = current_ir_graph;
1021         current_ir_graph = irg;
1022
1023         FIRM_DBG_REGISTER(dbg, "firm.opt.osr");
1024
1025         DB((dbg, LEVEL_1, "Doing Operator Strength Reduction for %+F\n", irg));
1026
1027         obstack_init(&env.obst);
1028         env.stack         = NEW_ARR_F(ir_node *, 128);
1029         env.tos           = 0;
1030         env.nextDFSnum    = 0;
1031         env.POnum         = 0;
1032         env.quad_map      = new_set(quad_cmp, 64);
1033         env.lftr_edges    = new_set(LFTR_cmp, 64);
1034         env.replaced      = 0;
1035         env.lftr_replaced = 0;
1036         env.flags         = flags;
1037         env.process_scc   = process_scc;
1038
1039         /* Clear all links and move Proj nodes into the
1040            the same block as it's predecessors.
1041            This can improve the placement of new nodes.
1042          */
1043         irg_walk_graph(irg, NULL, clear_and_fix, NULL);
1044
1045         /* we need dominance */
1046         assure_doms(irg);
1047         assure_irg_outs(irg);
1048
1049         /* calculate the post order number for blocks. */
1050         irg_out_block_walk(get_irg_start_block(irg), NULL, assign_po, &env);
1051
1052         /* calculate the SCC's and drive OSR. */
1053         do_dfs(irg, &env);
1054
1055         if (env.replaced) {
1056                 /* try linear function test replacements */
1057                 //lftr(irg, &env);
1058
1059                 set_irg_outs_inconsistent(irg);
1060                 DB((dbg, LEVEL_1, "Replacements: %u + %u (lftr)\n\n", env.replaced, env.lftr_replaced));
1061         }
1062
1063         del_set(env.lftr_edges);
1064         del_set(env.quad_map);
1065         DEL_ARR_F(env.stack);
1066         obstack_free(&env.obst, NULL);
1067
1068         current_ir_graph = rem;
1069 }
1070
1071 /* Remove any Phi cycles with only one real input. */
1072 void remove_phi_cycles(ir_graph *irg) {
1073         iv_env   env;
1074         ir_graph *rem;
1075
1076         rem = current_ir_graph;
1077         current_ir_graph = irg;
1078
1079         FIRM_DBG_REGISTER(dbg, "firm.opt.remove_phi");
1080
1081         DB((dbg, LEVEL_1, "Doing Phi cycle removement for %+F\n", irg));
1082
1083         obstack_init(&env.obst);
1084         env.stack         = NEW_ARR_F(ir_node *, 128);
1085         env.tos           = 0;
1086         env.nextDFSnum    = 0;
1087         env.POnum         = 0;
1088         env.quad_map      = NULL;
1089         env.lftr_edges    = NULL;
1090         env.replaced      = 0;
1091         env.lftr_replaced = 0;
1092         env.flags         = 0;
1093         env.process_scc   = process_phi_only_scc;
1094
1095         /* Clear all links and move Proj nodes into the
1096            the same block as it's predecessors.
1097            This can improve the placement of new nodes.
1098          */
1099         irg_walk_graph(irg, NULL, clear_and_fix, NULL);
1100
1101         /* we need dominance */
1102         assure_irg_outs(irg);
1103
1104         /* calculate the post order number for blocks. */
1105         irg_out_block_walk(get_irg_start_block(irg), NULL, assign_po, &env);
1106
1107         /* calculate the SCC's and drive OSR. */
1108         do_dfs(irg, &env);
1109
1110         if (env.replaced) {
1111                 set_irg_outs_inconsistent(irg);
1112                 DB((dbg, LEVEL_1, "remove_phi_cycles: %u Cycles removed\n\n", env.replaced));
1113         }
1114
1115         DEL_ARR_F(env.stack);
1116         obstack_free(&env.obst, NULL);
1117
1118         current_ir_graph = rem;
1119 }