46b712896a4e4e0272e9a3b019d9af455a72a6b5
[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 #include "bitfiddle.h"
27
28 #include "irop_t.h"
29 #include "irmode_t.h"
30 #include "irnode_t.h"
31 #include "ircons_t.h"
32 #include "irprintf.h"
33
34 #include "be_t.h"
35 #include "belive_t.h"
36 #include "besched_t.h"
37 #include "benode_t.h"
38
39 #include "beirgmod.h"
40
41 /* Sometimes we want to put const nodes into get_irn_generic_attr ... */
42 #define get_irn_attr(irn) get_irn_generic_attr((ir_node *) (irn))
43
44 static unsigned be_node_tag = FOURCC('B', 'E', 'N', 'O');
45
46 typedef enum _node_kind_t {
47         node_kind_spill,
48         node_kind_reload,
49         node_kind_perm,
50         node_kind_copy,
51         node_kind_kill,
52         node_kind_last
53 } node_kind_t;
54
55 typedef struct {
56         node_kind_t kind;
57         const arch_register_class_t *cls;
58         ir_op *op;
59         int n_pos;
60         int *pos;
61 } be_op_t;
62
63 typedef enum {
64         be_req_kind_old_limited,
65         be_req_kind_negate_old_limited,
66         be_req_kind_single_reg
67 } be_req_kind_t;
68
69 typedef struct {
70         arch_register_req_t req;
71         be_req_kind_t       kind;
72         arch_irn_flags_t    flags;
73         union {
74                 struct {
75                         void (*old_limited)(void *ptr, bitset_t *bs);
76                         void *old_limited_env;
77                 } old_limited;
78
79                 const arch_register_t *single_reg;
80         } x;
81 } be_req_t;
82
83 typedef struct {
84         const arch_register_t *reg;
85         be_req_t              req;
86         be_req_t              in_req;
87 } be_reg_data_t;
88
89 typedef struct {
90         int                         max_reg_data;
91         const arch_register_class_t *cls;
92         be_reg_data_t               *reg_data;
93 } be_node_attr_t;
94
95 typedef struct {
96         be_node_attr_t node_attr;
97         ir_node *spill_ctx;  /**< The node in whose context this spill was introduced. */
98         entity *ent;     /**< The entity in the stack frame the spill writes to. */
99 } be_spill_attr_t;
100
101 typedef struct {
102         be_node_attr_t node_attr;
103         int offset;           /**< The offset by which the stack shall be increased/decreased. */
104         be_stack_dir_t dir;   /**< The direction in which the stack shall be modified (along or in the other direction). */
105 } be_stack_attr_t;
106
107 static ir_op *op_Spill;
108 static ir_op *op_Reload;
109 static ir_op *op_Perm;
110 static ir_op *op_Copy;
111 static ir_op *op_Keep;
112 static ir_op *op_Call;
113 static ir_op *op_Return;
114 static ir_op *op_IncSP;
115 static ir_op *op_AddSP;
116 static ir_op *op_RegParams;
117 static ir_op *op_StackParam;
118 static ir_op *op_NoReg;
119
120 static int beo_base = -1;
121
122 static const ir_op_ops be_node_op_ops;
123
124 #define N   irop_flag_none
125 #define L   irop_flag_labeled
126 #define C   irop_flag_commutative
127 #define X   irop_flag_cfopcode
128 #define I   irop_flag_ip_cfopcode
129 #define F   irop_flag_fragile
130 #define Y   irop_flag_forking
131 #define H   irop_flag_highlevel
132 #define c   irop_flag_constlike
133 #define K   irop_flag_keep
134
135 void be_node_init(void) {
136         static int inited = 0;
137
138         if(inited)
139                 return;
140
141         inited = 1;
142
143         /* Acquire all needed opcodes. */
144         beo_base = get_next_ir_opcodes(beo_Last - 1);
145
146         op_Spill      = new_ir_op(beo_base + beo_Spill,      "Spill",      op_pin_state_mem_pinned, N, oparity_unary,    0, sizeof(be_spill_attr_t), &be_node_op_ops);
147         op_Reload     = new_ir_op(beo_base + beo_Reload,     "Reload",     op_pin_state_mem_pinned, N, oparity_zero,     0, sizeof(be_node_attr_t),  &be_node_op_ops);
148         op_Perm       = new_ir_op(beo_base + beo_Perm,       "Perm",       op_pin_state_pinned,     N, oparity_variable, 0, sizeof(be_node_attr_t),  &be_node_op_ops);
149         op_Copy       = new_ir_op(beo_base + beo_Copy,       "Copy",       op_pin_state_floats,     N, oparity_unary,    0, sizeof(be_node_attr_t),  &be_node_op_ops);
150         op_Keep       = new_ir_op(beo_base + beo_Keep,       "Keep",       op_pin_state_pinned,     K, oparity_variable, 0, sizeof(be_node_attr_t),  &be_node_op_ops);
151         op_NoReg      = new_ir_op(beo_base + beo_NoReg,      "NoReg",      op_pin_state_floats,     N, oparity_zero,     0, sizeof(be_node_attr_t),  &be_node_op_ops);
152         op_Call       = new_ir_op(beo_base + beo_Call,       "Call",       op_pin_state_pinned,     N, oparity_variable, 0, sizeof(be_node_attr_t),  &be_node_op_ops);
153         op_Return     = new_ir_op(beo_base + beo_Return,     "Return",     op_pin_state_pinned,     X, oparity_variable, 0, sizeof(be_node_attr_t),  &be_node_op_ops);
154         op_AddSP      = new_ir_op(beo_base + beo_AddSP,      "AddSP",      op_pin_state_pinned,     N, oparity_unary,    0, sizeof(be_stack_attr_t), &be_node_op_ops);
155         op_IncSP      = new_ir_op(beo_base + beo_IncSP,      "IncSP",      op_pin_state_pinned,     N, oparity_binary,   0, sizeof(be_stack_attr_t), &be_node_op_ops);
156         op_RegParams  = new_ir_op(beo_base + beo_RegParams,  "RegParams",  op_pin_state_pinned,     N, oparity_zero,     0, sizeof(be_node_attr_t),  &be_node_op_ops);
157         op_StackParam = new_ir_op(beo_base + beo_StackParam, "StackParam", op_pin_state_pinned,     N, oparity_unary,    0, sizeof(be_stack_attr_t), &be_node_op_ops);
158
159         set_op_tag(op_Spill,      &be_node_tag);
160         set_op_tag(op_Reload,     &be_node_tag);
161         set_op_tag(op_Perm,       &be_node_tag);
162         set_op_tag(op_Copy,       &be_node_tag);
163         set_op_tag(op_Keep,       &be_node_tag);
164         set_op_tag(op_NoReg,      &be_node_tag);
165         set_op_tag(op_Call,       &be_node_tag);
166         set_op_tag(op_Return,     &be_node_tag);
167         set_op_tag(op_AddSP,      &be_node_tag);
168         set_op_tag(op_IncSP,      &be_node_tag);
169         set_op_tag(op_RegParams,  &be_node_tag);
170         set_op_tag(op_StackParam, &be_node_tag);
171 }
172
173 static void *init_node_attr(ir_node* irn, const arch_register_class_t *cls, ir_graph *irg, int max_reg_data)
174 {
175         be_node_attr_t *a = get_irn_attr(irn);
176
177         a->max_reg_data = max_reg_data;
178         a->cls          = cls;
179         a->reg_data     = NULL;
180
181         if(max_reg_data > 0) {
182                 int i;
183
184                 a->reg_data = NEW_ARR_D(be_reg_data_t, get_irg_obstack(irg), max_reg_data);
185                 memset(a->reg_data, 0, max_reg_data * sizeof(a->reg_data[0]));
186                 for(i = 0; i < max_reg_data; ++i) {
187                         a->reg_data[i].req.req.cls  = cls;
188                         a->reg_data[i].req.req.type = arch_register_req_type_normal;
189                 }
190         }
191
192         return a;
193 }
194
195 static INLINE int is_be_node(const ir_node *irn)
196 {
197         return get_op_tag(get_irn_op(irn)) == &be_node_tag;
198 }
199
200 be_opcode_t be_get_irn_opcode(const ir_node *irn)
201 {
202         return is_be_node(irn) ? get_irn_opcode(irn) - beo_base : beo_NoBeOp;
203 }
204
205 static int redir_proj(const ir_node **node, int pos)
206 {
207         const ir_node *n = *node;
208
209         if(is_Proj(n)) {
210                 assert(pos == -1 && "Illegal pos for a Proj");
211                 *node = get_Proj_pred(n);
212                 return get_Proj_proj(n);
213         }
214
215         return 0;
216 }
217
218 static void
219 be_node_set_irn_reg(const void *_self, ir_node *irn, const arch_register_t *reg)
220 {
221         int out_pos;
222         be_node_attr_t *a;
223
224         out_pos = redir_proj((const ir_node **) &irn, -1);
225         a       = get_irn_attr(irn);
226
227         assert(is_be_node(irn));
228         assert(out_pos < a->max_reg_data && "position too high");
229         a->reg_data[out_pos].reg = reg;
230 }
231
232
233 ir_node *be_new_Spill(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, ir_node *to_spill, ir_node *ctx)
234 {
235         be_spill_attr_t *a;
236         ir_node *in[1];
237         ir_node *res;
238
239         in[0] = to_spill;
240         res   = new_ir_node(NULL, irg, bl, op_Spill, mode_M, 1, in);
241         a     = init_node_attr(res, cls, irg, 0);
242         a->ent       = NULL;
243         a->spill_ctx = ctx;
244         return res;
245 }
246
247 ir_node *be_new_Reload(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, ir_mode *mode, ir_node *mem)
248 {
249         ir_node *in[1];
250         ir_node *res;
251
252         in[0] = mem;
253         res   = new_ir_node(NULL, irg, bl, op_Reload, mode, 1, in);
254         init_node_attr(res, cls, irg, 1);
255         return res;
256 }
257
258 ir_node *be_new_Perm(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, int n, ir_node *in[])
259 {
260         ir_node *irn = new_ir_node(NULL, irg, bl, op_Perm, mode_T, n, in);
261         init_node_attr(irn, cls, irg, n);
262         return irn;
263 }
264
265 ir_node *be_new_Copy(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, ir_node *op)
266 {
267         ir_node *in[1];
268         ir_node *res;
269
270         in[0] = op;
271         res   = new_ir_node(NULL, irg, bl, op_Copy, get_irn_mode(op), 1, in);
272         init_node_attr(res, cls, irg, 1);
273         return res;
274 }
275
276 ir_node *be_new_Keep(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, int n, ir_node *in[])
277 {
278         ir_node *irn;
279
280         irn = new_ir_node(NULL, irg, bl, op_Keep, mode_ANY, n, in);
281         init_node_attr(irn, cls, irg, 0);
282         keep_alive(irn);
283         return irn;
284 }
285
286 ir_node *be_new_Call(ir_graph *irg, ir_node *bl, ir_node *mem, ir_node *sp, ir_node *ptr, int n_outs, int n, ir_node *in[])
287 {
288         int real_n = 3 + n;
289         ir_node *irn;
290         ir_node **real_in;
291
292         real_in = malloc(sizeof(real_in[0]) * (real_n));
293
294         real_in[0] = mem;
295         real_in[1] = sp;
296         real_in[2] = ptr;
297         memcpy(&real_in[3], in, n * sizeof(in[0]));
298
299         irn = new_ir_node(NULL, irg, bl, op_Call, mode_T, real_n, real_in);
300         init_node_attr(irn, NULL, irg, (n_outs > real_n ? n_outs : real_n));
301         return irn;
302 }
303
304 ir_node *be_new_Return(ir_graph *irg, ir_node *bl, int n, ir_node *in[])
305 {
306         ir_node *irn = new_ir_node(NULL, irg, bl, op_Return, mode_X, n, in);
307         init_node_attr(irn, NULL, irg, n);
308
309         return irn;
310 }
311
312 ir_node *be_new_IncSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl, ir_node *old_sp, ir_node *mem, unsigned offset, be_stack_dir_t dir)
313 {
314         be_stack_attr_t *a;
315         ir_node *irn;
316         ir_node *in[1];
317
318         in[0]     = old_sp;
319         in[1]     = mem;
320         irn       = new_ir_node(NULL, irg, bl, op_IncSP, sp->reg_class->mode, 2, in);
321         a         = init_node_attr(irn, sp->reg_class, irg, 1);
322         a->dir    = dir;
323         a->offset = offset;
324
325         be_node_set_flags(irn, -1, arch_irn_flags_ignore);
326
327         /* Set output constraint to stack register. */
328         be_set_constr_single_reg(irn, -1, sp);
329         be_node_set_irn_reg(NULL, irn, sp);
330
331         return irn;
332 }
333
334 ir_node *be_new_AddSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl, ir_node *old_sp, ir_node *op)
335 {
336         be_node_attr_t *a;
337         ir_node *irn;
338         ir_node *in[2];
339
340         in[0]    = old_sp;
341         in[1]    = op;
342         irn      = new_ir_node(NULL, irg, bl, op_AddSP, sp->reg_class->mode, 2, in);
343         a        = init_node_attr(irn, sp->reg_class, irg, 1);
344
345         be_node_set_flags(irn, -1, arch_irn_flags_ignore);
346
347         /* Set output constraint to stack register. */
348         be_set_constr_single_reg(irn, -1, sp);
349         be_node_set_irn_reg(NULL, irn, sp);
350
351         return irn;
352 }
353
354 ir_node *be_new_NoReg(const arch_register_t *reg, ir_graph *irg, ir_node *bl)
355 {
356         be_node_attr_t *a;
357         ir_node *irn;
358         ir_node *in[1];
359
360         irn = new_ir_node(NULL, irg, bl, op_NoReg, reg->reg_class->mode, 0, in);
361         a   = init_node_attr(irn, reg->reg_class, irg, 1);
362         be_node_set_flags(irn, -1, arch_irn_flags_ignore);
363         be_set_constr_single_reg(irn, -1, reg);
364         be_node_set_irn_reg(NULL, irn, reg);
365         return irn;
366 }
367
368 ir_node *be_new_StackParam(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, ir_mode *mode, ir_node *frame_pointer, unsigned offset)
369 {
370         be_stack_attr_t *a;
371         ir_node *irn;
372         ir_node *in[1];
373
374         in[0] = frame_pointer;
375         irn = new_ir_node(NULL, irg, bl, op_StackParam, mode, 1, in);
376         a = init_node_attr(irn, cls, irg, 1);
377         a->offset = offset;
378         return irn;
379 }
380
381 ir_node *be_new_RegParams(ir_graph *irg, ir_node *bl, int n_outs)
382 {
383         ir_node *irn;
384         ir_node *in[1];
385
386         irn = new_ir_node(NULL, irg, bl, op_RegParams, mode_T, 0, in);
387         init_node_attr(irn, NULL, irg, n_outs);
388         return irn;
389 }
390
391 int be_is_Spill         (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Spill          ; }
392 int be_is_Reload        (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Reload         ; }
393 int be_is_Copy          (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Copy           ; }
394 int be_is_Perm          (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Perm           ; }
395 int be_is_Keep          (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Keep           ; }
396 int be_is_Call          (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Call           ; }
397 int be_is_Return        (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_Return         ; }
398 int be_is_IncSP         (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_IncSP          ; }
399 int be_is_AddSP         (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_AddSP          ; }
400 int be_is_RegParams     (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_RegParams      ; }
401 int be_is_StackParam    (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_StackParam     ; }
402 int be_is_NoReg         (const ir_node *irn) { return be_get_irn_opcode(irn) == beo_NoReg          ; }
403
404 static void be_limited(void *data, bitset_t *bs)
405 {
406         be_req_t *req = data;
407
408         switch(req->kind) {
409         case be_req_kind_negate_old_limited:
410         case be_req_kind_old_limited:
411                 req->x.old_limited.old_limited(req->x.old_limited.old_limited_env, bs);
412                 if(req->kind == be_req_kind_negate_old_limited)
413                         bitset_flip_all(bs);
414                 break;
415         case be_req_kind_single_reg:
416                 bitset_clear_all(bs);
417                 bitset_set(bs, req->x.single_reg->index);
418                 break;
419         }
420 }
421
422 static INLINE be_req_t *get_req(ir_node *irn, int pos)
423 {
424         int idx           = pos < 0 ? -(pos + 1) : pos;
425         be_node_attr_t *a = get_irn_attr(irn);
426         be_reg_data_t *rd = &a->reg_data[idx];
427         be_req_t       *r = pos < 0 ? &rd->req : &rd->in_req;
428
429         assert(is_be_node(irn));
430         assert(!(pos >= 0) || pos < get_irn_arity(irn));
431         assert(!(pos < 0)  || -(pos + 1) <= a->max_reg_data);
432
433         return r;
434 }
435
436 void be_set_constr_single_reg(ir_node *irn, int pos, const arch_register_t *reg)
437 {
438         be_req_t *r = get_req(irn, pos);
439
440         r->kind            = be_req_kind_single_reg;
441         r->x.single_reg    = reg;
442         r->req.limited     = be_limited;
443         r->req.limited_env = r;
444         r->req.type        = arch_register_req_type_limited;
445         r->req.cls         = reg->reg_class;
446 }
447
448 void be_set_constr_limited(ir_node *irn, int pos, const arch_register_req_t *req)
449 {
450         be_req_t *r = get_req(irn, pos);
451
452         assert(arch_register_req_is(req, limited));
453
454         r->kind            = be_req_kind_old_limited;
455         r->req.limited     = be_limited;
456         r->req.limited_env = r;
457         r->req.type        = arch_register_req_type_limited;
458         r->req.cls         = req->cls;
459
460         r->x.old_limited.old_limited     = req->limited;
461         r->x.old_limited.old_limited_env = req->limited_env;
462 }
463
464 void be_node_set_flags(ir_node *irn, int pos, arch_irn_flags_t flags)
465 {
466         be_req_t *r = get_req(irn, pos);
467         r->flags = flags;
468 }
469
470 void be_node_set_reg_class(ir_node *irn, int pos, const arch_register_class_t *cls)
471 {
472         be_req_t *r = get_req(irn, pos);
473         r->req.cls = cls;
474 }
475
476 void be_set_IncSP_offset(ir_node *irn, unsigned offset)
477 {
478         be_stack_attr_t *a = get_irn_attr(irn);
479         assert(be_is_IncSP(irn));
480         a->offset = offset;
481 }
482
483 unsigned be_get_IncSP_offset(ir_node *irn)
484 {
485         be_stack_attr_t *a = get_irn_attr(irn);
486         assert(be_is_IncSP(irn));
487         return a->offset;
488 }
489
490 void be_set_IncSP_direction(ir_node *irn, be_stack_dir_t dir)
491 {
492         be_stack_attr_t *a = get_irn_attr(irn);
493         assert(be_is_IncSP(irn));
494         a->dir = dir;
495 }
496
497 be_stack_dir_t be_get_IncSP_direction(ir_node *irn)
498 {
499         be_stack_attr_t *a = get_irn_attr(irn);
500         assert(be_is_IncSP(irn));
501         return a->dir;
502 }
503
504 void be_set_Spill_entity(ir_node *irn, entity *ent)
505 {
506         be_spill_attr_t *a = get_irn_attr(irn);
507         assert(be_is_Spill(irn));
508         a->ent = ent;
509 }
510
511 static ir_node *find_a_spill_walker(ir_node *irn, unsigned visited_nr)
512 {
513         if(get_irn_visited(irn) < visited_nr) {
514                 set_irn_visited(irn, visited_nr);
515
516                 if(is_Phi(irn)) {
517                         int i, n;
518                         for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
519                                 ir_node *n = find_a_spill_walker(get_irn_n(irn, i), visited_nr);
520                                 if(n != NULL)
521                                         return n;
522                         }
523                 }
524
525                 else if(be_get_irn_opcode(irn) == beo_Spill)
526                         return irn;
527         }
528
529         return NULL;
530 }
531
532 ir_node *be_get_Spill_context(const ir_node *irn) {
533         const be_spill_attr_t *a = get_irn_attr(irn);
534         assert(be_is_Spill(irn));
535         return a->spill_ctx;
536 }
537
538 /**
539  * Finds a spill for a reload.
540  * If the reload is directly using the spill, this is simple,
541  * else we perform DFS from the reload (over all PhiMs) and return
542  * the first spill node we find.
543  */
544 static INLINE ir_node *find_a_spill(ir_node *irn)
545 {
546         ir_graph *irg       = get_irn_irg(irn);
547         unsigned visited_nr = get_irg_visited(irg) + 1;
548
549         assert(be_is_Reload(irn));
550         set_irg_visited(irg, visited_nr);
551         return find_a_spill_walker(irn, visited_nr);
552 }
553
554 entity *be_get_spill_entity(ir_node *irn)
555 {
556         int opc           = get_irn_opcode(irn);
557
558         switch(be_get_irn_opcode(irn)) {
559         case beo_Reload:
560                 return be_get_spill_entity(find_a_spill(irn));
561         case beo_Spill:
562                 {
563                         be_spill_attr_t *a = get_irn_attr(irn);
564                         return a->ent;
565                 }
566         default:
567                 assert(0 && "Must give spill/reload node");
568         }
569
570         return NULL;
571 }
572
573 ir_node *be_spill(const arch_env_t *arch_env, ir_node *irn, ir_node *ctx)
574 {
575         const arch_register_class_t *cls = arch_get_irn_reg_class(arch_env, irn, -1);
576
577         ir_node *bl    = get_nodes_block(irn);
578         ir_graph *irg  = get_irn_irg(bl);
579         ir_node *spill = be_new_Spill(cls, irg, bl, irn, ctx);
580         ir_node *insert;
581
582         /*
583          * search the right insertion point. a spill of a phi cannot be put
584          * directly after the phi, if there are some phis behind the one which
585          * is spilled.
586          */
587         insert = sched_next(irn);
588         while(is_Phi(insert) && !sched_is_end(insert))
589                 insert = sched_next(insert);
590
591         sched_add_before(insert, spill);
592         return spill;
593 }
594
595 ir_node *be_reload(const arch_env_t *arch_env,
596                                    const arch_register_class_t *cls,
597                                    ir_node *irn, int pos, ir_mode *mode, ir_node *spill)
598 {
599         ir_node *reload;
600
601         ir_node *bl   = get_nodes_block(irn);
602         ir_graph *irg = get_irn_irg(bl);
603
604         assert(be_is_Spill(spill) || (is_Phi(spill) && get_irn_mode(spill) == mode_M));
605
606         reload = be_new_Reload(cls, irg, bl, mode, spill);
607
608         set_irn_n(irn, pos, reload);
609         sched_add_before(irn, reload);
610         return reload;
611 }
612
613 static void *put_out_reg_req(arch_register_req_t *req, const ir_node *irn, int out_pos)
614 {
615         const be_node_attr_t *a = get_irn_attr(irn);
616
617         if(out_pos < a->max_reg_data)
618                 memcpy(req, &a->reg_data[out_pos].req, sizeof(req[0]));
619         else {
620                 req->type = arch_register_req_type_none;
621                 req->cls  = NULL;
622         }
623
624         return req;
625 }
626
627 static void *put_in_reg_req(arch_register_req_t *req, const ir_node *irn, int pos)
628 {
629         const be_node_attr_t *a = get_irn_attr(irn);
630         int n                   = get_irn_arity(irn);
631
632         if(pos < get_irn_arity(irn) && pos < a->max_reg_data)
633                 memcpy(req, &a->reg_data[pos].in_req, sizeof(req[0]));
634         else {
635                 req->type = arch_register_req_type_none;
636                 req->cls  = NULL;
637         }
638
639         return req;
640 }
641
642 static const arch_register_req_t *
643 be_node_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos)
644 {
645         int out_pos = pos;
646
647         if(pos < 0) {
648                 if(get_irn_mode(irn) == mode_T)
649                         return NULL;
650
651                 out_pos = redir_proj((const ir_node **) &irn, pos);
652                 assert(is_be_node(irn));
653                 return put_out_reg_req(req, irn, out_pos);
654         }
655
656         else {
657                 return is_be_node(irn) ? put_in_reg_req(req, irn, pos) : NULL;
658         }
659
660         return req;
661 }
662
663 const arch_register_t *
664 be_node_get_irn_reg(const void *_self, const ir_node *irn)
665 {
666         int out_pos;
667         be_node_attr_t *a;
668
669         out_pos = redir_proj((const ir_node **) &irn, -1);
670         a       = get_irn_attr(irn);
671
672         assert(is_be_node(irn));
673         assert(out_pos < a->max_reg_data && "position too high");
674
675         return a->reg_data[out_pos].reg;
676 }
677
678 static arch_irn_class_t be_node_classify(const void *_self, const ir_node *irn)
679 {
680         redir_proj((const ir_node **) &irn, -1);
681
682         switch(be_get_irn_opcode(irn)) {
683 #define XXX(a,b) case beo_ ## a: return arch_irn_class_ ## b;
684                 XXX(Spill, spill)
685                 XXX(Reload, reload)
686                 XXX(Perm, perm)
687                 XXX(Copy, copy)
688 #undef XXX
689                 default:
690                 return 0;
691         }
692
693         return 0;
694 }
695
696 static arch_irn_flags_t be_node_get_flags(const void *_self, const ir_node *irn)
697 {
698         int out_pos;
699         be_node_attr_t *a;
700
701         out_pos = redir_proj((const ir_node **) &irn, -1);
702         a       = get_irn_attr(irn);
703
704         assert(is_be_node(irn));
705         assert(out_pos < a->max_reg_data && "position too high");
706
707         return a->reg_data[out_pos].req.flags;
708 }
709
710 static const arch_irn_ops_if_t be_node_irn_ops_if = {
711         be_node_get_irn_reg_req,
712         be_node_set_irn_reg,
713         be_node_get_irn_reg,
714         be_node_classify,
715         be_node_get_flags,
716 };
717
718 static const arch_irn_ops_t be_node_irn_ops = {
719         &be_node_irn_ops_if
720 };
721
722 const void *be_node_get_arch_ops(const arch_irn_handler_t *self, const ir_node *irn)
723 {
724         redir_proj((const ir_node **) &irn, -1);
725         return is_be_node(irn) ? &be_node_irn_ops : NULL;
726 }
727
728 const arch_irn_handler_t be_node_irn_handler = {
729         be_node_get_arch_ops
730 };
731
732
733 static void dump_node_req(FILE *f, be_req_t *req)
734 {
735         int i;
736         int did_something = 0;
737         const char *suffix = "";
738
739         if(req->flags != arch_irn_flags_none) {
740                 fprintf(f, "flags: ");
741                 for(i = arch_irn_flags_none; i <= log2_ceil(arch_irn_flags_last); ++i) {
742                         if(req->flags & (1 << i)) {
743                                 fprintf(f, "%s%s", suffix, arch_irn_flag_str(1 << i));
744                                 suffix = "|";
745                         }
746                 }
747                 suffix = ", ";
748                 did_something = 1;
749         }
750
751         if(req->req.cls != 0) {
752                 char tmp[256];
753                 fprintf(f, suffix);
754                 arch_register_req_format(tmp, sizeof(tmp), &req->req);
755                 fprintf(f, "%s", tmp);
756                 did_something = 1;
757         }
758
759         if(did_something)
760                 fprintf(f, "\n");
761 }
762
763 static void dump_node_reqs(FILE *f, ir_node *irn)
764 {
765         int i;
766         be_node_attr_t *a = get_irn_attr(irn);
767
768         fprintf(f, "registers: \n");
769         for(i = 0; i < a->max_reg_data; ++i) {
770                 be_reg_data_t *rd = &a->reg_data[i];
771                 if(rd->reg)
772                         fprintf(f, "#%d: %s\n", i, rd->reg->name);
773         }
774
775         fprintf(f, "in requirements\n");
776         for(i = 0; i < a->max_reg_data; ++i) {
777                 dump_node_req(f, &a->reg_data[i].in_req);
778         }
779
780         fprintf(f, "\nout requirements\n");
781         for(i = 0; i < a->max_reg_data; ++i) {
782                 dump_node_req(f, &a->reg_data[i].req);
783         }
784 }
785
786 static int dump_node(ir_node *irn, FILE *f, dump_reason_t reason)
787 {
788         be_node_attr_t *at = get_irn_attr(irn);
789
790         assert(is_be_node(irn));
791
792         switch(reason) {
793                 case dump_node_opcode_txt:
794                         fprintf(f, get_op_name(get_irn_op(irn)));
795                         break;
796                 case dump_node_mode_txt:
797                         fprintf(f, get_mode_name(get_irn_mode(irn)));
798                         break;
799                 case dump_node_nodeattr_txt:
800                         break;
801                 case dump_node_info_txt:
802                         dump_node_reqs(f, irn);
803
804                         switch(be_get_irn_opcode(irn)) {
805                         case beo_Spill:
806                                 {
807                                         be_spill_attr_t *a = (be_spill_attr_t *) at;
808
809                                         ir_fprintf(f, "spill context: %+F\n", a->spill_ctx);
810                                         if (a->ent) {
811                                                 unsigned ofs = get_entity_offset_bytes(a->ent);
812                                                 ir_fprintf(f, "spill entity: %+F offset %x (%d)\n", a->ent, ofs, ofs);
813                                         }
814                                         else {
815                                                 ir_fprintf(f, "spill entity: n/a\n");
816                                         }
817                                 }
818                                 break;
819
820                         case beo_IncSP:
821                                 {
822                                         be_stack_attr_t *a = (be_stack_attr_t *) at;
823                                         fprintf(f, "offset: %u\n", a->offset);
824                                         fprintf(f, "direction: %s\n", a->dir == be_stack_dir_along ? "along" : "against");
825                                 }
826                                 break;
827                         }
828
829         }
830
831         return 0;
832 }
833
834 /**
835  * Copies the backend specific attributes from old node to new node.
836  */
837 static void copy_attr(const ir_node *old_node, ir_node *new_node)
838 {
839         be_node_attr_t *old_attr = get_irn_attr(old_node);
840         be_node_attr_t *new_attr = get_irn_attr(new_node);
841         int i;
842
843         assert(is_be_node(old_node));
844         assert(is_be_node(new_node));
845
846         memcpy(new_attr, old_attr, get_op_attr_size(get_irn_op(old_node)));
847         new_attr->reg_data = NULL;
848
849         if(new_attr->max_reg_data > 0) {
850                 new_attr->reg_data = NEW_ARR_D(be_reg_data_t, get_irg_obstack(get_irn_irg(new_node)), new_attr->max_reg_data);
851                 memcpy(new_attr->reg_data, old_attr->reg_data, new_attr->max_reg_data * sizeof(be_reg_data_t));
852
853                 for(i = 0; i < old_attr->max_reg_data; ++i) {
854                         be_req_t *r;
855
856                         r = &new_attr->reg_data[i].req;
857                         r->req.limited_env = r;
858
859                         r = &new_attr->reg_data[i].in_req;
860                         r->req.limited_env = r;
861                 }
862         }
863 }
864
865 static const ir_op_ops be_node_op_ops = {
866         NULL,
867         NULL,
868         NULL,
869         NULL,
870         NULL,
871         copy_attr,
872         NULL,
873         NULL,
874         NULL,
875         NULL,
876         NULL,
877         dump_node,
878         NULL
879 };
880
881 pset *nodes_live_at(const arch_env_t *arch_env, const arch_register_class_t *cls, const ir_node *pos, pset *live)
882 {
883         firm_dbg_module_t *dbg = firm_dbg_register("firm.be.node");
884         const ir_node *bl      = is_Block(pos) ? pos : get_nodes_block(pos);
885         ir_node *irn;
886         irn_live_t *li;
887
888         live_foreach(bl, li) {
889                 ir_node *irn = (ir_node *) li->irn;
890                 if(live_is_end(li) && arch_irn_consider_in_reg_alloc(arch_env, cls, irn))
891                         pset_insert_ptr(live, irn);
892         }
893
894         sched_foreach_reverse(bl, irn) {
895                 int i, n;
896                 ir_node *x;
897
898                 /*
899                  * If we encounter the node we want to insert the Perm after,
900                 * exit immediately, so that this node is still live
901                 */
902                 if(irn == pos)
903                         return live;
904
905                 DBG((dbg, LEVEL_1, "%+F\n", irn));
906                 for(x = pset_first(live); x; x = pset_next(live))
907                         DBG((dbg, LEVEL_1, "\tlive: %+F\n", x));
908
909                 if(arch_irn_consider_in_reg_alloc(arch_env, cls, irn))
910                         pset_remove_ptr(live, irn);
911
912                 for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
913                         ir_node *op = get_irn_n(irn, i);
914
915                         if(arch_irn_consider_in_reg_alloc(arch_env, cls, op))
916                                 pset_insert_ptr(live, op);
917                 }
918         }
919
920         return live;
921 }
922
923 ir_node *insert_Perm_after(const arch_env_t *arch_env,
924                                                    const arch_register_class_t *cls,
925                                                    dom_front_info_t *dom_front,
926                                                    ir_node *pos)
927 {
928         ir_node *bl                 = is_Block(pos) ? pos : get_nodes_block(pos);
929         ir_graph *irg               = get_irn_irg(bl);
930         pset *live                  = pset_new_ptr_default();
931         firm_dbg_module_t *dbg      = firm_dbg_register("be.node");
932
933         ir_node *curr, *irn, *perm, **nodes;
934         int i, n;
935
936         DBG((dbg, LEVEL_1, "Insert Perm after: %+F\n", pos));
937
938         if(!nodes_live_at(arch_env, cls, pos, live));
939
940         n = pset_count(live);
941
942         if(n == 0)
943                 return NULL;
944
945         nodes = malloc(n * sizeof(nodes[0]));
946
947         DBG((dbg, LEVEL_1, "live:\n"));
948         for(irn = pset_first(live), i = 0; irn; irn = pset_next(live), i++) {
949                 DBG((dbg, LEVEL_1, "\t%+F\n", irn));
950                 nodes[i] = irn;
951         }
952
953         perm = be_new_Perm(cls, irg, bl, n, nodes);
954         sched_add_after(pos, perm);
955         free(nodes);
956
957         curr = perm;
958         for(i = 0; i < n; ++i) {
959                 ir_node *copies[2];
960                 ir_node *perm_op = get_irn_n(perm, i);
961                 const arch_register_t *reg = arch_get_irn_register(arch_env, perm_op);
962
963                 ir_mode *mode = get_irn_mode(perm_op);
964                 ir_node *proj = new_r_Proj(irg, bl, perm, mode, i);
965                 arch_set_irn_register(arch_env, proj, reg);
966
967                 sched_add_after(curr, proj);
968                 curr = proj;
969
970                 copies[0] = perm_op;
971                 copies[1] = proj;
972                 be_ssa_constr(dom_front, 2, copies);
973         }
974         return perm;
975 }