Replace the reassoc env struct by its only member.
[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       i, input_nr, k;
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 (i = get_irn_n_outs(sel) - 1; i >= 0; --i) {
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 (k = get_irn_n_outs(succ) - 1; k >= 0; --k) {
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         int i;
295         bool is_leave = true;
296
297         for (i = get_irn_n_outs(sel) - 1; i >= 0; --i) {
298                 ir_node *succ = get_irn_out(sel, i);
299
300                 if (is_Sel(succ)) {
301                         /* the current leave has further Sel's, no leave */
302                         is_leave = false;
303                         link_all_leave_sels(ent, succ);
304                 } else if (is_Id(succ)) {
305                         is_leave &= link_all_leave_sels(ent, succ);
306                 }
307         }
308
309         if (is_leave) {
310                 /* beware of Id's */
311                 sel = skip_Id(sel);
312
313                 /* we know we are at a leave, because this function is only
314                  * called if the address is NOT taken, so sel's successor(s)
315                  * must be Loads or Stores
316                  */
317                 set_irn_link(sel, get_entity_link(ent));
318                 set_entity_link(ent, sel);
319         }
320         return is_leave;
321 }
322
323 /* we need a special address that serves as an address taken marker */
324 static char _x;
325 static void *ADDRESS_TAKEN = &_x;
326
327 /**
328  * Find possible scalar replacements.
329  *
330  * @param irg  an IR graph
331  *
332  * This function finds variables on the (members of the) frame type
333  * that can be scalar replaced, because their address is never taken.
334  * If such a variable is found, its entity link will hold a list of all
335  * Sel nodes, that selects the atomic fields of this entity.
336  * Otherwise, the link will be ADDRESS_TAKEN or NULL.
337  *
338  * @return  non-zero if at least one entity could be replaced
339  *          potentially
340  */
341 static int find_possible_replacements(ir_graph *irg)
342 {
343         ir_node *irg_frame;
344         ir_type *frame_tp;
345         size_t  mem_idx;
346         int     i;
347         long    static_link_arg;
348         int     res = 0;
349
350         /*
351          * First, clear the link field of all interesting entities.
352          */
353         frame_tp = get_irg_frame_type(irg);
354         for (mem_idx = get_class_n_members(frame_tp); mem_idx > 0;) {
355                 ir_entity *ent = get_class_member(frame_tp, --mem_idx);
356                 set_entity_link(ent, NULL);
357         }
358
359         /* check for inner functions:
360          * FIXME: need a way to get the argument position for the static link */
361         static_link_arg = 0;
362         for (mem_idx = get_class_n_members(frame_tp); mem_idx > 0;) {
363                 ir_entity *ent = get_class_member(frame_tp, --mem_idx);
364                 if (is_method_entity(ent)) {
365                         ir_graph *inner_irg = get_entity_irg(ent);
366                         ir_node  *args;
367                         int      j;
368
369                         assure_irg_properties(inner_irg, IR_GRAPH_PROPERTY_CONSISTENT_OUTS);
370                         args = get_irg_args(inner_irg);
371                         for (j = get_irn_n_outs(args) - 1; j >= 0; --j) {
372                                 ir_node *arg = get_irn_out(args, j);
373
374                                 if (get_Proj_proj(arg) == static_link_arg) {
375                                         int k;
376                                         for (k = get_irn_n_outs(arg) - 1; k >= 0; --k) {
377                                                 ir_node *succ = get_irn_out(arg, k);
378
379                                                 if (is_Sel(succ)) {
380                                                         ir_entity *ent = get_Sel_entity(succ);
381
382                                                         if (get_entity_owner(ent) == frame_tp) {
383                                                                 /* found an access to the outer frame */
384                                                                 set_entity_link(ent, ADDRESS_TAKEN);
385                                                         }
386                                                 }
387                                         }
388                                 }
389                         }
390                 }
391         }
392
393         /*
394          * Check the ir_graph for Sel nodes. If the entity of Sel
395          * isn't a scalar replacement set the link of this entity
396          * equal ADDRESS_TAKEN.
397          */
398         irg_frame = get_irg_frame(irg);
399         for (i = get_irn_n_outs(irg_frame) - 1; i >= 0; --i) {
400                 ir_node *succ = get_irn_out(irg_frame, i);
401
402                 if (is_Sel(succ)) {
403                         ir_entity *ent = get_Sel_entity(succ);
404                         ir_type *ent_type;
405
406                         /* we are only interested in entities on the frame, NOT
407                            on the value type */
408                         if (get_entity_owner(ent) != frame_tp)
409                                 continue;
410
411                         if (get_entity_link(ent) == ADDRESS_TAKEN)
412                                 continue;
413
414                         ent_type = get_entity_type(ent);
415
416                         /* we can handle arrays, structs and atomic types yet */
417                         if (is_Array_type(ent_type) || is_Struct_type(ent_type) || is_atomic_type(ent_type)) {
418                                 if (is_address_taken(succ)) {
419                                          /* killing one */
420                                         if (get_entity_link(ent))
421                                                 --res;
422                                         set_entity_link(ent, ADDRESS_TAKEN);
423                                 } else {
424                                         /* possible found one */
425                                         if (get_entity_link(ent) == NULL)
426                                                 ++res;
427                                         link_all_leave_sels(ent, succ);
428                                 }
429                         }
430                 }
431         }
432
433         return res;
434 }
435
436 /**
437  * Return a path from the Sel node "sel" to its root.
438  *
439  * @param sel  the Sel node
440  * @param len  the length of the path so far
441  */
442 static path_t *find_path(ir_node *sel, size_t len)
443 {
444         size_t pos;
445         int i, n;
446         path_t *res;
447         ir_node *pred = get_Sel_ptr(sel);
448
449         /* the current Sel node will add some path elements */
450         n    = get_Sel_n_indexs(sel);
451         len += n + 1;
452
453         if (! is_Sel(pred)) {
454                 /* we found the root */
455                 res = XMALLOCF(path_t, path, len);
456                 res->path_len = len;
457         } else
458                 res = find_path(pred, len);
459
460         assert(len <= res->path_len);
461         pos = res->path_len - len;
462
463         res->path[pos++].ent = get_Sel_entity(sel);
464         for (i = 0; i < n; ++i) {
465                 ir_node *index = get_Sel_index(sel, i);
466
467                 res->path[pos++].tv = get_Const_tarval(index);
468         }
469         return res;
470 }
471
472
473 /**
474  * Allocate value numbers for the leaves
475  * in our found entities.
476  *
477  * @param sels  a set that will contain all Sels that have a value number
478  * @param ent   the entity that will be scalar replaced
479  * @param vnum  the first value number we can assign
480  * @param modes a flexible array, containing all the modes of
481  *              the value numbers.
482  *
483  * @return the next free value number
484  */
485 static unsigned allocate_value_numbers(pset *sels, ir_entity *ent, unsigned vnum, ir_mode ***modes)
486 {
487         ir_node *sel, *next;
488         path_t *key, *path;
489         set *pathes = new_set(path_cmp, 8);
490
491         DB((dbg, SET_LEVEL_3, "  Visiting Sel nodes of entity %+F\n", ent));
492         /* visit all Sel nodes in the chain of the entity */
493         for (sel = (ir_node*)get_entity_link(ent); sel != NULL; sel = next) {
494                 next = (ir_node*)get_irn_link(sel);
495
496                 /* we must mark this sel for later */
497                 pset_insert_ptr(sels, sel);
498
499                 key  = find_path(sel, 0);
500                 path = set_find(path_t, pathes, key, path_size(key), path_hash(key));
501
502                 if (path) {
503                         set_vnum(sel, path->vnum);
504                         DB((dbg, SET_LEVEL_3, "  %+F represents value %u\n", sel, path->vnum));
505                 } else {
506                         key->vnum = vnum++;
507
508                         (void)set_insert(path_t, pathes, key, path_size(key), path_hash(key));
509
510                         set_vnum(sel, key->vnum);
511                         DB((dbg, SET_LEVEL_3, "  %+F represents value %u\n", sel, key->vnum));
512
513                         ARR_EXTO(ir_mode *, *modes, (key->vnum + 15) & ~15);
514
515                         (*modes)[key->vnum] = get_type_mode(get_entity_type(get_Sel_entity(sel)));
516
517                         assert((*modes)[key->vnum] && "Value is not atomic");
518
519 #ifdef DEBUG_libfirm
520                         /* Debug output */
521                         {
522                                 unsigned i;
523                                 DB((dbg, SET_LEVEL_2, "  %s", get_entity_name(key->path[0].ent)));
524                                 for (i = 1; i < key->path_len; ++i) {
525                                         if (is_entity(key->path[i].ent))
526                                                 DB((dbg, SET_LEVEL_2, ".%s", get_entity_name(key->path[i].ent)));
527                                         else
528                                                 DB((dbg, SET_LEVEL_2, "[%ld]", get_tarval_long(key->path[i].tv)));
529                                 }
530                                 DB((dbg, SET_LEVEL_2, " = %u (%s)\n", PTR_TO_INT(get_irn_link(sel)), get_mode_name((*modes)[key->vnum])));
531                         }
532 #endif /* DEBUG_libfirm */
533                 }
534                 free(key);
535         }
536
537         del_set(pathes);
538         set_entity_link(ent, NULL);
539         return vnum;
540 }
541
542 /**
543  * environment for memory walker
544  */
545 typedef struct env_t {
546         unsigned nvals;      /**< number of values */
547         ir_mode  **modes;    /**< the modes of the values */
548         pset     *sels;      /**< A set of all Sel nodes that have a value number */
549 } env_t;
550
551 /**
552  * topological post-walker.
553  */
554 static void walker(ir_node *node, void *ctx)
555 {
556         env_t    *env = (env_t*)ctx;
557         ir_graph *irg = get_irn_irg(node);
558         ir_node  *addr, *block, *mem, *val;
559         ir_mode  *mode;
560         unsigned vnum;
561
562         if (is_Load(node)) {
563                 /* a load, check if we can resolve it */
564                 addr = get_Load_ptr(node);
565
566                 DB((dbg, SET_LEVEL_3, "  checking %+F for replacement ", node));
567                 if (! is_Sel(addr)) {
568                         DB((dbg, SET_LEVEL_3, "no Sel input (%+F)\n", addr));
569                         return;
570                 }
571
572                 if (! pset_find_ptr(env->sels, addr)) {
573                         DB((dbg, SET_LEVEL_3, "Sel %+F has no VNUM\n", addr));
574                         return;
575                 }
576
577                 /* ok, we have a Load that will be replaced */
578                 vnum = get_vnum(addr);
579                 assert(vnum < env->nvals);
580
581                 DB((dbg, SET_LEVEL_3, "replacing by value %u\n", vnum));
582
583                 block = get_nodes_block(node);
584                 set_cur_block(block);
585
586                 /* check, if we can replace this Load */
587                 val = get_value(vnum, env->modes[vnum]);
588
589                 /* Beware: A Load can contain a hidden conversion in Firm.
590                 This happens for instance in the following code:
591
592                  int i;
593                  unsigned j = *(unsigned *)&i;
594
595                 Handle this here. */
596                 mode = get_Load_mode(node);
597                 if (mode != get_irn_mode(val))
598                         val = new_rd_Conv(get_irn_dbg_info(node), block, val, mode);
599
600                 mem = get_Load_mem(node);
601                 turn_into_tuple(node, pn_Load_max+1);
602                 set_Tuple_pred(node, pn_Load_M,         mem);
603                 set_Tuple_pred(node, pn_Load_res,       val);
604                 set_Tuple_pred(node, pn_Load_X_regular, new_r_Jmp(block));
605                 set_Tuple_pred(node, pn_Load_X_except,  new_r_Bad(irg, mode_X));
606         } else if (is_Store(node)) {
607                 DB((dbg, SET_LEVEL_3, "  checking %+F for replacement ", node));
608
609                 /* a Store always can be replaced */
610                 addr = get_Store_ptr(node);
611
612                 if (! is_Sel(addr)) {
613                         DB((dbg, SET_LEVEL_3, "no Sel input (%+F)\n", addr));
614                         return;
615                 }
616
617                 if (! pset_find_ptr(env->sels, addr)) {
618                         DB((dbg, SET_LEVEL_3, "Sel %+F has no VNUM\n", addr));
619                         return;
620                 }
621
622                 vnum = get_vnum(addr);
623                 assert(vnum < env->nvals);
624
625                 DB((dbg, SET_LEVEL_3, "replacing by value %u\n", vnum));
626
627                 block = get_nodes_block(node);
628                 set_cur_block(block);
629
630                 /* Beware: A Store can contain a hidden conversion in Firm. */
631                 val = get_Store_value(node);
632                 if (get_irn_mode(val) != env->modes[vnum])
633                         val = new_rd_Conv(get_irn_dbg_info(node), block, val, env->modes[vnum]);
634
635                 set_value(vnum, val);
636
637                 mem = get_Store_mem(node);
638                 turn_into_tuple(node, pn_Store_max+1);
639                 set_Tuple_pred(node, pn_Store_M,         mem);
640                 set_Tuple_pred(node, pn_Store_X_regular, new_r_Jmp(block));
641                 set_Tuple_pred(node, pn_Store_X_except,  new_r_Bad(irg, mode_X));
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         int       i;
683         scalars_t key;
684         ir_node   *irg_frame;
685         ir_mode   **modes;
686         set       *set_ent;
687         pset      *sels;
688         ir_type   *ent_type, *frame_tp;
689
690         assure_irg_properties(irg,
691                 IR_GRAPH_PROPERTY_NO_UNREACHABLE_CODE
692                 | IR_GRAPH_PROPERTY_CONSISTENT_OUTS);
693
694         /* we use the link field to store the VNUM */
695         ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
696         irp_reserve_resources(irp, IRP_RESOURCE_ENTITY_LINK);
697
698         /* Find possible scalar replacements */
699         if (find_possible_replacements(irg)) {
700                 DB((dbg, SET_LEVEL_1, "Scalar Replacement: %+F\n", irg));
701
702                 /* Insert in set the scalar replacements. */
703                 irg_frame = get_irg_frame(irg);
704                 nvals     = 0;
705                 modes     = NEW_ARR_F(ir_mode *, 16);
706                 set_ent   = new_set(ent_cmp, 8);
707                 sels      = pset_new_ptr(8);
708                 frame_tp  = get_irg_frame_type(irg);
709
710                 for (i = get_irn_n_outs(irg_frame) - 1; i >= 0; --i) {
711                         ir_node *succ = get_irn_out(irg_frame, i);
712
713                         if (is_Sel(succ)) {
714                                 ir_entity *ent = get_Sel_entity(succ);
715
716                                 /* we are only interested in entities on the frame, NOT
717                                    parameters */
718                                 if (get_entity_owner(ent) != frame_tp
719                                     || is_parameter_entity(ent))
720                                         continue;
721
722                                 if (get_entity_link(ent) == NULL || get_entity_link(ent) == ADDRESS_TAKEN)
723                                         continue;
724
725                                 ent_type = get_entity_type(ent);
726
727                                 key.ent       = ent;
728                                 (void)set_insert(scalars_t, set_ent, &key, sizeof(key), hash_ptr(key.ent));
729
730 #ifdef DEBUG_libfirm
731                                 if (is_Array_type(ent_type)) {
732                                         DB((dbg, SET_LEVEL_1, "  found array %s\n", get_entity_name(ent)));
733                                 } else if (is_Struct_type(ent_type)) {
734                                         DB((dbg, SET_LEVEL_1, "  found struct %s\n", get_entity_name(ent)));
735                                 } else if (is_atomic_type(ent_type))
736                                         DB((dbg, SET_LEVEL_1, "  found atomic value %s\n", get_entity_name(ent)));
737                                 else {
738                                         panic("Neither an array nor a struct or atomic value found in scalar replace");
739                                 }
740 #endif /* DEBUG_libfirm */
741
742                                 nvals = allocate_value_numbers(sels, ent, nvals, &modes);
743                         }
744                 }
745
746                 DB((dbg, SET_LEVEL_1, "  %u values will be needed\n", nvals));
747
748                 /* If scalars were found. */
749                 if (nvals > 0) {
750                         do_scalar_replacements(irg, sels, nvals, modes);
751
752                         foreach_set(set_ent, scalars_t, value) {
753                                 free_entity(value->ent);
754                         }
755
756                         /*
757                          * We changed the graph, but did NOT introduce new blocks
758                          * neither changed control flow, cf-backedges should be still
759                          * consistent.
760                          */
761                 }
762                 del_pset(sels);
763                 del_set(set_ent);
764                 DEL_ARR_F(modes);
765         }
766
767         ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
768         irp_free_resources(irp, IRP_RESOURCE_ENTITY_LINK);
769
770         confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_NONE);
771 }
772
773 ir_graph_pass_t *scalar_replacement_opt_pass(const char *name)
774 {
775         return def_graph_pass(name ? name : "scalar_rep", scalar_replacement_opt);
776 }
777
778 void firm_init_scalar_replace(void)
779 {
780         FIRM_DBG_REGISTER(dbg, "firm.opt.scalar_replace");
781 }