7a8e7e1e7fa844530844e292659caa962bb1d804
[libfirm] / ir / opt / scalar_replace.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   Scalar replacement of compounds.
23  * @author  Beyhan Veliev, Michael Beck
24  * @version $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <string.h>
31
32 #include "iroptimize.h"
33 #include "scalar_replace.h"
34 #include "irflag_t.h"
35 #include "irouts.h"
36 #include "set.h"
37 #include "pset.h"
38 #include "array.h"
39 #include "tv.h"
40 #include "ircons_t.h"
41 #include "hashptr.h"
42 #include "irgwalk.h"
43 #include "irgmod.h"
44 #include "irnode_t.h"
45 #include "irtools.h"
46 #include "xmalloc.h"
47
48 #define SET_VNUM(node, vnum) set_irn_link(node, INT_TO_PTR(vnum))
49 #define GET_VNUM(node)       (unsigned)PTR_TO_INT(get_irn_link(node))
50
51 /**
52  * A path element entry: it is either an entity
53  * or a tarval, because we evaluate only constant array
54  * accesses like a.b.c[8].d
55  */
56 typedef union {
57         ir_entity *ent;
58         tarval *tv;
59 } path_elem_t;
60
61 /**
62  * An access path, used to assign value numbers
63  * to variables that will be scalar replaced.
64  */
65 typedef struct _path_t {
66         unsigned    vnum;      /**< The value number. */
67         unsigned    path_len;  /**< The length of the access path. */
68         path_elem_t path[1];   /**< The path. */
69 } path_t;
70
71 /** The size of a path in bytes. */
72 #define PATH_SIZE(p)  (sizeof(*(p)) + sizeof((p)->path[0]) * ((p)->path_len - 1))
73
74 typedef struct _scalars_t {
75         ir_entity *ent;              /**< A entity for scalar replacement. */
76         ir_type *ent_owner;          /**< The owner of this entity. */
77 } scalars_t;
78
79
80 /**
81  * Compare two pathes.
82  *
83  * @return 0 if they are identically
84  */
85 static int path_cmp(const void *elt, const void *key, size_t size) {
86         const path_t *p1 = elt;
87         const path_t *p2 = key;
88         (void) size;
89
90         /* we can use memcmp here, because identical tarvals should have identical addresses */
91         return memcmp(p1->path, p2->path, p1->path_len * sizeof(p1->path[0]));
92 }
93
94 /**
95  * Compare two elements of the scalars_t set.
96  *
97  * @return 0 if they are identically
98  */
99 static int ent_cmp(const void *elt, const void *key, size_t size) {
100         const scalars_t *c1 = elt;
101         const scalars_t *c2 = key;
102         (void) size;
103
104         return c1->ent != c2->ent;
105 }
106
107 /**
108  * Calculate a hash value for a path.
109  */
110 static unsigned path_hash(const path_t *path) {
111         unsigned hash = 0;
112         unsigned i;
113
114         for (i = 0; i < path->path_len; ++i)
115                 hash ^= (unsigned)PTR_TO_INT(path->path[i].ent);
116
117         return hash >> 4;
118 }
119
120 /**
121  * Returns non-zero, if all indeces of a Sel node are constants.
122  *
123  * @param sel  the Sel node that will be checked
124  */
125 static int is_const_sel(ir_node *sel) {
126         int i, n = get_Sel_n_indexs(sel);
127
128         for (i = 0; i < n; ++i) {
129                 ir_node *idx = get_Sel_index(sel, i);
130
131                 if (get_irn_op(idx) != op_Const)
132                         return 0;
133         }
134         return 1;
135 }
136
137 /**
138  * Check the mode of a Load/Store with the mode of the entity
139  * that is accessed.
140  * If the mode of the entity and the Load/Store mode do not match, we
141  * have the bad reinterpret case:
142  *
143  * int i;
144  * char b = *(char *)&i;
145  *
146  * We do NOT count this as one value and return address_taken
147  * in that case.
148  * However, we support an often used case. If the mode is two-complement
149  * we allow casts between signed/unsigned.
150  *
151  * @param mode     the mode of the Load/Store
152  * @param ent_mode the mode of the accessed entity
153  */
154 static int check_load_store_mode(ir_mode *mode, ir_mode *ent_mode) {
155         if (ent_mode != mode) {
156                 if (ent_mode == NULL ||
157                     get_mode_size_bits(ent_mode) != get_mode_size_bits(mode) ||
158                     get_mode_sort(ent_mode) != get_mode_sort(mode) ||
159                     get_mode_arithmetic(ent_mode) != irma_twos_complement ||
160                     get_mode_arithmetic(mode) != irma_twos_complement)
161                         return 0;
162         }
163         return 1;
164 }
165
166 /*
167  * Returns non-zero, if the address of an entity
168  * represented by a Sel node (or it's successor Sels) is taken.
169  */
170 int is_address_taken(ir_node *sel)
171 {
172         int     i;
173         ir_mode *emode, *mode;
174         ir_node *value;
175         ir_entity *ent;
176
177         if (! is_const_sel(sel))
178                 return 1;
179
180         for (i = get_irn_n_outs(sel) - 1; i >= 0; --i) {
181                 ir_node *succ = get_irn_out(sel, i);
182
183                 switch (get_irn_opcode(succ)) {
184                 case iro_Load:
185                         /* check if this load is not a hidden conversion */
186                         mode = get_Load_mode(succ);
187                         ent = get_Sel_entity(sel);
188                         emode = get_type_mode(get_entity_type(ent));
189                         if (! check_load_store_mode(mode, emode))
190                                 return 1;
191                         break;
192
193                 case iro_Store:
194                         /* check that Sel is not the Store's value */
195                         value = get_Store_value(succ);
196                         if (value == sel)
197                                 return 1;
198                         /* check if this Store is not a hidden conversion */
199                         mode = get_irn_mode(value);
200                         ent = get_Sel_entity(sel);
201                         emode = get_type_mode(get_entity_type(ent));
202                         if (! check_load_store_mode(mode, emode))
203                                 return 1;
204                         break;
205
206                 case iro_Sel: {
207                         /* Check the Sel successor of Sel */
208                         int res = is_address_taken(succ);
209
210                         if (res)
211                                 return 1;
212                         break;
213                 }
214
215                 case iro_Call:
216                         /* The address of an entity is given as a parameter.
217                          * As long as we do not have analyses that can tell what
218                          * is done with parameters, think is taken.
219                          * One special case: If the Call type tells that it's a
220                          * value parameter, the address is NOT taken.
221                          */
222                         return 1;
223
224                 default:
225                         /* another op, the address is taken */
226                         return 1;
227                 }
228         }
229         return 0;
230 }
231
232 /**
233  * Link all leave Sels with the entity.
234  *
235  * @param ent  the entity that will be scalar replaced
236  * @param sel  a Sel node that selects some fields of this entity
237  */
238 static void link_all_leave_sels(ir_entity *ent, ir_node *sel) {
239         int i, n, flag = 1;
240
241         n = get_irn_n_outs(sel);
242         for (i = 0; i < n; ++i) {
243                 ir_node *succ = get_irn_out(sel, i);
244
245                 if (is_Sel(succ)) {
246                         link_all_leave_sels(ent, succ);
247                         flag = 0;
248                 }
249         }
250
251         if (flag) {
252                 /* if Sel nodes with memory inputs are used, a entity can be
253                  * visited more than once causing a ring here, so we use the
254                  * node flag to mark linked nodes
255                  */
256                 if (irn_visited(sel))
257                         return;
258
259                 /* we know we are at a leave, because this function is only
260                  * called if the address is NOT taken, so succ must be a Load
261                  * or a Store node
262                  */
263                 set_irn_link(sel, get_entity_link(ent));
264                 set_entity_link(ent, sel);
265
266                 mark_irn_visited(sel);
267         }
268 }
269
270 /* we need a special address that serves as an address taken marker */
271 static char _x;
272 static void *ADDRESS_TAKEN = &_x;
273
274 /**
275  * Find possible scalar replacements.
276  *
277  * @param irg  an IR graph
278  *
279  * This function finds variables on the (members of the) frame type
280  * that can be scalar replaced, because their address is never taken.
281  * If such a variable is found, it's entity link will hold a list of all
282  * Sel nodes, that selects the atomic fields of this entity.
283  * Otherwise, the link will be ADDRESS_TAKEN or NULL.
284  *
285  * @return  non-zero if at least one entity could be replaced
286  *          potentially
287  */
288 static int find_possible_replacements(ir_graph *irg) {
289         ir_node *irg_frame = get_irg_frame(irg);
290         int i, n;
291         int res = 0;
292
293         inc_irg_visited(irg);
294
295         n = get_irn_n_outs(irg_frame);
296
297         /*
298          * First, clear the link field of all interesting entities.
299          * Note that we did not rely on the fact that there is only
300          * one Sel node per entity, so we might access one entity
301          * more than once here.
302          * That's why we have need two loops.
303          */
304         for (i = 0; i < n; ++i) {
305                 ir_node *succ = get_irn_out(irg_frame, i);
306
307                 if (is_Sel(succ)) {
308                         ir_entity *ent = get_Sel_entity(succ);
309                         set_entity_link(ent, NULL);
310                 }
311         }
312
313         /*
314          * Check the ir_graph for Sel nodes. If the entity of Sel
315          * isn't a scalar replacement set the link of this entity
316          * equal ADDRESS_TAKEN.
317          */
318         for (i = 0; i < n; ++i) {
319                 ir_node *succ = get_irn_out(irg_frame, i);
320
321                 if (is_Sel(succ)) {
322                         ir_entity *ent = get_Sel_entity(succ);
323                         ir_type *ent_type;
324
325                         if (get_entity_link(ent) == ADDRESS_TAKEN)
326                                 continue;
327
328                         /*
329                          * Beware: in rare cases even entities on the frame might be
330                          * volatile. This might happen if the entity serves as a store
331                          * to a value that must survive a exception. Do not optimize
332                          * such entities away.
333                          */
334                         if (get_entity_volatility(ent) == volatility_is_volatile) {
335                                 set_entity_link(ent, ADDRESS_TAKEN);
336                                 continue;
337                         }
338
339                         ent_type = get_entity_type(ent);
340
341                         /* we can handle arrays, structs and atomic types yet */
342                         if (is_Array_type(ent_type) || is_Struct_type(ent_type) || is_atomic_type(ent_type)) {
343                                 if (is_address_taken(succ)) {
344                                         if (get_entity_link(ent)) /* killing one */
345                                                 --res;
346                                         set_entity_link(ent, ADDRESS_TAKEN);
347                                 } else {
348                                         /* possible found one */
349                                         if (get_entity_link(ent) == NULL)
350                                                 ++res;
351                                         link_all_leave_sels(ent, succ);
352                                 }
353                         }
354                 }
355         }
356
357         return res;
358 }
359
360 /**
361  * Return a path from the Sel node sel to it's root.
362  *
363  * @param sel  the Sel node
364  * @param len  the length of the path so far
365  */
366 static path_t *find_path(ir_node *sel, unsigned len) {
367         int pos, i, n;
368         path_t *res;
369         ir_node *pred = get_Sel_ptr(sel);
370
371         /* the current Sel node will add some path elements */
372         n    = get_Sel_n_indexs(sel);
373         len += n + 1;
374
375         if (! is_Sel(pred)) {
376                 /* we found the root */
377
378                 res = xmalloc(sizeof(*res) + (len - 1) * sizeof(res->path));
379                 res->path_len = len;
380         } else
381                 res = find_path(pred, len);
382
383         pos = res->path_len - len;
384
385         res->path[pos++].ent = get_Sel_entity(sel);
386         for (i = 0; i < n; ++i) {
387                 ir_node *index = get_Sel_index(sel, i);
388
389                 res->path[pos++].tv = get_Const_tarval(index);
390         }
391         return res;
392 }
393
394
395 /**
396  * Allocate value numbers for the leaves
397  * in our found entities.
398  *
399  * @param sels  a set that will contain all Sels that have a value number
400  * @param ent   the entity that will be scalar replaced
401  * @param vnum  the first value number we can assign
402  * @param modes a flexible array, containing all the modes of
403  *              the value numbers.
404  *
405  * @return the next free value number
406  */
407 static unsigned allocate_value_numbers(pset *sels, ir_entity *ent, unsigned vnum, ir_mode ***modes)
408 {
409         ir_node *sel, *next;
410         path_t *key, *path;
411         set *pathes = new_set(path_cmp, 8);
412
413         /* visit all Sel nodes in the chain of the entity */
414         for (sel = get_entity_link(ent); sel; sel = next) {
415                 next = get_irn_link(sel);
416
417                 /* we must mark this sel for later */
418                 pset_insert_ptr(sels, sel);
419
420                 key  = find_path(sel, 0);
421                 path = set_find(pathes, key, PATH_SIZE(key), path_hash(key));
422
423                 if (path)
424                         SET_VNUM(sel, path->vnum);
425                 else {
426                         key->vnum = vnum++;
427
428                         set_insert(pathes, key, PATH_SIZE(key), path_hash(key));
429
430                         SET_VNUM(sel, key->vnum);
431                         ARR_EXTO(ir_mode *, *modes, (int)((key->vnum + 15) & ~15));
432
433                         (*modes)[key->vnum] = get_type_mode(get_entity_type(get_Sel_entity(sel)));
434
435                         assert((*modes)[key->vnum] && "Value is not atomic");
436
437 #ifdef DEBUG_libfirm
438                         /* Debug output */
439                         if (get_opt_scalar_replacement_verbose() && get_firm_verbosity() > 1) {
440                                 unsigned i;
441                                 printf("  %s", get_entity_name(key->path[0].ent));
442                                 for (i = 1; i < key->path_len; ++i) {
443                                         if (is_entity(key->path[i].ent))
444                                                 printf(".%s", get_entity_name(key->path[i].ent));
445                                         else
446                                                 printf("[%ld]", get_tarval_long(key->path[i].tv));
447                                 }
448                                 printf(" = %u (%s)\n", PTR_TO_INT(get_irn_link(sel)), get_mode_name((*modes)[key->vnum]));
449                         }
450 #endif /* DEBUG_libfirm */
451                 }
452                 free(key);
453         }
454
455         del_set(pathes);
456         set_entity_link(ent, NULL);
457         return vnum;
458 }
459
460 /**
461  * A list entry for the fixing lists
462  */
463 typedef struct _list_entry_t {
464         ir_node  *node;   /**< the node that must be fixed */
465         unsigned vnum;    /**< the value number of this node */
466 } list_entry_t;
467
468 /**
469  * environment for memory walker
470  */
471 typedef struct _env_t {
472         struct obstack obst;      /**< a obstack for the value blocks */
473         int          nvals;       /**< number of values */
474         ir_mode      **modes;     /**< the modes of the values */
475         list_entry_t *fix_phis;   /**< list of all Phi nodes that must be fixed */
476         list_entry_t *fix_loads;  /**< list of all Load nodes that must be fixed */
477         pset         *sels;       /**< A set of all Sel nodes that have a value number */
478 } env_t;
479
480 /**
481  * topological walker.
482  */
483 static void topologic_walker(ir_node *node, void *ctx) {
484         env_t        *env = ctx;
485         ir_op        *op = get_irn_op(node);
486         ir_node      *adr, *block, *mem, *unk, **value_arr, **in, *val;
487         ir_mode      *mode;
488         unsigned     vnum;
489         int          i, j, n;
490         list_entry_t *l;
491
492         if (op == op_Load) {
493                 /* a load, check if we can resolve it */
494                 adr = get_Load_ptr(node);
495
496                 if (! is_Sel(adr))
497                         return;
498
499                 if (! pset_find_ptr(env->sels, adr))
500                         return;
501
502                 /* ok, we have a Load that will be replaced */
503                 vnum = GET_VNUM(adr);
504
505                 assert(vnum < (unsigned)env->nvals);
506
507                 block     = get_nodes_block(node);
508                 value_arr = get_irn_link(block);
509
510                 /* check, if we can replace this Load */
511                 if (value_arr[vnum]) {
512                         mem = get_Load_mem(node);
513
514                         /* Beware: A Load can contain a hidden conversion in Firm.
515                         This happens for instance in the following code:
516
517                          int i;
518                          unsigned j = *(unsigned *)&i;
519
520                         Handle this here. */
521                         val = value_arr[vnum];
522                         mode = get_Load_mode(node);
523                         if (mode != get_irn_mode(val))
524                                 val = new_d_Conv(get_irn_dbg_info(node), val, mode);
525
526                         turn_into_tuple(node, pn_Load_max);
527                         set_Tuple_pred(node, pn_Load_M,         mem);
528                         set_Tuple_pred(node, pn_Load_res,       val);
529                         set_Tuple_pred(node, pn_Load_X_regular, new_r_Jmp(current_ir_graph, block));
530                         set_Tuple_pred(node, pn_Load_X_except,  new_Bad());
531                 } else {
532                         l = obstack_alloc(&env->obst, sizeof(*l));
533                         l->node = node;
534                         l->vnum = vnum;
535
536                         set_irn_link(node, env->fix_loads);
537                         env->fix_loads = l;
538                 }
539         } else if (op == op_Store) {
540                 /* a Store always can be replaced */
541                 adr = get_Store_ptr(node);
542
543                 if (! is_Sel(adr))
544                         return;
545
546                 if (! pset_find_ptr(env->sels, adr))
547                         return;
548
549                 vnum = GET_VNUM(adr);
550
551                 assert(vnum < (unsigned)env->nvals);
552
553                 block     = get_nodes_block(node);
554                 value_arr = get_irn_link(block);
555
556                 /* Beware: A Store can contain a hidden conversion in Firm. */
557                 val = get_Store_value(node);
558                 if (get_irn_mode(val) != env->modes[vnum])
559                         val = new_d_Conv(get_irn_dbg_info(node), val, env->modes[vnum]);
560                 value_arr[vnum] = val;
561
562                 mem = get_Store_mem(node);
563                 block = get_nodes_block(node);
564
565                 turn_into_tuple(node, pn_Store_max);
566                 set_Tuple_pred(node, pn_Store_M,         mem);
567                 set_Tuple_pred(node, pn_Store_X_regular, new_r_Jmp(current_ir_graph, block));
568                 set_Tuple_pred(node, pn_Store_X_except,  new_Bad());
569         } else if (op == op_Phi && get_irn_mode(node) == mode_M) {
570                 /*
571                  * found a memory Phi: Here, we must create new Phi nodes
572                  */
573                 block     = get_nodes_block(node);
574                 value_arr = get_irn_link(block);
575
576                 n = get_Block_n_cfgpreds(block);
577
578                 in = alloca(sizeof(*in) * n);
579
580                 for (i = env->nvals - 1; i >= 0; --i) {
581                         unk = new_Unknown(env->modes[i]);
582                         for (j = n - 1; j >= 0; --j)
583                                 in[j] = unk;
584
585                         value_arr[i] = new_r_Phi(current_ir_graph, block, n, in, env->modes[i]);
586
587                         l = obstack_alloc(&env->obst, sizeof(*l));
588                         l->node = value_arr[i];
589                         l->vnum = i;
590
591                         set_irn_link(value_arr[i], env->fix_phis);
592                         env->fix_phis = l;
593                 }
594         }
595 }
596
597 /**
598  * Walker: allocate the value array for every block.
599  */
600 static void alloc_value_arr(ir_node *block, void *ctx) {
601         env_t *env = ctx;
602         ir_node **var_arr = obstack_alloc(&env->obst, sizeof(*var_arr) * env->nvals);
603
604         /* the value array is empty at start */
605         memset(var_arr, 0, sizeof(*var_arr) * env->nvals);
606         set_irn_link(block, var_arr);
607 }
608
609 /**
610  * searches through blocks beginning from block for value
611  * vnum and return it.
612  */
613 static ir_node *find_vnum_value(ir_node *block, unsigned vnum) {
614         ir_node **value_arr;
615         int i;
616         ir_node *res;
617
618         if (Block_not_block_visited(block)) {
619                 mark_Block_block_visited(block);
620
621                 value_arr = get_irn_link(block);
622
623                 if (value_arr[vnum])
624                         return value_arr[vnum];
625
626                 for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) {
627                         ir_node *pred = get_Block_cfgpred(block, i);
628
629                         res = find_vnum_value(get_nodes_block(pred), vnum);
630                         if (res)
631                                 return res;
632                 }
633         }
634         return NULL;
635 }
636
637 /**
638  * fix the Phi list
639  */
640 static void fix_phis(env_t *env) {
641         list_entry_t *l;
642         ir_node      *phi, *block, *pred, *val;
643         int          i;
644
645         for (l = env->fix_phis; l; l = get_irn_link(phi)) {
646                 phi = l->node;
647
648                 block = get_nodes_block(phi);
649                 for (i = get_irn_arity(phi) - 1; i >= 0; --i) {
650                         pred = get_Block_cfgpred(block, i);
651                         pred = get_nodes_block(pred);
652
653                         inc_irg_block_visited(current_ir_graph);
654                         val = find_vnum_value(pred, l->vnum);
655
656                         if (val)
657                                 set_irn_n(phi, i, val);
658                 }
659         }
660 }
661
662 /**
663  * fix the Load list
664  */
665 static void fix_loads(env_t *env) {
666         list_entry_t *l;
667         ir_node      *load, *block, *pred, *val = NULL, *mem;
668         ir_mode      *mode;
669         int          i;
670
671         for (l = env->fix_loads; l; l = get_irn_link(load)) {
672                 load = l->node;
673
674                 block = get_nodes_block(load);
675                 for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) {
676                         pred = get_Block_cfgpred(block, i);
677                         pred = get_nodes_block(pred);
678
679                         inc_irg_block_visited(current_ir_graph);
680                         val = find_vnum_value(pred, l->vnum);
681
682                         if (val)
683                                 break;
684                 }
685
686                 if (! val) {
687                         /* access of an uninitialized value */
688                         val = new_Unknown(env->modes[l->vnum]);
689                 }
690
691                 /* Beware: A Load can contain a hidden conversion in Firm.
692                    Handle this here. */
693                 mode = get_Load_mode(load);
694                 if (mode != get_irn_mode(val))
695                         val = new_d_Conv(get_irn_dbg_info(load), val, mode);
696
697                 mem = get_Load_mem(load);
698
699                 turn_into_tuple(load, pn_Load_max);
700                 set_Tuple_pred(load, pn_Load_M,         mem);
701                 set_Tuple_pred(load, pn_Load_res,       val);
702                 set_Tuple_pred(load, pn_Load_X_regular, new_r_Jmp(current_ir_graph, block));
703                 set_Tuple_pred(load, pn_Load_X_except,  new_Bad());
704         }
705 }
706
707 /**
708  *  Make scalar replacement.
709  *
710  * @param sels    A set containing all Sel nodes that have a value number
711  * @param nvals   The number of scalars.
712  * @param modes   A flexible array, containing all the modes of
713  *                the value numbers.
714  */
715 static void do_scalar_replacements(pset *sels, int nvals, ir_mode **modes) {
716         env_t env;
717
718         obstack_init(&env.obst);
719         env.nvals     = nvals;
720         env.modes     = modes;
721         env.fix_phis  = NULL;
722         env.fix_loads = NULL;
723         env.sels      = sels;
724
725         /* first step: allocate the value arrays for every block */
726         irg_block_walk_graph(current_ir_graph, NULL, alloc_value_arr, &env);
727
728         /*
729          * second step: walk over the graph blockwise in topological order
730          * and fill the array as much as possible.
731          */
732         irg_walk_blkwise_graph(current_ir_graph, NULL, topologic_walker, &env);
733
734         /* third, fix the list of Phis, then the list of Loads */
735         fix_phis(&env);
736         fix_loads(&env);
737
738         obstack_free(&env.obst, NULL);
739 }
740
741 /*
742  * Find possible scalar replacements
743  *
744  * @param irg  The current ir graph.
745  */
746 void scalar_replacement_opt(ir_graph *irg) {
747         unsigned  nvals;
748         int       i;
749         scalars_t key, *value;
750         ir_node   *irg_frame;
751         ir_mode   **modes;
752         set       *set_ent;
753         pset      *sels;
754         ir_type   *ent_type;
755         ir_graph  *rem;
756
757         if (! get_opt_scalar_replacement())
758                 return;
759
760         rem = current_ir_graph;
761
762         /* Call algorithm that computes the out edges */
763         assure_irg_outs(irg);
764
765         /* Find possible scalar replacements */
766         if (find_possible_replacements(irg)) {
767
768                 if (get_opt_scalar_replacement_verbose()) {
769                         printf("Scalar Replacement: %s\n", get_entity_name(get_irg_entity(irg)));
770                 }
771
772                 /* Insert in set the scalar replacements. */
773                 irg_frame = get_irg_frame(irg);
774                 nvals = 0;
775                 modes = NEW_ARR_F(ir_mode *, 16);
776                 set_ent = new_set(ent_cmp, 8);
777                 sels    = pset_new_ptr(8);
778
779                 for (i = 0 ; i < get_irn_n_outs(irg_frame); i++) {
780                         ir_node *succ = get_irn_out(irg_frame, i);
781
782                         if (is_Sel(succ)) {
783                                 ir_entity *ent = get_Sel_entity(succ);
784
785                                 if (get_entity_link(ent) == NULL || get_entity_link(ent) == ADDRESS_TAKEN)
786                                         continue;
787
788                                 ent_type = get_entity_type(ent);
789
790                                 key.ent       = ent;
791                                 key.ent_owner = get_entity_owner(ent);
792                                 set_insert(set_ent, &key, sizeof(key), HASH_PTR(key.ent));
793
794                                 if (get_opt_scalar_replacement_verbose()) {
795                                         if (is_Array_type(ent_type)) {
796                                                 printf("  found array %s\n", get_entity_name(ent));
797                                         }
798                                         else if (is_Struct_type(ent_type)) {
799                                                 printf("  found struct %s\n", get_entity_name(ent));
800                                         }
801                                         else if (is_atomic_type(ent_type))
802                                                 printf("  found atomic value %s\n", get_entity_name(ent));
803                                         else {
804                                                 assert(0 && "Neither an array nor a struct or atomic value");
805                                         }
806                                 }
807
808                                 nvals = allocate_value_numbers(sels, ent, nvals, &modes);
809                         }
810                 }
811
812                 if (get_opt_scalar_replacement_verbose()) {
813                         printf("  %u values will be needed\n", nvals);
814                 }
815
816                 /* If scalars were found. */
817                 if (nvals) {
818                         do_scalar_replacements(sels, nvals, modes);
819
820                         for (value = set_first(set_ent); value; value = set_next(set_ent)) {
821                                 remove_class_member(value->ent_owner, value->ent);
822                         }
823                 }
824
825                 del_pset(sels);
826                 del_set(set_ent);
827                 DEL_ARR_F(modes);
828
829                 if (nvals) {
830                         /*
831                          * We changed the graph, but did NOT introduce new blocks
832                          * neither changed control flow, cf-backedges should be still
833                          * consistent.
834                          */
835                         set_irg_outs_inconsistent(irg);
836                         set_irg_loopinfo_inconsistent(irg);
837                 }
838         }
839
840         current_ir_graph = rem;
841 }