removed union from register requirements to make static inits easier
[libfirm] / ir / be / benode.c
1 /**
2  * @file   benode.c
3  * @date   17.05.2005
4  * @author Sebastian Hack
5  *
6  * Backend node support.
7  *
8  * This file provdies Perm, Copy, Spill and Reload nodes.
9  *
10  * Copyright (C) 2005 Universitaet Karlsruhe
11  * Released under the GPL
12  */
13
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17
18 #include <stdlib.h>
19
20 #include "obst.h"
21 #include "set.h"
22 #include "pmap.h"
23 #include "util.h"
24 #include "debug.h"
25 #include "fourcc.h"
26
27 #include "irop_t.h"
28 #include "irmode_t.h"
29 #include "irnode_t.h"
30 #include "ircons_t.h"
31 #include "irprintf.h"
32
33 #include "be_t.h"
34 #include "belive_t.h"
35 #include "besched_t.h"
36 #include "benode_t.h"
37
38 #include "beirgmod.h"
39
40 #define DBG_LEVEL 0
41
42 #define BENODE_MAGIC FOURCC('B', 'E', 'N', 'O')
43
44 typedef enum _node_kind_t {
45         node_kind_spill,
46         node_kind_reload,
47         node_kind_perm,
48         node_kind_copy,
49         node_kind_last
50 } node_kind_t;
51
52 typedef struct {
53         node_kind_t kind;
54         const arch_register_class_t *cls;
55         ir_op *op;
56         int n_pos;
57         int *pos;
58 } be_op_t;
59
60 typedef struct {
61         const arch_register_t *reg;
62         arch_register_req_t   req;
63 } be_reg_data_t;
64
65 typedef struct {
66         unsigned      magic;
67         const be_op_t *op;
68         int           n_regs;
69         be_reg_data_t reg_data[1];
70 } be_node_attr_t;
71
72 typedef struct {
73         be_node_attr_t attr;
74         ir_node *spill_ctx;  /**< The node in whose context this spill was introduced. */
75         unsigned offset;     /**< The offset of the memory location the spill writes to
76                                                    in the spill area. */
77 } be_spill_attr_t;
78
79 static int templ_pos_Spill[] = {
80         0
81 };
82
83 static int templ_pos_Reload[] = {
84         -1
85 };
86
87 static int templ_pos_Copy[] = {
88         0, -1
89 };
90
91 static int dump_node(ir_node *irn, FILE *f, dump_reason_t reason);
92
93 static const ir_op_ops be_node_ops = {
94         NULL,
95         NULL,
96         NULL,
97         NULL,
98         NULL,
99         NULL,
100         NULL,
101         NULL,
102         NULL,
103         NULL,
104         NULL,
105         dump_node,
106         NULL
107 };
108
109 static INLINE int is_be_node(const ir_node *irn)
110 {
111         const be_node_attr_t *attr = (const be_node_attr_t *) &irn->attr;
112         return attr->magic == BENODE_MAGIC;
113 }
114
115 static INLINE int is_be_kind(const ir_node *irn, node_kind_t kind)
116 {
117         const be_node_attr_t *a = (const be_node_attr_t *) &irn->attr;
118         return a->magic == BENODE_MAGIC && a->op && a->op->kind == kind;
119 }
120
121 static INLINE void *get_attr_and_check(ir_node *irn, node_kind_t kind)
122 {
123         is_be_kind(irn, kind);
124         return &irn->attr;
125 }
126
127 static be_node_attr_t *init_node_attr(ir_node *irn,
128                                                                           const be_op_t *op,
129                                                                           const arch_register_class_t *cls,
130                                                                           int n_regs)
131
132 {
133         be_node_attr_t *attr = (be_node_attr_t *) &irn->attr;
134         int i;
135
136         attr->magic   = BENODE_MAGIC;
137         attr->n_regs  = n_regs;
138         attr->op      = op;
139
140         for(i = 0; i < n_regs; ++i) {
141                 be_reg_data_t *rd = attr->reg_data + i;
142
143                 rd->reg      = NULL;
144                 rd->req.cls  = cls;
145                 rd->req.type = arch_register_req_type_normal;
146         }
147
148         return attr;
149 }
150
151 #define ARRSIZE(x) (sizeof(x) / sizeof(x[0]))
152
153 static int cmp_op_map(const void *a, const void *b, size_t size)
154 {
155         const be_op_t *x = a;
156         const be_op_t *y = b;
157
158         return !(x->kind == y->kind && x->cls == y->cls);
159 }
160
161 static be_op_t *get_op(const be_node_factory_t *fact,
162                 const arch_register_class_t *cls, node_kind_t kind)
163 {
164         be_op_t templ;
165
166         templ.kind = kind;
167         templ.cls = cls;
168
169         return set_insert(fact->ops, &templ, sizeof(templ),
170                 HASH_PTR(cls) + 7 * kind);
171 }
172
173 ir_node *new_Spill(const be_node_factory_t *factory,
174                 const arch_register_class_t *cls,
175                 ir_graph *irg, ir_node *bl, ir_node *node_to_spill, ir_node *ctx)
176 {
177         be_spill_attr_t *a;
178         ir_node *irn;
179         ir_node *in[1];
180         be_op_t *bop = get_op(factory, cls, node_kind_spill);
181         ir_op *op    = bop->op;
182
183         assert(op && "Spill opcode must be present for this register class");
184         in[0]        = node_to_spill;
185         irn          = new_ir_node(NULL, irg, bl, op, mode_M, 1, in);
186         a            = (be_spill_attr_t *) init_node_attr(irn, bop, cls, 0);
187         a->spill_ctx = ctx;
188         a->offset    = 0;
189
190         return irn;
191 }
192
193 void set_Spill_offset(ir_node *irn, unsigned offset)
194 {
195         be_spill_attr_t *a = (be_spill_attr_t *) &irn->attr;
196         assert(is_be_kind(irn, node_kind_spill));
197         a->offset = offset;
198 }
199
200 static ir_node *find_a_spill_walker(ir_node *irn, unsigned visited_nr)
201 {
202         if(get_irn_visited(irn) < visited_nr) {
203                 set_irn_visited(irn, visited_nr);
204
205                 if(is_Phi(irn)) {
206                         int i, n;
207                         for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
208                                 ir_node *n = find_a_spill_walker(get_irn_n(irn, i), visited_nr);
209                                 if(n != NULL)
210                                         return n;
211                         }
212                 }
213
214                 else if(is_be_kind(irn, node_kind_spill))
215                         return irn;
216         }
217
218         return NULL;
219 }
220
221 ir_node *get_Spill_context(const ir_node *irn) {
222         be_spill_attr_t *a = (be_spill_attr_t *) &irn->attr;
223         assert(is_be_kind(irn, node_kind_spill));
224         return a->spill_ctx;
225 }
226
227 /**
228  * Finds a spill for a reload.
229  * If the reload is directly using the spill, this is simple,
230  * else we perform DFS from the reload (over all PhiMs) and return
231  * the first spill node we find.
232  */
233 static INLINE ir_node *find_a_spill(ir_node *irn)
234 {
235         ir_graph *irg       = get_irn_irg(irn);
236         unsigned visited_nr = get_irg_visited(irg) + 1;
237
238         assert(is_be_kind(irn, node_kind_reload));
239         set_irg_visited(irg, visited_nr);
240         return find_a_spill_walker(irn, visited_nr);
241 }
242
243
244 unsigned get_Spill_offset(ir_node *irn)
245 {
246         be_node_attr_t *a = (be_node_attr_t *) &irn->attr;
247         assert(is_be_node(irn));
248
249         switch(a->op->kind) {
250         case node_kind_reload:
251                 assert(0 && "not yet implemented");
252                 return get_Spill_offset(find_a_spill(irn));
253         case node_kind_spill:
254                 return ((be_spill_attr_t *) a)->offset;
255         default:
256                 assert(0 && "Illegal node kind (spill/reload required)");
257         }
258
259         return 0;
260 }
261
262 ir_node *new_Reload(const be_node_factory_t *factory,
263                 const arch_register_class_t *cls, ir_graph *irg,
264                 ir_node *bl, ir_mode *mode, ir_node *spill_node)
265 {
266         ir_node *irn, *in[1];
267         be_op_t *bop = get_op(factory, cls, node_kind_reload);
268         ir_op *op    = bop->op;
269
270         assert(op && "Reload opcode must be present for this register class");
271         in[0] = spill_node;
272
273         irn  = new_ir_node(NULL, irg, bl, op, mode, 1, in);
274         init_node_attr(irn, bop, cls, 1);
275
276         return irn;
277 }
278
279 ir_node *new_Perm(const be_node_factory_t *factory,
280                 const arch_register_class_t *cls,
281                 ir_graph *irg, ir_node *bl, int arity, ir_node **in)
282 {
283         ir_node *irn;
284         be_op_t *bop = get_op(factory, cls, node_kind_perm);
285         ir_op *op    = bop->op;
286
287         irn  = new_ir_node(NULL, irg, bl, op, mode_T, arity, in);
288         init_node_attr(irn, bop, cls, arity);
289
290         return irn;
291 }
292
293 ir_node *new_Copy(const be_node_factory_t *factory,
294                 const arch_register_class_t *cls,
295                 ir_graph *irg, ir_node *bl, ir_node *in)
296 {
297         ir_node *irn, *ins[1];
298         be_op_t *bop = get_op(factory, cls, node_kind_copy);
299         ir_op *op    = bop->op;
300
301         ins[0] = in;
302
303         irn  = new_ir_node(NULL, irg, bl, op, get_irn_mode(in), 1, ins);
304         init_node_attr(irn, bop, cls, 1);
305
306         return irn;
307 }
308
309 ir_node *be_spill(
310                 const be_node_factory_t *factory,
311                 const arch_env_t *arch_env,
312                 ir_node *irn, ir_node *ctx)
313 {
314         const arch_register_class_t *cls = arch_get_irn_reg_class(arch_env, irn, -1);
315
316         ir_node *bl    = get_nodes_block(irn);
317         ir_graph *irg  = get_irn_irg(bl);
318         ir_node *spill = new_Spill(factory, cls, irg, bl, irn, ctx);
319         ir_node *insert;
320
321         /*
322          * search the right insertion point. a spill of a phi cannot be put
323          * directly after the phi, if there are some phis behind the one which
324          * is spilled.
325          */
326         insert = sched_next(irn);
327         while(is_Phi(insert) && !sched_is_end(insert))
328                 insert = sched_next(insert);
329
330         sched_add_before(insert, spill);
331         return spill;
332 }
333
334 ir_node *be_reload(const be_node_factory_t *factory,
335                                          const arch_env_t *arch_env,
336                                          const arch_register_class_t *cls,
337                                          ir_node *irn, int pos, ir_mode *mode, ir_node *spill)
338 {
339         ir_node *reload;
340
341         ir_node *bl   = get_nodes_block(irn);
342         ir_graph *irg = get_irn_irg(bl);
343
344         assert(be_is_Spill(spill)
345                         || (is_Phi(spill) && get_irn_mode(spill) == mode_M));
346
347         reload = new_Reload(factory, cls, irg, bl, mode, spill);
348
349         set_irn_n(irn, pos, reload);
350         sched_add_before(irn, reload);
351         return reload;
352 }
353
354 /**
355  * If the node is a proj, reset the node to the proj's target and return
356  * the proj number.
357  * @param node The address of a node pointer.
358  * @param def  A default value.
359  * @return     If *node is a Proj, *node is set to the Proj's target and
360  *             the Proj number is returned. Else *node remains the same and @p def
361  *             is returned.
362  */
363 static int redir_proj(const ir_node **node, int def)
364 {
365         const ir_node *n = *node;
366
367         if(is_Proj(n)) {
368                 *node = get_Proj_pred(n);
369                 def = -(get_Proj_proj(n) + 1);
370         }
371
372         return def;
373 }
374
375 static const arch_register_req_t *
376 be_node_get_irn_reg_req(const arch_irn_ops_t *_self,
377                 arch_register_req_t *req, const ir_node *irn, int pos)
378 {
379         /* We cannot get output requirements for tuple nodes. */
380         if(get_irn_mode(irn) == mode_T && pos < 0)
381                 return NULL;
382
383         /*
384          * if we're interested in an output operand (pos < 0), so let's resolve projs.
385          */
386         if(pos < 0)
387                 pos = redir_proj((const ir_node **) &irn, pos);
388
389         if(is_be_node(irn)) {
390                 const be_node_attr_t *a = (const be_node_attr_t *) &irn->attr;
391                 const be_op_t *bo       = a->op;
392                 int i;
393
394                 for(i = 0; i < bo->n_pos; ++i) {
395                         if(pos == bo->pos[i]) {
396
397                                 /* be nodes have no input constraints.
398                                    so return normal register requirements. */
399                                 if(pos >= 0) {
400                                         req->cls = bo->cls;
401                                         req->type = arch_register_req_type_normal;
402                                 }
403
404                                 /*
405                                  * if an output requirement is requested,
406                                  * return the one stored in the node.
407                                  */
408                                 else
409                                         *req = a->reg_data[-pos - 1].req;
410
411                                 return req;
412                         }
413                 }
414         }
415
416         return NULL;
417 }
418
419 void be_set_Perm_out_req(ir_node *irn, int pos, const arch_register_req_t *req)
420 {
421         be_node_attr_t *a = get_attr_and_check(irn, node_kind_perm);
422         assert(pos >= 0 && pos < get_irn_arity(irn) && "position out of range");
423         a->reg_data[pos].req = *req;
424 }
425
426 void
427 be_node_set_irn_reg(const arch_irn_ops_t *_self, ir_node *irn,
428                 const arch_register_t *reg)
429 {
430         int pos;
431         be_op_t *bo;
432         be_node_attr_t *attr;
433         const be_node_factory_t *factory =
434                 container_of(_self, const be_node_factory_t, irn_ops);
435
436         if(get_irn_mode(irn) == mode_T)
437                 return;
438
439         pos = redir_proj((const ir_node **) &irn, -1);
440         bo = pmap_get(factory->irn_op_map, get_irn_op(irn));
441
442         if(!bo)
443                 return;
444
445         attr = (be_node_attr_t *) &irn->attr;
446         attr->reg_data[-pos - 1].reg = reg;
447 }
448
449 const arch_register_t *
450 be_node_get_irn_reg(const arch_irn_ops_t *_self, const ir_node *irn)
451 {
452         int i, pos;
453         be_op_t *bo;
454         const be_node_factory_t *factory =
455                 container_of(_self, const be_node_factory_t, irn_ops);
456
457         if(get_irn_mode(irn) == mode_T)
458                 return NULL;
459
460         pos = redir_proj((const ir_node **) &irn, -1);
461         bo = pmap_get(factory->irn_op_map, get_irn_op(irn));
462
463         if(!bo)
464                 return NULL;
465
466         for(i = 0; i < bo->n_pos; ++i) {
467                 if(bo->pos[i] == pos) {
468                         be_node_attr_t *attr = (be_node_attr_t *) &irn->attr;
469                         return attr->reg_data[-pos - 1].reg;
470                 }
471         }
472
473         return NULL;
474 }
475
476 arch_irn_class_t be_node_classify(const arch_irn_ops_t *_self, const ir_node *irn)
477 {
478         const be_node_factory_t *factory = container_of(_self, const be_node_factory_t, irn_ops);
479
480         be_op_t *bo;
481         int idx;
482
483         idx = redir_proj(&irn, 0);
484         bo = pmap_get(factory->irn_op_map, get_irn_op(irn));
485
486         switch(bo->kind) {
487 #define XXX(a) case node_kind_ ## a: return arch_irn_class_ ## a;
488                 XXX(spill)
489                 XXX(reload)
490                 XXX(perm)
491                 XXX(copy)
492 #undef XXX
493                 default:
494                 return 0;
495         }
496
497         return 0;
498 }
499
500 arch_irn_class_t be_node_get_flags(const arch_irn_ops_t *_self, const ir_node *irn)
501 {
502         return 0;
503 }
504
505 static const arch_irn_ops_t *
506 be_node_get_irn_ops(const arch_irn_handler_t *_self, const ir_node *irn)
507 {
508         be_op_t *bo;
509         const be_node_factory_t *factory =
510                 container_of(_self, const be_node_factory_t, handler);
511
512         redir_proj(&irn, 0);
513         bo = pmap_get(factory->irn_op_map, get_irn_op(irn));
514
515         return bo ? &factory->irn_ops : NULL;
516 }
517
518 const arch_irn_handler_t *be_node_get_irn_handler(const be_node_factory_t *f)
519 {
520         return &f->handler;
521 }
522
523 int be_is_Spill(const ir_node *irn)
524 {
525         return is_be_kind(irn, node_kind_spill);
526 }
527
528 int be_is_Reload(const ir_node *irn)
529 {
530         return is_be_kind(irn, node_kind_reload);
531 }
532
533 int be_is_Copy(const ir_node *irn)
534 {
535         return is_be_kind(irn, node_kind_copy);
536 }
537
538 int be_is_Perm(const ir_node *irn)
539 {
540         return is_be_kind(irn, node_kind_perm);
541 }
542
543 be_node_factory_t *be_node_factory_init(be_node_factory_t *factory, const arch_isa_t *isa)
544 {
545         int i, j, n;
546
547         factory->ops = new_set(cmp_op_map, 64);
548         factory->irn_op_map = pmap_create();
549         obstack_init(&factory->obst);
550
551         factory->handler.get_irn_ops = be_node_get_irn_ops;
552
553         factory->irn_ops.get_irn_reg_req = be_node_get_irn_reg_req;
554         factory->irn_ops.set_irn_reg     = be_node_set_irn_reg;
555         factory->irn_ops.get_irn_reg     = be_node_get_irn_reg;
556         factory->irn_ops.classify        = be_node_classify;
557         factory->irn_ops.get_flags       = be_node_get_flags;
558
559         for(i = 0, n = arch_isa_get_n_reg_class(isa); i < n; ++i) {
560                 const arch_register_class_t *cls = arch_isa_get_reg_class(isa, i);
561                 be_op_t *ent;
562
563                 ent = get_op(factory, cls, node_kind_spill);
564                 ent->op = new_ir_op(get_next_ir_opcode(), "Spill", op_pin_state_pinned,
565                                 0, oparity_unary, 0, sizeof(be_spill_attr_t), &be_node_ops);
566                 ent->n_pos = ARRSIZE(templ_pos_Spill);
567                 ent->pos = templ_pos_Spill;
568                 pmap_insert(factory->irn_op_map, ent->op, ent);
569
570                 ent = get_op(factory, cls, node_kind_reload);
571                 ent->op = new_ir_op(get_next_ir_opcode(), "Reload", op_pin_state_pinned, 0,
572                                 oparity_unary, 0, sizeof(be_node_attr_t), &be_node_ops);
573                 ent->n_pos = ARRSIZE(templ_pos_Reload);
574                 ent->pos = templ_pos_Reload;
575                 pmap_insert(factory->irn_op_map, ent->op, ent);
576
577                 ent = get_op(factory, cls, node_kind_copy);
578                 ent->op = new_ir_op(get_next_ir_opcode(), "Copy", op_pin_state_pinned, 0,
579                                 oparity_unary, 0, sizeof(be_node_attr_t), &be_node_ops);
580                 ent->n_pos = ARRSIZE(templ_pos_Copy);
581                 ent->pos = templ_pos_Copy;
582                 pmap_insert(factory->irn_op_map, ent->op, ent);
583
584                 ent = get_op(factory, cls, node_kind_perm);
585                 ent->op = new_ir_op(get_next_ir_opcode(), "Perm", op_pin_state_pinned, 0,
586                                 oparity_variable, 0,
587                                 sizeof(be_node_attr_t)
588                                 + sizeof(be_reg_data_t) * cls->n_regs, &be_node_ops);
589                 ent->n_pos = 2 * cls->n_regs;
590                 ent->pos = obstack_alloc(&factory->obst, sizeof(ent->pos[0]) * ent->n_pos);
591                 for(j = 0; j < ent->n_pos; j += 2) {
592                         int k = j / 2;
593                         ent->pos[j] = k;
594                         ent->pos[j + 1] = -(k + 1);
595                 }
596                 pmap_insert(factory->irn_op_map, ent->op, ent);
597
598         }
599
600         return factory;
601 }
602
603 static int dump_node(ir_node *irn, FILE *f, dump_reason_t reason)
604 {
605         be_node_attr_t *at = (be_node_attr_t *) &irn->attr;
606         const be_op_t *bo;
607         int i;
608
609         assert(is_be_node(irn));
610         bo = at->op;
611
612         switch(reason) {
613                 case dump_node_opcode_txt:
614                         fprintf(f, get_op_name(bo->op));
615                         break;
616                 case dump_node_mode_txt:
617                         fprintf(f, get_mode_name(get_irn_mode(irn)));
618                         break;
619                 case dump_node_nodeattr_txt:
620                         fprintf(f, "%s ", bo->cls->name);
621                         break;
622                 case dump_node_info_txt:
623                         for(i = 0; i < at->n_regs; ++i) {
624                                 const arch_register_t *reg = at->reg_data[i].reg;
625                                 fprintf(f, "reg #%d: %s\n", i, reg ? reg->name : "n/a");
626                         }
627
628                         if(bo->kind == node_kind_spill) {
629                                 be_spill_attr_t *a = (be_spill_attr_t *) at;
630                                 ir_fprintf(f, "spill context: %+F\n", a->spill_ctx);
631                         }
632                         break;
633         }
634
635         return 0;
636 }
637
638 ir_node *insert_Perm_after(const be_main_env_t *env,
639                                                          const arch_register_class_t *cls,
640                                                          dom_front_info_t *dom_front,
641                                                          ir_node *pos)
642 {
643         const arch_env_t *arch_env  = env->arch_env;
644         ir_node *bl                 = is_Block(pos) ? pos : get_nodes_block(pos);
645         ir_graph *irg               = get_irn_irg(bl);
646         pset *live                  = pset_new_ptr_default();
647         firm_dbg_module_t *dbg      = firm_dbg_register("be.node");
648
649         irn_live_t *li;
650         ir_node *curr, *irn, *perm, **nodes;
651         int i, n;
652
653         DBG((dbg, LEVEL_1, "Insert Perm after: %+F\n", pos));
654
655
656         live_foreach(bl, li) {
657                 ir_node *irn = (ir_node *) li->irn;
658                 if(live_is_end(li) && arch_irn_has_reg_class(arch_env, irn, -1, cls))
659                         pset_insert_ptr(live, irn);
660         }
661
662         sched_foreach_reverse(bl, irn) {
663                 ir_node *x;
664
665         /*
666          * If we encounter the node we want to insert the Perm after,
667          * exit immediately, so that this node is still live
668          */
669                 if(irn == pos)
670                         break;
671
672                 DBG((dbg, LEVEL_1, "%+F\n", irn));
673                 for(x = pset_first(live); x; x = pset_next(live))
674                         DBG((dbg, LEVEL_1, "\tlive: %+F\n", x));
675
676                 if(arch_irn_has_reg_class(arch_env, irn, -1, cls))
677                         pset_remove_ptr(live, irn);
678
679                 for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
680                         ir_node *op = get_irn_n(irn, i);
681
682                         if(arch_irn_has_reg_class(arch_env, op, -1, cls))
683                                 pset_insert_ptr(live, op);
684                 }
685         }
686
687         n = pset_count(live);
688         nodes = malloc(n * sizeof(nodes[0]));
689
690         DBG((dbg, LEVEL_1, "live:\n"));
691         for(irn = pset_first(live), i = 0; irn; irn = pset_next(live), i++) {
692                 DBG((dbg, LEVEL_1, "\t%+F\n", irn));
693                 nodes[i] = irn;
694         }
695
696         perm = new_Perm(env->node_factory, cls, irg, bl, n, nodes);
697         sched_add_after(pos, perm);
698         free(nodes);
699
700         curr = perm;
701         for(i = 0; i < n; ++i) {
702                 ir_node *copies[1];
703                 ir_node *perm_op = get_irn_n(perm, i);
704                 const arch_register_t *reg = arch_get_irn_register(arch_env, perm_op);
705
706                 ir_mode *mode = get_irn_mode(perm_op);
707                 ir_node *proj = new_r_Proj(irg, bl, perm, mode, i);
708                 arch_set_irn_register(arch_env, proj, reg);
709
710                 sched_add_after(curr, proj);
711                 curr = proj;
712
713                 copies[0] = proj;
714                 be_introduce_copies(dom_front, perm_op, array_size(copies), copies);
715         }
716         return perm;
717 }