84d69c0c67f4a7695780bb60355c667e00eadafa
[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  * Copyright (C) 2005 Universitaet Karlsruhe
9  * Released under the GPL
10  */
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #include <stdlib.h>
16
17 #include "obst.h"
18 #include "set.h"
19 #include "pmap.h"
20 #include "util.h"
21
22 #include "irop_t.h"
23 #include "irmode_t.h"
24 #include "irnode_t.h"
25 #include "ircons_t.h"
26
27 #include "be_t.h"
28 #include "belive_t.h"
29 #include "besched_t.h"
30 #include "benode_t.h"
31
32 #include "beirgmod.h"
33
34 typedef enum _node_kind_t {
35   node_kind_spill,
36   node_kind_reload,
37   node_kind_perm,
38   node_kind_copy,
39   node_kind_last
40 } node_kind_t;
41
42 typedef struct {
43   node_kind_t kind;
44   const arch_register_class_t *cls;
45   ir_op *op;
46   int n_pos;
47   int *pos;
48 } be_op_t;
49
50 static int templ_pos_Spill[] = {
51   arch_pos_make_in(0)
52 };
53
54 static int templ_pos_Reload[] = {
55   arch_pos_make_out(0)
56 };
57
58 static int templ_pos_Copy[] = {
59   arch_pos_make_in(0),
60   arch_pos_make_out(0)
61 };
62
63 #define ARRSIZE(x) (sizeof(x) / sizeof(x[0]))
64
65 static int cmp_op_map(const void *a, const void *b, size_t size)
66 {
67   const be_op_t *x = a;
68   const be_op_t *y = b;
69
70   return !(x->kind == y->kind && x->cls == y->cls);
71 }
72
73 static be_op_t *get_op(const be_node_factory_t *fact,
74     const arch_register_class_t *cls, node_kind_t kind)
75 {
76   be_op_t templ;
77
78   templ.kind = kind;
79   templ.cls = cls;
80
81   return set_insert(fact->ops, &templ, sizeof(templ),
82       HASH_PTR(cls) + 7 * kind);
83 }
84
85 ir_node *new_Spill(const be_node_factory_t *factory,
86     const arch_register_class_t *cls,
87     ir_graph *irg, ir_node *bl, ir_node *node_to_spill)
88 {
89   ir_node *in[1];
90   ir_op *op = get_op(factory, cls, node_kind_spill)->op;
91
92   assert(op && "Spill opcode must be present for this register class");
93   in[0] = node_to_spill;
94
95   return new_ir_node(NULL, irg, bl, op, mode_M, 1, in);
96 }
97
98 ir_node *new_Reload(const be_node_factory_t *factory,
99     const arch_register_class_t *cls,
100     ir_graph *irg, ir_node *bl, ir_node *spill_node)
101 {
102   ir_mode *mode;
103   ir_node *in[1];
104   ir_op *op = get_op(factory, cls, node_kind_reload)->op;
105
106   assert(op && "Reload opcode must be present for this register class");
107   assert(is_Spill(factory, spill_node) && "Operand of Reload must be a Spill");
108   in[0] = spill_node;
109   mode = get_irn_mode(get_irn_n(spill_node, 0));
110
111   return new_ir_node(NULL, irg, bl, op, mode, 1, in);
112 }
113
114 ir_node *new_Perm(const be_node_factory_t *factory,
115     const arch_register_class_t *cls,
116     ir_graph *irg, ir_node *bl, int arity, ir_node **in)
117 {
118   ir_op *op = get_op(factory, cls, node_kind_perm)->op;
119
120   return new_ir_node(NULL, irg, bl, op, mode_T, arity, in);
121 }
122
123 ir_node *new_Copy(const be_node_factory_t *factory,
124     const arch_register_class_t *cls,
125     ir_graph *irg, ir_node *bl, ir_node *in)
126 {
127   ir_node *ins[1];
128   ir_op *op = get_op(factory, cls, node_kind_perm)->op;
129
130   ins[0] = in;
131
132   return new_ir_node(NULL, irg, bl, op, get_irn_mode(in), 1, ins);
133 }
134
135 /**
136  * If the node is a proj, reset the node to the proj's target and return
137  * the proj number.
138  * @param node The address of a node pointer.
139  * @param def  A default value.
140  * @return     If *node is a Proj, *node is set to the Proj's target and
141  *             the Proj number is returned. Else *node remains the same and @p def
142  *             is returned.
143  */
144 static int redir_proj(const ir_node **node, int def)
145 {
146   const ir_node *n = *node;
147
148   if(is_Proj(n)) {
149     *node = get_Proj_pred(n);
150     def = get_Proj_proj(n);
151   }
152
153   return def;
154 }
155
156 static const arch_register_req_t *
157 be_node_get_irn_reg_req(const arch_irn_ops_t *_self,
158     arch_register_req_t *req, const ir_node *irn, int pos)
159 {
160   be_op_t *bo;
161   const be_node_factory_t *factory =
162     container_of(_self, const be_node_factory_t, irn_ops);
163
164   pos = arch_pos_make_out(redir_proj(&irn, arch_pos_get_index(pos)));
165
166   bo = pmap_get(factory->irn_op_map, get_irn_op(irn));
167
168   if(bo) {
169     int i;
170
171     req->type = arch_register_req_type_normal;
172     req->cls = bo->cls;
173
174     for(i = 0; i < bo->n_pos; ++pos)
175       if(pos == bo->pos[i])
176         return req;
177   }
178
179   return NULL;
180 }
181
182 static int
183 be_node_get_n_operands(const arch_irn_ops_t *_self, const ir_node *irn, int in_out)
184 {
185   be_op_t *bo;
186   int i, res = 0;
187   const be_node_factory_t *factory =
188     container_of(_self, const be_node_factory_t, irn_ops);
189
190   redir_proj(&irn, 0);
191   bo = pmap_get(factory->irn_op_map, get_irn_op(irn));
192
193   for(i = 0; i < bo->n_pos; ++i)
194     res += (bo->pos[i] ^ in_out) > 0;
195
196   return res;
197 }
198
199 void
200 be_node_set_irn_reg(const arch_irn_ops_t *_self, ir_node *irn,
201     int idx, const arch_register_t *reg)
202 {
203   const arch_register_t **regs;
204
205   idx = redir_proj((const ir_node **) &irn, idx);
206   regs = (const arch_register_t **) &irn->attr;
207   regs[idx] = reg;
208 }
209
210 const arch_register_t *
211 be_node_get_irn_reg(const arch_irn_ops_t *_self, const ir_node *irn, int idx)
212 {
213   const arch_register_t **regs;
214
215   idx = redir_proj(&irn, idx);
216   regs = (const arch_register_t **) &irn->attr;
217   return regs[idx];
218 }
219
220 arch_irn_class_t be_node_classify(const arch_irn_ops_t *_self, const ir_node *irn)
221 {
222   const be_node_factory_t *factory =
223     container_of(_self, const be_node_factory_t, irn_ops);
224
225   be_op_t *bo;
226   int idx;
227
228   idx = redir_proj(&irn, 0);
229   bo = pmap_get(factory->irn_op_map, get_irn_op(irn));
230
231   return 0;
232 }
233
234 static const arch_irn_ops_t *
235 be_node_get_irn_ops(const arch_irn_handler_t *_self, const ir_node *irn)
236 {
237   be_op_t *bo;
238   const be_node_factory_t *factory =
239     container_of(_self, const be_node_factory_t, handler);
240
241   redir_proj(&irn, 0);
242   bo = pmap_get(factory->irn_op_map, get_irn_op(irn));
243
244   return bo ? &factory->irn_ops : NULL;
245 }
246
247 const arch_irn_handler_t *be_node_get_irn_handler(const be_node_factory_t *f)
248 {
249   return &f->handler;
250 }
251
252 int is_Spill(const be_node_factory_t *f, const ir_node *irn)
253 {
254   be_op_t *bo;
255   bo = pmap_get(f->irn_op_map, get_irn_op(irn));
256   return bo->kind == node_kind_spill;
257 }
258
259 be_node_factory_t *be_node_factory_init(be_node_factory_t *factory,
260     const arch_isa_if_t *isa)
261 {
262   char buf[256];
263   int i, j, n;
264
265   factory->ops = new_set(cmp_op_map, 64);
266   factory->irn_op_map = pmap_create();
267   obstack_init(&factory->obst);
268
269   factory->handler.get_irn_ops = be_node_get_irn_ops;
270
271   factory->irn_ops.get_irn_reg_req = be_node_get_irn_reg_req;
272   factory->irn_ops.get_n_operands  = be_node_get_n_operands;
273   factory->irn_ops.set_irn_reg     = be_node_set_irn_reg;
274   factory->irn_ops.get_irn_reg     = be_node_get_irn_reg;
275   factory->irn_ops.classify        = be_node_classify;
276
277   for(i = 0, n = isa->get_n_reg_class(); i < n; ++i) {
278     const arch_register_class_t *cls = isa->get_reg_class(i);
279     be_op_t *ent;
280
281     ent = get_op(factory, cls, node_kind_spill);
282     snprintf(buf, sizeof(buf), "Spill_%s", cls->name);
283     ent->op = new_ir_op(get_next_ir_opcode(), buf, op_pin_state_pinned,
284         0, 0, oparity_unary, 0);
285     ent->n_pos = ARRSIZE(templ_pos_Spill);
286     ent->pos = templ_pos_Spill;
287     pmap_insert(factory->irn_op_map, ent->op, ent);
288
289     ent = get_op(factory, cls, node_kind_reload);
290     snprintf(buf, sizeof(buf), "Reload_%s", cls->name);
291     ent->op = new_ir_op(get_next_ir_opcode(), buf, op_pin_state_pinned, 0, 0,
292         oparity_unary, sizeof(const arch_register_t *));
293     ent->n_pos = ARRSIZE(templ_pos_Reload);
294     ent->pos = templ_pos_Reload;
295     pmap_insert(factory->irn_op_map, ent->op, ent);
296
297     ent = get_op(factory, cls, node_kind_copy);
298     snprintf(buf, sizeof(buf), "Copy_%s", cls->name);
299     ent->op = new_ir_op(get_next_ir_opcode(), buf, op_pin_state_pinned, 0, 0,
300         oparity_unary, sizeof(const arch_register_t *));
301     ent->n_pos = ARRSIZE(templ_pos_Copy);
302     ent->pos = templ_pos_Copy;
303     pmap_insert(factory->irn_op_map, ent->op, ent);
304
305     ent = get_op(factory, cls, node_kind_perm);
306     snprintf(buf, sizeof(buf), "Perm_%s", cls->name);
307     ent->op = new_ir_op(get_next_ir_opcode(), buf, op_pin_state_pinned, 0, 0,
308         oparity_variable, sizeof(const arch_register_t) * cls->n_regs);
309     ent->n_pos = 2 * cls->n_regs;
310     ent->pos = obstack_alloc(&factory->obst, sizeof(ent->pos[0]) * ent->n_pos);
311     for(j = 0; j < ent->n_pos; j += 2) {
312       ent->pos[j] = arch_pos_make_in(j);
313       ent->pos[j + 1] = arch_pos_make_out(j);
314     }
315     pmap_insert(factory->irn_op_map, ent->op, ent);
316
317   }
318
319   return factory;
320 }
321
322 ir_node *insert_Perm_after(const be_main_session_env_t *env,
323     const arch_register_class_t *cls, ir_node *pos)
324 {
325   const arch_env_t *arch_env = env->main_env->arch_env;
326   ir_node *bl = is_Block(pos) ? pos : get_nodes_block(pos);
327   ir_graph *irg = get_irn_irg(bl);
328   pset *live = put_live_end(bl, pset_new_ptr_default());
329   ir_node *curr, *irn, *perm, **nodes;
330   int i, n;
331
332   ir_printf("Insert Perm after: %+F\n", pos);
333
334   sched_foreach_reverse(bl, irn) {
335
336     if(arch_irn_has_reg_class(arch_env, irn, arch_pos_make_out(0), cls))
337       pset_remove_ptr(live, irn);
338
339     for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
340       ir_node *op = get_irn_n(irn, i);
341
342       if(arch_irn_has_reg_class(arch_env, op, arch_pos_make_out(0), cls))
343         pset_insert_ptr(live, op);
344     }
345
346     if(sched_prev(irn) == pos)
347       break;
348   }
349
350   n = pset_count(live);
351   nodes = malloc(n * sizeof(nodes[0]));
352
353   for(irn = pset_first(live), i = 0; irn; irn = pset_next(live), i++)
354     nodes[i] = irn;
355
356   perm = new_Perm(env->main_env->node_factory, cls, irg, bl, n, nodes);
357   sched_add_after(pos, perm);
358   free(nodes);
359
360   curr = perm;
361   for(i = 0; i < n; ++i) {
362     ir_node *copies[1];
363     ir_node *perm_op = get_irn_n(perm, i);
364
365     ir_mode *mode = get_irn_mode(perm_op);
366     ir_node *proj = new_r_Proj(irg, bl, perm, mode, i);
367     sched_add_after(curr, proj);
368     curr = proj;
369
370     copies[0] = proj;
371     be_introduce_copies(env->dom_front, perm_op, array_size(copies), copies);
372   }
373   return perm;
374 }