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