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