irgmod: Pass the new inputs to turn_into_tuple() instead of initialising them with...
[libfirm] / ir / opt / scalar_replace.c
1 /*
2  * Copyright (C) 1995-2011 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Scalar replacement of compounds.
23  * @author  Beyhan Veliev, Michael Beck
24  */
25 #include "config.h"
26
27 #include <string.h>
28 #include <stdbool.h>
29
30 #include "iroptimize.h"
31 #include "scalar_replace.h"
32 #include "opt_init.h"
33 #include "irflag_t.h"
34 #include "irouts.h"
35 #include "set.h"
36 #include "pset.h"
37 #include "array.h"
38 #include "tv.h"
39 #include "ircons_t.h"
40 #include "hashptr.h"
41 #include "irgwalk.h"
42 #include "irgmod.h"
43 #include "irnode_t.h"
44 #include "irpass.h"
45 #include "util.h"
46 #include "xmalloc.h"
47 #include "debug.h"
48 #include "error.h"
49
50 static unsigned get_vnum(const ir_node *node)
51 {
52         return (unsigned)PTR_TO_INT(get_irn_link(node));
53 }
54
55 static void set_vnum(ir_node *node, unsigned vnum)
56 {
57         set_irn_link(node, INT_TO_PTR(vnum));
58 }
59
60 /**
61  * A path element entry: it is either an entity
62  * or a tarval, because we evaluate only constant array
63  * accesses like a.b.c[8].d
64  */
65 typedef union {
66         ir_entity *ent;
67         ir_tarval *tv;
68 } path_elem_t;
69
70 /**
71  * An access path, used to assign value numbers
72  * to variables that will be scalar replaced.
73  */
74 typedef struct path_t {
75         unsigned    vnum;      /**< The value number. */
76         size_t      path_len;  /**< The length of the access path. */
77         path_elem_t path[1];   /**< The path. */
78 } path_t;
79
80 /** The size of a path in bytes. */
81 static size_t path_size(path_t *p)
82 {
83         return sizeof(*p) + sizeof(p->path[0]) * (p->path_len-1);
84 }
85
86 typedef struct scalars_t {
87         ir_entity *ent;              /**< A entity for scalar replacement. */
88 } scalars_t;
89
90 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
91
92 /**
93  * Compare two pathes.
94  *
95  * @return 0 if they are identically
96  */
97 static int path_cmp(const void *elt, const void *key, size_t size)
98 {
99         const path_t *p1 = (const path_t*)elt;
100         const path_t *p2 = (const path_t*)key;
101         (void) size;
102
103         /* we can use memcmp here, because identical tarvals should have identical addresses */
104         return memcmp(p1->path, p2->path, p1->path_len * sizeof(p1->path[0]));
105 }
106
107 /**
108  * Compare two elements of the scalars_t set.
109  *
110  * @return 0 if they are identically
111  */
112 static int ent_cmp(const void *elt, const void *key, size_t size)
113 {
114         const scalars_t *c1 = (const scalars_t*)elt;
115         const scalars_t *c2 = (const scalars_t*)key;
116         (void) size;
117
118         return c1->ent != c2->ent;
119 }
120
121 /**
122  * Calculate a hash value for a path.
123  */
124 static unsigned path_hash(const path_t *path)
125 {
126         unsigned hash = 0;
127         unsigned i;
128
129         for (i = 0; i < path->path_len; ++i)
130                 hash ^= (unsigned)PTR_TO_INT(path->path[i].ent);
131
132         return hash >> 4;
133 }
134
135 /**
136  * Returns non-zero, if all indeces of a Sel node are constants.
137  *
138  * @param sel  the Sel node that will be checked
139  */
140 static bool is_const_sel(ir_node *sel)
141 {
142         int i, n = get_Sel_n_indexs(sel);
143
144         for (i = 0; i < n; ++i) {
145                 ir_node *idx = get_Sel_index(sel, i);
146
147                 if (!is_Const(idx))
148                         return false;
149         }
150         return true;
151 }
152
153 /**
154  * Check the mode of a Load/Store with the mode of the entity
155  * that is accessed.
156  * If the mode of the entity and the Load/Store mode do not match, we
157  * have the bad reinterpret case:
158  *
159  * int i;
160  * char b = *(char *)&i;
161  *
162  * We do NOT count this as one value and return address_taken
163  * in that case.
164  * However, we support an often used case. If the mode is two-complement
165  * we allow casts between signed/unsigned.
166  *
167  * @param mode     the mode of the Load/Store
168  * @param ent_mode the mode of the accessed entity
169  */
170 static bool check_load_store_mode(ir_mode *mode, ir_mode *ent_mode)
171 {
172         if (ent_mode != mode) {
173                 if (ent_mode == NULL ||
174                     get_mode_size_bits(ent_mode) != get_mode_size_bits(mode) ||
175                     get_mode_arithmetic(ent_mode) != irma_twos_complement ||
176                     get_mode_arithmetic(mode) != irma_twos_complement)
177                         return false;
178         }
179         return true;
180 }
181
182 /*
183  * Returns non-zero, if the address of an entity
184  * represented by a Sel node (or its successor Sels) is taken.
185  */
186 bool is_address_taken(ir_node *sel)
187 {
188         int       input_nr;
189         ir_mode   *emode, *mode;
190         ir_node   *value;
191         ir_entity *ent;
192
193         if (! is_const_sel(sel))
194                 return true;
195
196         for (unsigned i = get_irn_n_outs(sel); i-- > 0; ) {
197                 ir_node *succ = get_irn_out(sel, i);
198
199                 switch (get_irn_opcode(succ)) {
200                 case iro_Load:
201                         /* do not remove volatile variables */
202                         if (get_Load_volatility(succ) == volatility_is_volatile)
203                                 return true;
204                         /* check if this load is not a hidden conversion */
205                         mode = get_Load_mode(succ);
206                         ent = get_Sel_entity(sel);
207                         emode = get_type_mode(get_entity_type(ent));
208                         if (! check_load_store_mode(mode, emode))
209                                 return true;
210                         break;
211
212                 case iro_Store:
213                         /* check that Sel is not the Store's value */
214                         value = get_Store_value(succ);
215                         if (value == sel)
216                                 return true;
217                         /* do not remove volatile variables */
218                         if (get_Store_volatility(succ) == volatility_is_volatile)
219                                 return true;
220                         /* check if this Store is not a hidden conversion */
221                         mode = get_irn_mode(value);
222                         ent = get_Sel_entity(sel);
223                         emode = get_type_mode(get_entity_type(ent));
224                         if (! check_load_store_mode(mode, emode))
225                                 return true;
226                         break;
227
228                 case iro_Sel: {
229                         int       res;
230                         ir_entity *entity = get_Sel_entity(succ);
231                         /* we can't handle unions correctly yet -> address taken */
232                         if (is_Union_type(get_entity_owner(entity)))
233                                 return true;
234
235                         /* Check the Sel successor of Sel */
236                         res = is_address_taken(succ);
237                         if (res)
238                                 return true;
239                         break;
240                 }
241
242                 case iro_Call:
243                         /* The address of an entity is given as a parameter.
244                          * As long as we do not have analyses that can tell what
245                          * is done with parameters, think is taken.
246                          * One special case: If the Call type tells that it's a
247                          * value parameter, the address is NOT taken.
248                          */
249                         return true;
250
251                 case iro_Id: {
252                         int res = is_address_taken(succ);
253                         if (res)
254                                 return true;
255                         break;
256                 }
257
258                 case iro_Tuple:
259                         /* Non-optimized Tuple, happens in inlining */
260                         for (input_nr = get_Tuple_n_preds(succ) - 1; input_nr >= 0; --input_nr) {
261                                 ir_node *pred = get_Tuple_pred(succ, input_nr);
262
263                                 if (pred == sel) {
264                                         /* we found one input */
265                                         for (unsigned k = get_irn_n_outs(succ); k-- > 0; ) {
266                                                 ir_node *proj = get_irn_out(succ, k);
267
268                                                 if (is_Proj(proj) && get_Proj_proj(proj) == input_nr) {
269                                                         int res = is_address_taken(proj);
270                                                         if (res)
271                                                                 return true;
272                                                 }
273                                         }
274                                 }
275                         }
276                         break;
277
278                 default:
279                         /* another op, the address is taken */
280                         return true;
281                 }
282         }
283         return false;
284 }
285
286 /**
287  * Link all leave Sels with the entity.
288  *
289  * @param ent  the entity that will be scalar replaced
290  * @param sel  a Sel node that selects some fields of this entity
291  */
292 static bool link_all_leave_sels(ir_entity *ent, ir_node *sel)
293 {
294         bool is_leave = true;
295
296         for (unsigned i = get_irn_n_outs(sel); i-- > 0; ) {
297                 ir_node *succ = get_irn_out(sel, i);
298
299                 if (is_Sel(succ)) {
300                         /* the current leave has further Sel's, no leave */
301                         is_leave = false;
302                         link_all_leave_sels(ent, succ);
303                 } else if (is_Id(succ)) {
304                         is_leave &= link_all_leave_sels(ent, succ);
305                 }
306         }
307
308         if (is_leave) {
309                 /* beware of Id's */
310                 sel = skip_Id(sel);
311
312                 /* we know we are at a leave, because this function is only
313                  * called if the address is NOT taken, so sel's successor(s)
314                  * must be Loads or Stores
315                  */
316                 set_irn_link(sel, get_entity_link(ent));
317                 set_entity_link(ent, sel);
318         }
319         return is_leave;
320 }
321
322 /* we need a special address that serves as an address taken marker */
323 static char _x;
324 static void *ADDRESS_TAKEN = &_x;
325
326 /**
327  * Find possible scalar replacements.
328  *
329  * @param irg  an IR graph
330  *
331  * This function finds variables on the (members of the) frame type
332  * that can be scalar replaced, because their address is never taken.
333  * If such a variable is found, its entity link will hold a list of all
334  * Sel nodes, that selects the atomic fields of this entity.
335  * Otherwise, the link will be ADDRESS_TAKEN or NULL.
336  *
337  * @return  non-zero if at least one entity could be replaced
338  *          potentially
339  */
340 static int find_possible_replacements(ir_graph *irg)
341 {
342         ir_node *irg_frame;
343         ir_type *frame_tp;
344         size_t  mem_idx;
345         long    static_link_arg;
346         int     res = 0;
347
348         /*
349          * First, clear the link field of all interesting entities.
350          */
351         frame_tp = get_irg_frame_type(irg);
352         for (mem_idx = get_class_n_members(frame_tp); mem_idx > 0;) {
353                 ir_entity *ent = get_class_member(frame_tp, --mem_idx);
354                 set_entity_link(ent, NULL);
355         }
356
357         /* check for inner functions:
358          * FIXME: need a way to get the argument position for the static link */
359         static_link_arg = 0;
360         for (mem_idx = get_class_n_members(frame_tp); mem_idx > 0;) {
361                 ir_entity *ent = get_class_member(frame_tp, --mem_idx);
362                 if (is_method_entity(ent)) {
363                         ir_graph *inner_irg = get_entity_irg(ent);
364                         ir_node  *args;
365
366                         assure_irg_properties(inner_irg, IR_GRAPH_PROPERTY_CONSISTENT_OUTS);
367                         args = get_irg_args(inner_irg);
368                         for (unsigned j = get_irn_n_outs(args); j-- > 0; ) {
369                                 ir_node *arg = get_irn_out(args, j);
370
371                                 if (get_Proj_proj(arg) == static_link_arg) {
372                                         for (unsigned k = get_irn_n_outs(arg); k-- > 0; ) {
373                                                 ir_node *succ = get_irn_out(arg, k);
374
375                                                 if (is_Sel(succ)) {
376                                                         ir_entity *ent = get_Sel_entity(succ);
377
378                                                         if (get_entity_owner(ent) == frame_tp) {
379                                                                 /* found an access to the outer frame */
380                                                                 set_entity_link(ent, ADDRESS_TAKEN);
381                                                         }
382                                                 }
383                                         }
384                                 }
385                         }
386                 }
387         }
388
389         /*
390          * Check the ir_graph for Sel nodes. If the entity of Sel
391          * isn't a scalar replacement set the link of this entity
392          * equal ADDRESS_TAKEN.
393          */
394         irg_frame = get_irg_frame(irg);
395         for (unsigned i = get_irn_n_outs(irg_frame); i-- > 0; ) {
396                 ir_node *succ = get_irn_out(irg_frame, i);
397
398                 if (is_Sel(succ)) {
399                         ir_entity *ent = get_Sel_entity(succ);
400                         ir_type *ent_type;
401
402                         /* we are only interested in entities on the frame, NOT
403                            on the value type */
404                         if (get_entity_owner(ent) != frame_tp)
405                                 continue;
406
407                         if (get_entity_link(ent) == ADDRESS_TAKEN)
408                                 continue;
409
410                         ent_type = get_entity_type(ent);
411
412                         /* we can handle arrays, structs and atomic types yet */
413                         if (is_Array_type(ent_type) || is_Struct_type(ent_type) || is_atomic_type(ent_type)) {
414                                 if (is_address_taken(succ)) {
415                                          /* killing one */
416                                         if (get_entity_link(ent))
417                                                 --res;
418                                         set_entity_link(ent, ADDRESS_TAKEN);
419                                 } else {
420                                         /* possible found one */
421                                         if (get_entity_link(ent) == NULL)
422                                                 ++res;
423                                         link_all_leave_sels(ent, succ);
424                                 }
425                         }
426                 }
427         }
428
429         return res;
430 }
431
432 /**
433  * Return a path from the Sel node "sel" to its root.
434  *
435  * @param sel  the Sel node
436  * @param len  the length of the path so far
437  */
438 static path_t *find_path(ir_node *sel, size_t len)
439 {
440         size_t pos;
441         int i, n;
442         path_t *res;
443         ir_node *pred = get_Sel_ptr(sel);
444
445         /* the current Sel node will add some path elements */
446         n    = get_Sel_n_indexs(sel);
447         len += n + 1;
448
449         if (! is_Sel(pred)) {
450                 /* we found the root */
451                 res = XMALLOCF(path_t, path, len);
452                 res->path_len = len;
453         } else
454                 res = find_path(pred, len);
455
456         assert(len <= res->path_len);
457         pos = res->path_len - len;
458
459         res->path[pos++].ent = get_Sel_entity(sel);
460         for (i = 0; i < n; ++i) {
461                 ir_node *index = get_Sel_index(sel, i);
462
463                 res->path[pos++].tv = get_Const_tarval(index);
464         }
465         return res;
466 }
467
468
469 /**
470  * Allocate value numbers for the leaves
471  * in our found entities.
472  *
473  * @param sels  a set that will contain all Sels that have a value number
474  * @param ent   the entity that will be scalar replaced
475  * @param vnum  the first value number we can assign
476  * @param modes a flexible array, containing all the modes of
477  *              the value numbers.
478  *
479  * @return the next free value number
480  */
481 static unsigned allocate_value_numbers(pset *sels, ir_entity *ent, unsigned vnum, ir_mode ***modes)
482 {
483         ir_node *sel, *next;
484         path_t *key, *path;
485         set *pathes = new_set(path_cmp, 8);
486
487         DB((dbg, SET_LEVEL_3, "  Visiting Sel nodes of entity %+F\n", ent));
488         /* visit all Sel nodes in the chain of the entity */
489         for (sel = (ir_node*)get_entity_link(ent); sel != NULL; sel = next) {
490                 next = (ir_node*)get_irn_link(sel);
491
492                 /* we must mark this sel for later */
493                 pset_insert_ptr(sels, sel);
494
495                 key  = find_path(sel, 0);
496                 path = set_find(path_t, pathes, key, path_size(key), path_hash(key));
497
498                 if (path) {
499                         set_vnum(sel, path->vnum);
500                         DB((dbg, SET_LEVEL_3, "  %+F represents value %u\n", sel, path->vnum));
501                 } else {
502                         key->vnum = vnum++;
503
504                         (void)set_insert(path_t, pathes, key, path_size(key), path_hash(key));
505
506                         set_vnum(sel, key->vnum);
507                         DB((dbg, SET_LEVEL_3, "  %+F represents value %u\n", sel, key->vnum));
508
509                         ARR_EXTO(ir_mode *, *modes, (key->vnum + 15) & ~15);
510
511                         (*modes)[key->vnum] = get_type_mode(get_entity_type(get_Sel_entity(sel)));
512
513                         assert((*modes)[key->vnum] && "Value is not atomic");
514
515 #ifdef DEBUG_libfirm
516                         /* Debug output */
517                         {
518                                 unsigned i;
519                                 DB((dbg, SET_LEVEL_2, "  %s", get_entity_name(key->path[0].ent)));
520                                 for (i = 1; i < key->path_len; ++i) {
521                                         if (is_entity(key->path[i].ent))
522                                                 DB((dbg, SET_LEVEL_2, ".%s", get_entity_name(key->path[i].ent)));
523                                         else
524                                                 DB((dbg, SET_LEVEL_2, "[%ld]", get_tarval_long(key->path[i].tv)));
525                                 }
526                                 DB((dbg, SET_LEVEL_2, " = %u (%s)\n", PTR_TO_INT(get_irn_link(sel)), get_mode_name((*modes)[key->vnum])));
527                         }
528 #endif /* DEBUG_libfirm */
529                 }
530                 free(key);
531         }
532
533         del_set(pathes);
534         set_entity_link(ent, NULL);
535         return vnum;
536 }
537
538 /**
539  * environment for memory walker
540  */
541 typedef struct env_t {
542         unsigned nvals;      /**< number of values */
543         ir_mode  **modes;    /**< the modes of the values */
544         pset     *sels;      /**< A set of all Sel nodes that have a value number */
545 } env_t;
546
547 /**
548  * topological post-walker.
549  */
550 static void walker(ir_node *node, void *ctx)
551 {
552         env_t    *env = (env_t*)ctx;
553         ir_graph *irg = get_irn_irg(node);
554         ir_node  *addr, *block, *mem, *val;
555         ir_mode  *mode;
556         unsigned vnum;
557
558         if (is_Load(node)) {
559                 /* a load, check if we can resolve it */
560                 addr = get_Load_ptr(node);
561
562                 DB((dbg, SET_LEVEL_3, "  checking %+F for replacement ", node));
563                 if (! is_Sel(addr)) {
564                         DB((dbg, SET_LEVEL_3, "no Sel input (%+F)\n", addr));
565                         return;
566                 }
567
568                 if (! pset_find_ptr(env->sels, addr)) {
569                         DB((dbg, SET_LEVEL_3, "Sel %+F has no VNUM\n", addr));
570                         return;
571                 }
572
573                 /* ok, we have a Load that will be replaced */
574                 vnum = get_vnum(addr);
575                 assert(vnum < env->nvals);
576
577                 DB((dbg, SET_LEVEL_3, "replacing by value %u\n", vnum));
578
579                 block = get_nodes_block(node);
580                 set_cur_block(block);
581
582                 /* check, if we can replace this Load */
583                 val = get_value(vnum, env->modes[vnum]);
584
585                 /* Beware: A Load can contain a hidden conversion in Firm.
586                 This happens for instance in the following code:
587
588                  int i;
589                  unsigned j = *(unsigned *)&i;
590
591                 Handle this here. */
592                 mode = get_Load_mode(node);
593                 if (mode != get_irn_mode(val))
594                         val = new_rd_Conv(get_irn_dbg_info(node), block, val, mode);
595
596                 mem = get_Load_mem(node);
597                 ir_node *const in[] = {
598                         [pn_Load_M]         = mem,
599                         [pn_Load_res]       = val,
600                         [pn_Load_X_regular] = new_r_Jmp(block),
601                         [pn_Load_X_except]  = new_r_Bad(irg, mode_X),
602                 };
603                 turn_into_tuple(node, ARRAY_SIZE(in), in);
604         } else if (is_Store(node)) {
605                 DB((dbg, SET_LEVEL_3, "  checking %+F for replacement ", node));
606
607                 /* a Store always can be replaced */
608                 addr = get_Store_ptr(node);
609
610                 if (! is_Sel(addr)) {
611                         DB((dbg, SET_LEVEL_3, "no Sel input (%+F)\n", addr));
612                         return;
613                 }
614
615                 if (! pset_find_ptr(env->sels, addr)) {
616                         DB((dbg, SET_LEVEL_3, "Sel %+F has no VNUM\n", addr));
617                         return;
618                 }
619
620                 vnum = get_vnum(addr);
621                 assert(vnum < env->nvals);
622
623                 DB((dbg, SET_LEVEL_3, "replacing by value %u\n", vnum));
624
625                 block = get_nodes_block(node);
626                 set_cur_block(block);
627
628                 /* Beware: A Store can contain a hidden conversion in Firm. */
629                 val = get_Store_value(node);
630                 if (get_irn_mode(val) != env->modes[vnum])
631                         val = new_rd_Conv(get_irn_dbg_info(node), block, val, env->modes[vnum]);
632
633                 set_value(vnum, val);
634
635                 mem = get_Store_mem(node);
636                 ir_node *const in[] = {
637                         [pn_Store_M]         = mem,
638                         [pn_Store_X_regular] = new_r_Jmp(block),
639                         [pn_Store_X_except]  = new_r_Bad(irg, mode_X),
640                 };
641                 turn_into_tuple(node, ARRAY_SIZE(in), in);
642         }
643 }
644
645 /**
646  * Make scalar replacement.
647  *
648  * @param sels    A set containing all Sel nodes that have a value number
649  * @param nvals   The number of scalars.
650  * @param modes   A flexible array, containing all the modes of
651  *                the value numbers.
652  */
653 static void do_scalar_replacements(ir_graph *irg, pset *sels, unsigned nvals,
654                                    ir_mode **modes)
655 {
656         env_t env;
657
658         ssa_cons_start(irg, (int)nvals);
659
660         env.nvals = nvals;
661         env.modes = modes;
662         env.sels  = sels;
663
664         /*
665          * second step: walk over the graph blockwise in topological order
666          * and fill the array as much as possible.
667          */
668         DB((dbg, SET_LEVEL_3, "Substituting Loads and Stores in %+F\n", irg));
669         irg_walk_blkwise_graph(irg, NULL, walker, &env);
670
671         ssa_cons_finish(irg);
672 }
673
674 /*
675  * Find possible scalar replacements
676  *
677  * @param irg  The current ir graph.
678  */
679 void scalar_replacement_opt(ir_graph *irg)
680 {
681         unsigned  nvals;
682         scalars_t key;
683         ir_node   *irg_frame;
684         ir_mode   **modes;
685         set       *set_ent;
686         pset      *sels;
687         ir_type   *ent_type, *frame_tp;
688
689         assure_irg_properties(irg,
690                 IR_GRAPH_PROPERTY_NO_UNREACHABLE_CODE
691                 | IR_GRAPH_PROPERTY_CONSISTENT_OUTS);
692
693         /* we use the link field to store the VNUM */
694         ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
695         irp_reserve_resources(irp, IRP_RESOURCE_ENTITY_LINK);
696
697         /* Find possible scalar replacements */
698         if (find_possible_replacements(irg)) {
699                 DB((dbg, SET_LEVEL_1, "Scalar Replacement: %+F\n", irg));
700
701                 /* Insert in set the scalar replacements. */
702                 irg_frame = get_irg_frame(irg);
703                 nvals     = 0;
704                 modes     = NEW_ARR_F(ir_mode *, 16);
705                 set_ent   = new_set(ent_cmp, 8);
706                 sels      = pset_new_ptr(8);
707                 frame_tp  = get_irg_frame_type(irg);
708
709                 for (unsigned i = get_irn_n_outs(irg_frame); i-- > 0; ) {
710                         ir_node *succ = get_irn_out(irg_frame, i);
711
712                         if (is_Sel(succ)) {
713                                 ir_entity *ent = get_Sel_entity(succ);
714
715                                 /* we are only interested in entities on the frame, NOT
716                                    parameters */
717                                 if (get_entity_owner(ent) != frame_tp
718                                     || is_parameter_entity(ent))
719                                         continue;
720
721                                 if (get_entity_link(ent) == NULL || get_entity_link(ent) == ADDRESS_TAKEN)
722                                         continue;
723
724                                 ent_type = get_entity_type(ent);
725
726                                 key.ent       = ent;
727                                 (void)set_insert(scalars_t, set_ent, &key, sizeof(key), hash_ptr(key.ent));
728
729 #ifdef DEBUG_libfirm
730                                 if (is_Array_type(ent_type)) {
731                                         DB((dbg, SET_LEVEL_1, "  found array %s\n", get_entity_name(ent)));
732                                 } else if (is_Struct_type(ent_type)) {
733                                         DB((dbg, SET_LEVEL_1, "  found struct %s\n", get_entity_name(ent)));
734                                 } else if (is_atomic_type(ent_type))
735                                         DB((dbg, SET_LEVEL_1, "  found atomic value %s\n", get_entity_name(ent)));
736                                 else {
737                                         panic("Neither an array nor a struct or atomic value found in scalar replace");
738                                 }
739 #endif /* DEBUG_libfirm */
740
741                                 nvals = allocate_value_numbers(sels, ent, nvals, &modes);
742                         }
743                 }
744
745                 DB((dbg, SET_LEVEL_1, "  %u values will be needed\n", nvals));
746
747                 /* If scalars were found. */
748                 if (nvals > 0) {
749                         do_scalar_replacements(irg, sels, nvals, modes);
750
751                         foreach_set(set_ent, scalars_t, value) {
752                                 free_entity(value->ent);
753                         }
754
755                         /*
756                          * We changed the graph, but did NOT introduce new blocks
757                          * neither changed control flow, cf-backedges should be still
758                          * consistent.
759                          */
760                 }
761                 del_pset(sels);
762                 del_set(set_ent);
763                 DEL_ARR_F(modes);
764         }
765
766         ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
767         irp_free_resources(irp, IRP_RESOURCE_ENTITY_LINK);
768
769         confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_NONE);
770 }
771
772 ir_graph_pass_t *scalar_replacement_opt_pass(const char *name)
773 {
774         return def_graph_pass(name ? name : "scalar_rep", scalar_replacement_opt);
775 }
776
777 void firm_init_scalar_replace(void)
778 {
779         FIRM_DBG_REGISTER(dbg, "firm.opt.scalar_replace");
780 }