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