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