ia32: improve Test peephole optimisation
[libfirm] / ir / be / bespillslots.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       Spillslot coalescer.
23  * @author      Matthias Braun
24  * @date        26.07.2006
25  * @version     $Id$
26  */
27 #include "config.h"
28
29 #include <stdlib.h>
30
31 #include "set.h"
32 #include "array.h"
33 #include "irgwalk.h"
34 #include "ircons.h"
35 #include "irprintf.h"
36 #include "execfreq.h"
37 #include "unionfind.h"
38 #include "irdump_t.h"
39
40 #include "benode.h"
41 #include "besched.h"
42 #include "bespill.h"
43 #include "bespillslots.h"
44 #include "bechordal_t.h"
45 #include "bestatevent.h"
46 #include "bemodule.h"
47 #include "beintlive_t.h"
48 #include "beirg.h"
49 #include "bearch.h"
50
51 #define DBG_COALESCING      1
52 #define DBG_INTERFERENCES   2
53
54 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
55
56 typedef struct spill_t {
57         ir_node       *spill;
58         const ir_mode *mode;      /**< mode of the spilled value */
59         int            alignment; /**< alignment for the spilled value */
60         int            spillslot; /**< index into spillslot_unionfind structure */
61 } spill_t;
62
63 typedef struct affinity_edge_t {
64         double affinity;
65         int    slot1;
66         int    slot2;
67 } affinity_edge_t;
68
69 struct be_fec_env_t {
70         struct obstack         obst;
71         ir_graph              *irg;
72         set                   *spills;
73         ir_node              **reloads;
74         affinity_edge_t      **affinity_edges;
75         set                   *memperms;
76         set_frame_entity_func  set_frame_entity;
77         bool                   at_begin;  /**< frame entities should be allocate at
78                                                the beginning of the stackframe */
79 };
80
81 /** Compare 2 affinity edges (used in quicksort) */
82 static int cmp_affinity(const void *d1, const void *d2)
83 {
84         const affinity_edge_t * const *e1 = (const affinity_edge_t**)d1;
85         const affinity_edge_t * const *e2 = (const affinity_edge_t**)d2;
86
87         /* sort in descending order */
88         return (*e1)->affinity < (*e2)->affinity ? 1 : -1;
89 }
90
91 static int cmp_spill(const void* d1, const void* d2, size_t size)
92 {
93         const spill_t* s1 = (const spill_t*)d1;
94         const spill_t* s2 = (const spill_t*)d2;
95         (void) size;
96
97         return s1->spill != s2->spill;
98 }
99
100 static spill_t *get_spill(be_fec_env_t *env, ir_node *node)
101 {
102         spill_t spill, *res;
103         int hash = hash_irn(node);
104
105         spill.spill = node;
106         res = (spill_t*)set_find(env->spills, &spill, sizeof(spill), hash);
107
108         return res;
109 }
110
111
112 static inline ir_node *get_memory_edge(const ir_node *node)
113 {
114         int i, arity;
115
116         arity = get_irn_arity(node);
117         for (i = arity - 1; i >= 0; --i) {
118                 ir_node *arg = get_irn_n(node, i);
119                 if (get_irn_mode(arg) == mode_M)
120                         return arg;
121         }
122
123         return NULL;
124 }
125
126 static spill_t *collect_spill(be_fec_env_t *env, ir_node *node,
127                                       const ir_mode *mode, int align)
128 {
129         spill_t spill, *res;
130         int     hash = hash_irn(node);
131
132         /* insert into set of spills if not already there */
133         spill.spill = node;
134         res         = (spill_t*)set_find(env->spills, &spill, sizeof(spill), hash);
135
136         if (res == NULL) {
137                 spill.spillslot = set_count(env->spills);
138                 spill.mode      = mode;
139                 spill.alignment = align;
140                 res             = (spill_t*)set_insert(env->spills, &spill, sizeof(spill), hash);
141                 DB((dbg, DBG_COALESCING, "Slot %d: %+F\n", spill.spillslot, node));
142         } else {
143                 assert(res->mode == mode);
144                 assert(res->alignment == align);
145         }
146
147         return res;
148 }
149
150 static spill_t *collect_memphi(be_fec_env_t *env, ir_node *node,
151                                const ir_mode *mode, int align)
152 {
153         int i, arity;
154         spill_t spill, *res;
155         int hash = hash_irn(node);
156         const ir_exec_freq *exec_freq = be_get_irg_exec_freq(env->irg);
157
158         assert(is_Phi(node));
159
160         spill.spill = node;
161         res = (spill_t*)set_find(env->spills, &spill, sizeof(spill), hash);
162         if (res != NULL) {
163                 assert(res->mode == mode);
164                 assert(res->alignment == align);
165                 return res;
166         }
167
168         spill.spillslot = set_count(env->spills);
169         spill.mode      = mode;
170         spill.alignment = align;
171         DB((dbg, DBG_COALESCING, "Slot %d: %+F\n", spill.spillslot, node));
172         res             = (spill_t*)set_insert(env->spills, &spill, sizeof(spill), hash);
173
174         /* collect attached spills and mem-phis */
175         arity = get_irn_arity(node);
176         for (i = 0; i < arity; ++i) {
177                 affinity_edge_t *affinty_edge;
178                 ir_node *arg = get_irn_n(node, i);
179                 spill_t *arg_spill;
180
181                 if (is_Phi(arg)) {
182                         arg_spill = collect_memphi(env, arg, mode, align);
183                 } else {
184                         arg_spill = collect_spill(env, arg, mode, align);
185                 }
186
187                 /* add an affinity edge */
188                 affinty_edge           = OALLOC(&env->obst, affinity_edge_t);
189                 affinty_edge->affinity = get_block_execfreq(exec_freq, get_nodes_block(arg));
190                 affinty_edge->slot1    = res->spillslot;
191                 affinty_edge->slot2    = arg_spill->spillslot;
192                 ARR_APP1(affinity_edge_t*, env->affinity_edges, affinty_edge);
193         }
194
195         return res;
196 }
197
198 void be_node_needs_frame_entity(be_fec_env_t *env, ir_node *node,
199                                 const ir_mode *mode, int align)
200 {
201         ir_node *spillnode = get_memory_edge(node);
202
203         assert(spillnode != NULL);
204
205         /* walk upwards and collect all phis and spills on this way */
206         if (is_Phi(spillnode)) {
207                 collect_memphi(env, spillnode, mode, align);
208         } else {
209                 collect_spill(env, spillnode, mode, align);
210         }
211
212         ARR_APP1(ir_node *, env->reloads, node);
213 }
214
215
216
217 static int merge_interferences(be_fec_env_t *env, bitset_t** interferences,
218                                int* spillslot_unionfind, int s1, int s2)
219 {
220         int res;
221         int i;
222         int spillcount;
223
224         /* merge spillslots and interferences */
225         res = uf_union(spillslot_unionfind, s1, s2);
226         /* we assume that we always merge s2 to s1 so swap s1, s2 if necessary */
227         if (res != s1) {
228                 int t = s1;
229                 s1 = s2;
230                 s2 = t;
231         }
232
233         bitset_or(interferences[s1], interferences[s2]);
234
235         /* update other interferences */
236         spillcount = set_count(env->spills);
237         for (i = 0; i < spillcount; ++i) {
238                 bitset_t *intfs = interferences[i];
239                 if (bitset_is_set(intfs, s2))
240                         bitset_set(intfs, s1);
241         }
242
243         return res;
244 }
245
246 static int my_values_interfere2(ir_graph *irg, const ir_node *a,
247                                 const ir_node *b)
248 {
249         be_lv_t *lv = be_get_irg_liveness(irg);
250
251     int a2b = _value_dominates(a, b);
252     int b2a = _value_dominates(b, a);
253
254     /* If there is no dominance relation, they do not interfere. */
255     if ((a2b | b2a) > 0) {
256         const ir_edge_t *edge;
257         ir_node *bb;
258
259         /*
260          * Adjust a and b so, that a dominates b if
261          * a dominates b or vice versa.
262          */
263         if (b2a) {
264             const ir_node *t = a;
265             a = b;
266             b = t;
267         }
268
269         bb = get_nodes_block(b);
270
271         /*
272          * If a is live end in b's block it is
273          * live at b's definition (a dominates b)
274          */
275         if (be_is_live_end(lv, bb, a))
276             return 1;
277
278         /*
279          * Look at all usages of a.
280          * If there's one usage of a in the block of b, then
281          * we check, if this use is dominated by b, if that's true
282          * a and b interfere. Note that b must strictly dominate the user,
283          * since if b is the last user of in the block, b and a do not
284          * interfere.
285          * Uses of a not in b's block can be disobeyed, because the
286          * check for a being live at the end of b's block is already
287          * performed.
288          */
289         foreach_out_edge(a, edge) {
290             const ir_node *user = get_edge_src_irn(edge);
291                         if (is_Sync(user)) {
292                                 const ir_edge_t *edge2;
293                                 foreach_out_edge(user, edge2) {
294                                         const ir_node *user2 = get_edge_src_irn(edge2);
295                                         assert(!is_Sync(user2));
296                                         if (get_nodes_block(user2) == bb && !is_Phi(user2) &&
297                                            _value_strictly_dominates(b, user2))
298                                                 return 1;
299                                 }
300                         } else {
301                                 if (get_nodes_block(user) == bb && !is_Phi(user) &&
302                                                 _value_strictly_dominates(b, user))
303                 return 1;
304                         }
305         }
306     }
307
308         return 0;
309 }
310
311 /**
312  * same as values_interfere but with special handling for Syncs
313  */
314 static int my_values_interfere(ir_graph *irg, ir_node *a, ir_node *b)
315 {
316         if (is_Sync(a)) {
317                 int i, arity = get_irn_arity(a);
318                 for (i = 0; i < arity; ++i) {
319                         ir_node *in = get_irn_n(a, i);
320                         if (my_values_interfere(irg, in, b))
321                                 return 1;
322                 }
323                 return 0;
324         } else if (is_Sync(b)) {
325                 int i, arity = get_irn_arity(b);
326                 for (i = 0; i < arity; ++i) {
327                         ir_node *in = get_irn_n(b, i);
328                         /* a is not a sync, so no need for my_values_interfere */
329                         if (my_values_interfere2(irg, a, in))
330                                 return 1;
331                 }
332                 return 0;
333         }
334
335         return my_values_interfere2(irg, a, b);
336 }
337
338 /**
339  * A greedy coalescing algorithm for spillslots:
340  *  1. Sort the list of affinity edges
341  *  2. Try to merge slots with affinity edges (most expensive slots first)
342  *  3. Try to merge everything else that is possible
343  */
344 static void do_greedy_coalescing(be_fec_env_t *env)
345 {
346         int spillcount;
347         spill_t **spilllist;
348         spill_t *spill;
349         int i, i2;
350         int affinity_edge_count;
351         bitset_t **interferences;
352         int* spillslot_unionfind;
353         struct obstack data;
354
355         spillcount = set_count(env->spills);
356         if (spillcount == 0)
357                 return;
358
359         obstack_init(&data);
360
361         DB((dbg, DBG_COALESCING, "Coalescing %d spillslots\n", spillcount));
362
363         interferences       = OALLOCN(&data, bitset_t*, spillcount);
364         spillslot_unionfind = OALLOCN(&data, int,       spillcount);
365         spilllist           = OALLOCN(&data, spill_t*,  spillcount);
366
367         uf_init(spillslot_unionfind, spillcount);
368
369         DEBUG_ONLY(
370                 memset(spilllist, 0, spillcount * sizeof(spilllist[0]));
371         )
372
373         i = 0;
374         foreach_set(env->spills, spill_t*, spill) {
375                 assert(spill->spillslot < spillcount);
376                 spilllist[spill->spillslot] = spill;
377                 ++i;
378         }
379
380         for (i = 0; i < spillcount; ++i) {
381                 interferences[i] = bitset_obstack_alloc(&data, spillcount);
382         }
383
384         /* construct interferences */
385         for (i = 0; i < spillcount; ++i) {
386                 ir_node *spill1 = spilllist[i]->spill;
387
388                 if (is_NoMem(spill1))
389                         continue;
390
391                 for (i2 = i+1; i2 < spillcount; ++i2) {
392                         ir_node *spill2 = spilllist[i2]->spill;
393
394                         if (is_NoMem(spill2))
395                                 continue;
396
397                         if (my_values_interfere(env->irg, spill1, spill2)) {
398                                 DB((dbg, DBG_INTERFERENCES,
399                                      "Slot %d and %d interfere\n", i, i2));
400
401                                 bitset_set(interferences[i], i2);
402                                 bitset_set(interferences[i2], i);
403                         }
404                 }
405         }
406
407         /* sort affinity edges */
408         affinity_edge_count = ARR_LEN(env->affinity_edges);
409         qsort(env->affinity_edges, affinity_edge_count,
410               sizeof(env->affinity_edges[0]), cmp_affinity);
411
412         /*dump_interference_graph(env, interferences, "before"); */
413
414         /* try to merge affine nodes */
415         for (i = 0; i < affinity_edge_count; ++i) {
416                 const affinity_edge_t *edge = env->affinity_edges[i];
417                 int s1 = uf_find(spillslot_unionfind, edge->slot1);
418                 int s2 = uf_find(spillslot_unionfind, edge->slot2);
419
420                 /* test if values interfere */
421                 if (bitset_is_set(interferences[s1], s2)) {
422                         assert(bitset_is_set(interferences[s2], s1));
423                         continue;
424                 }
425
426                 DB((dbg, DBG_COALESCING,
427                      "Merging %d and %d because of affinity edge\n", s1, s2));
428
429                 merge_interferences(env, interferences, spillslot_unionfind, s1, s2);
430         }
431
432         /* try to merge as much remaining spillslots as possible */
433         for (i = 0; i < spillcount; ++i) {
434                 int s1 = uf_find(spillslot_unionfind, i);
435                 if (s1 != i)
436                         continue;
437
438                 for (i2 = i+1; i2 < spillcount; ++i2) {
439                         int s2 = uf_find(spillslot_unionfind, i2);
440                         if (s2 != i2)
441                                 continue;
442
443                         /* test if values interfere
444                          * we have to test n1-n2 and n2-n1, because only 1 side gets updated
445                          * when node merging occurs
446                          */
447                         if (bitset_is_set(interferences[s1], s2)) {
448                                 assert(bitset_is_set(interferences[s2], s1));
449                                 continue;
450                         }
451
452                         DB((dbg, DBG_COALESCING,
453                              "Merging %d and %d because it is possible\n", s1, s2));
454
455                         if (merge_interferences(env, interferences, spillslot_unionfind, s1, s2) != 0) {
456                                 /* we can break the loop here, because s2 is the new supernode
457                                  * now and we'll test s2 again later anyway */
458                                 break;
459                         }
460                 }
461         }
462
463         /* assign spillslots to spills */
464         for (i = 0; i < spillcount; ++i) {
465                 spill_t *spill = spilllist[i];
466
467                 spill->spillslot = uf_find(spillslot_unionfind, i);
468         }
469
470         /*dump_interference_graph(env, interferences, "after");*/
471         obstack_free(&data, 0);
472 }
473
474
475
476 typedef struct spill_slot_t {
477         int size;
478         int align;
479         ir_entity *entity;
480 } spill_slot_t;
481
482 typedef struct memperm_entry_t {
483         ir_node* node;
484         int pos;
485         ir_entity *in;
486         ir_entity *out;
487         struct memperm_entry_t *next;
488 } memperm_entry_t;
489
490 typedef struct memperm_t {
491         ir_node *block;
492         int entrycount;
493         memperm_entry_t *entries;
494 } memperm_t;
495
496 static int cmp_memperm(const void* d1, const void* d2, size_t size)
497 {
498         const memperm_t* e1 = (const memperm_t*)d1;
499         const memperm_t* e2 = (const memperm_t*)d2;
500         (void) size;
501
502         return e1->block != e2->block;
503 }
504
505 static memperm_t *get_memperm(be_fec_env_t *env, ir_node *block)
506 {
507         memperm_t entry, *res;
508         int hash;
509
510         entry.block = block;
511         hash        = hash_irn(block);
512
513         res = (memperm_t*)set_find(env->memperms, &entry, sizeof(entry), hash);
514
515         if (res == NULL) {
516                 entry.entrycount = 0;
517                 entry.entries = NULL;
518                 res = (memperm_t*)set_insert(env->memperms, &entry, sizeof(entry), hash);
519         }
520
521         return res;
522 }
523
524 static ir_entity* create_stack_entity(be_fec_env_t *env, spill_slot_t *slot)
525 {
526         ir_graph  *irg   = env->irg;
527         ir_type   *frame = get_irg_frame_type(irg);
528         ir_entity *res   = frame_alloc_area(frame, slot->size, slot->align,
529                                             env->at_begin);
530         slot->entity = res;
531
532         return res;
533 }
534
535 /**
536  * Enlarges a spillslot (if necessary) so that it can carry a value of size
537  * @p othersize and alignment @p otheralign.
538  */
539 static void enlarge_spillslot(spill_slot_t *slot, int otheralign, int othersize)
540 {
541         if (othersize > slot->size) {
542                 slot->size = othersize;
543         }
544         if (otheralign > slot->align) {
545                 if (otheralign % slot->align != 0)
546                         slot->align *= otheralign;
547                 else
548                         slot->align = otheralign;
549         } else if (slot->align % otheralign != 0) {
550                 slot->align *= otheralign;
551         }
552 }
553
554 static void assign_spill_entity(be_fec_env_t *env,
555                                 ir_node *node, ir_entity *entity)
556 {
557         if (is_NoMem(node))
558                 return;
559         if (is_Sync(node)) {
560                 int i, arity;
561
562                 arity = get_irn_arity(node);
563                 for (i = 0; i < arity; ++i) {
564                         ir_node *in = get_irn_n(node, i);
565                         assert(!is_Phi(in));
566
567                         assign_spill_entity(env, in, entity);
568                 }
569                 return;
570         }
571
572         /* beware: we might have Stores with Memory Proj's, ia32 fisttp for
573            instance */
574         node = skip_Proj(node);
575         assert(arch_get_frame_entity(node) == NULL);
576         env->set_frame_entity(node, entity);
577 }
578
579 /**
580  * Create stack entities for the spillslots and assign them to the spill and
581  * reload nodes.
582  */
583 static void assign_spillslots(be_fec_env_t *env)
584 {
585         int           spillcount = set_count(env->spills);
586         spill_slot_t *spillslots = ALLOCANZ(spill_slot_t, spillcount);
587         spill_t      *spill;
588         size_t        i;
589
590         /* construct spillslots */
591         foreach_set(env->spills, spill_t*, spill) {
592                 int slotid = spill->spillslot;
593                 const ir_mode *mode = spill->mode;
594                 spill_slot_t *slot = & (spillslots[slotid]);
595                 int size = get_mode_size_bytes(mode);
596                 int align = spill->alignment;
597
598                 if (slot->align == 0 && slot->size == 0) {
599                         slot->align = align;
600                         slot->size = size;
601                 } else {
602                         enlarge_spillslot(slot, align, size);
603                 }
604         }
605
606         foreach_set(env->spills, spill_t*, spill) {
607                 ir_node      *node   = spill->spill;
608                 int           slotid = spill->spillslot;
609                 spill_slot_t *slot;
610
611                 slot = &spillslots[slotid];
612                 if (slot->entity == NULL) {
613                         create_stack_entity(env, slot);
614                 }
615
616                 if (is_Phi(node)) {
617                         int i, arity;
618                         ir_node *block = get_nodes_block(node);
619
620                         /* should be a PhiM */
621                         assert(get_irn_mode(node) == mode_M);
622
623                         for (i = 0, arity = get_irn_arity(node); i < arity; ++i) {
624                                 ir_node *arg = get_irn_n(node, i);
625                                 ir_node *predblock = get_Block_cfgpred_block(block, i);
626                                 spill_t *argspill;
627                                 int argslotid;
628
629                                 argspill = get_spill(env, arg);
630                                 assert(argspill != NULL);
631
632                                 argslotid = argspill->spillslot;
633                                 if (slotid != argslotid) {
634                                         memperm_t *memperm;
635                                         memperm_entry_t *entry;
636                                         spill_slot_t *argslot = &spillslots[argslotid];
637                                         if (argslot->entity == NULL) {
638                                                 create_stack_entity(env, argslot);
639                                         }
640
641                                         memperm = get_memperm(env, predblock);
642
643                                         entry = OALLOC(&env->obst, memperm_entry_t);
644                                         entry->node = node;
645                                         entry->pos = i;
646                                         entry->in = argslot->entity;
647                                         entry->out = slot->entity;
648                                         entry->next = memperm->entries;
649                                         memperm->entrycount++;
650                                         memperm->entries = entry;
651                                 }
652                         }
653                 } else {
654                         assign_spill_entity(env, node, slot->entity);
655                 }
656         }
657
658         for (i = 0; i < ARR_LEN(env->reloads); ++i) {
659                 ir_node            *reload    = env->reloads[i];
660                 ir_node            *spillnode = get_memory_edge(reload);
661                 spill_t            *spill     = get_spill(env, spillnode);
662                 const spill_slot_t *slot      = & spillslots[spill->spillslot];
663
664                 assert(slot->entity != NULL);
665
666                 env->set_frame_entity(reload, slot->entity);
667         }
668 }
669
670 /**
671  * Returns the last node in a block which is no control flow changing node
672  */
673 static ir_node *get_end_of_block_insertion_point(ir_node* block)
674 {
675         ir_node* ins = sched_last(block);
676         while (is_Proj(ins) && get_irn_mode(ins) == mode_X) {
677                 ins = sched_prev(ins);
678                 assert(ins != NULL);
679         }
680
681         if (is_cfop(ins)) {
682                 for (;;) {
683                         ir_node *prev = sched_prev(ins);
684                         if (!is_cfop(prev))
685                                 break;
686                         ins = prev;
687                 }
688         }
689
690         return ins;
691 }
692
693 static void create_memperms(be_fec_env_t *env)
694 {
695         memperm_t *memperm;
696
697         foreach_set(env->memperms, memperm_t*, memperm) {
698                 ir_node         **nodes = ALLOCAN(ir_node*, memperm->entrycount);
699                 memperm_entry_t  *entry;
700                 ir_node          *blockend;
701                 ir_node          *mempermnode;
702                 int               i;
703
704                 assert(memperm->entrycount > 0);
705
706                 for (entry = memperm->entries, i = 0; entry != NULL; entry = entry->next, ++i) {
707                         ir_node* arg = get_irn_n(entry->node, entry->pos);
708                         nodes[i] = arg;
709                 }
710
711                 mempermnode = be_new_MemPerm(memperm->block, memperm->entrycount,
712                                              nodes);
713
714                 /* insert node into schedule */
715                 blockend = get_end_of_block_insertion_point(memperm->block);
716                 sched_add_before(blockend, mempermnode);
717                 stat_ev_dbl("mem_perm", memperm->entrycount);
718
719                 i = 0;
720                 for (entry = memperm->entries; entry != NULL; entry = entry->next, ++i) {
721                         ir_node *proj;
722                         ir_node* arg = get_irn_n(entry->node, entry->pos);
723
724                         be_set_MemPerm_in_entity(mempermnode, i, entry->in);
725                         be_set_MemPerm_out_entity(mempermnode, i, entry->out);
726                         proj = new_r_Proj(mempermnode, get_irn_mode(arg), i);
727
728                         set_irn_n(entry->node, entry->pos, proj);
729                 }
730         }
731 }
732
733 static int count_spillslots(const be_fec_env_t *env)
734 {
735         const spill_t *spill;
736         int spillcount = set_count(env->spills);
737         bitset_t *counted = bitset_alloca(spillcount);
738         int slotcount;
739
740         slotcount = 0;
741         foreach_set(env->spills, spill_t*, spill) {
742                 int spillslot = spill->spillslot;
743                 if (!bitset_is_set(counted, spillslot)) {
744                         slotcount++;
745                         bitset_set(counted, spillslot);
746                 }
747         }
748
749         return slotcount;
750 }
751
752 be_fec_env_t *be_new_frame_entity_coalescer(ir_graph *irg)
753 {
754         be_fec_env_t *env = XMALLOCZ(be_fec_env_t);
755
756         be_liveness_assure_chk(be_assure_liveness(irg));
757
758         obstack_init(&env->obst);
759         env->irg            = irg;
760         env->spills         = new_set(cmp_spill, 10);
761         env->reloads        = NEW_ARR_F(ir_node*, 0);
762         env->affinity_edges = NEW_ARR_F(affinity_edge_t*, 0);
763         env->memperms       = new_set(cmp_memperm, 10);
764
765         return env;
766 }
767
768 void be_free_frame_entity_coalescer(be_fec_env_t *env)
769 {
770         del_set(env->memperms);
771         DEL_ARR_F(env->reloads);
772         DEL_ARR_F(env->affinity_edges);
773         del_set(env->spills);
774         obstack_free(&env->obst, NULL);
775
776         free(env);
777 }
778
779 void be_assign_entities(be_fec_env_t *env,
780                         set_frame_entity_func set_frame_entity,
781                         bool alloc_entities_at_begin)
782 {
783         env->set_frame_entity = set_frame_entity;
784         env->at_begin         = alloc_entities_at_begin;
785
786         stat_ev_dbl("spillslots", set_count(env->spills));
787
788         if (be_coalesce_spill_slots) {
789                 do_greedy_coalescing(env);
790         }
791
792         stat_ev_dbl("spillslots_after_coalescing", count_spillslots(env));
793
794         assign_spillslots(env);
795
796         create_memperms(env);
797 }
798
799 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_spillslots)
800 void be_init_spillslots(void)
801 {
802         FIRM_DBG_REGISTER(dbg, "firm.be.spillslots");
803 }