Several BugFixes and updates:
[libfirm] / ir / be / firm / bearch_firm.c
1 /*
2  * Copyright (C) 1995-2007 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   ISA implementation for Firm IR nodes.
23  * @author  Daniel Grund
24  * @version $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "bitset.h"
31 #include "obst.h"
32
33 #include "irmode_t.h"
34 #include "irnode_t.h"
35 #include "iredges_t.h"
36 #include "irgmod.h"
37 #include "ircons_t.h"
38 #include "irgwalk.h"
39 #include "type.h"
40 #include "irtools.h"
41
42 #include "../be_t.h"
43 #include "../bearch_t.h"
44 #include "../besched.h"
45 #include "../beutil.h"
46 #include "../beabi.h"
47
48 #define N_REGS 3
49
50 typedef struct {
51   enum  { imm_Const, imm_SymConst } tp;
52   union {
53     const_attr    cnst_attr;
54     symconst_attr symc_attr;
55   } data;
56 } imm_attr_t;
57
58 static arch_register_t datab_regs[N_REGS];
59
60 static arch_register_class_t reg_classes[] = {
61   { "datab", N_REGS, NULL, datab_regs },
62 };
63
64 static ir_op *op_push;
65 static ir_op *op_imm;
66
67 const arch_isa_if_t firm_isa;
68
69 #define N_CLASSES \
70   (sizeof(reg_classes) / sizeof(reg_classes[0]))
71
72 #define CLS_DATAB 0
73
74 tarval *get_Imm_tv(ir_node *n) {
75   imm_attr_t *attr = (imm_attr_t *)get_irn_generic_attr(n);
76   return attr->tp == imm_Const ? attr->data.cnst_attr.tv : NULL;
77 }
78
79 int is_Imm(const ir_node *irn) {
80   return get_irn_op(irn) == op_imm;
81 }
82
83 static int dump_node_Imm(ir_node *n, FILE *F, dump_reason_t reason) {
84   ir_mode    *mode;
85   int        bad = 0;
86   char       buf[1024];
87   tarval     *tv;
88   imm_attr_t *attr;
89
90   switch (reason) {
91     case dump_node_opcode_txt:
92       tv = get_Imm_tv(n);
93
94       if (tv) {
95         tarval_snprintf(buf, sizeof(buf), tv);
96         fprintf(F, "%s", buf);
97       }
98       else {
99         fprintf(F, "immSymC");
100       }
101       break;
102
103     case dump_node_mode_txt:
104       mode = get_irn_mode(n);
105
106       if (mode && mode != mode_BB && mode != mode_ANY && mode != mode_BAD && mode != mode_T) {
107         fprintf(F, "[%s]", get_mode_name(mode));
108       }
109       break;
110
111     case dump_node_nodeattr_txt:
112       attr = (imm_attr_t *)get_irn_generic_attr(n);
113
114       if (is_Imm(n) && attr->tp == imm_SymConst) {
115         const char *name    = NULL;
116         symconst_attr *sc_attr = &attr->data.symc_attr;
117
118         switch (sc_attr->num) {
119           case symconst_addr_name:
120             name = get_id_str(sc_attr->sym.ident_p);
121             break;
122
123           case symconst_addr_ent:
124             name = get_entity_ld_name(sc_attr->sym.entity_p);
125             break;
126
127           default:
128             assert(!"Unsupported SymConst");
129         }
130
131         fprintf(F, "&%s ", name);
132       }
133
134       break;
135
136     case dump_node_info_txt:
137       break;
138   }
139
140   return bad;
141 }
142
143 static void *firm_init(FILE *outfile)
144 {
145   static struct obstack obst;
146   static int inited = 0;
147   arch_isa_t *isa = xmalloc(sizeof(*isa));
148   int k;
149
150   isa->impl = &firm_isa;
151
152   if(inited)
153     return NULL;
154
155   inited = 1;
156   obstack_init(&obst);
157
158   for(k = 0; k < N_CLASSES; ++k) {
159     arch_register_class_t *cls = &reg_classes[k];
160     int i;
161
162     cls->mode = mode_Is;
163     for(i = 0; i < cls->n_regs; ++i) {
164       int n;
165       char buf[8];
166       char *name;
167       arch_register_t *reg = (arch_register_t *) &cls->regs[i];
168
169       n = snprintf(buf, sizeof(buf), "r%d", i);
170       name = obstack_copy0(&obst, buf, n);
171
172       reg->name = name;
173       reg->reg_class = cls;
174       reg->index = i;
175       reg->type = 0;
176     }
177   }
178
179         /*
180          * Create some opcodes and types to let firm look a little
181          * bit more like real machines.
182          */
183         if(!op_push) {
184                 int push_opc = get_next_ir_opcode();
185
186                 op_push = new_ir_op(push_opc, "Push",
187                                 op_pin_state_pinned, 0, oparity_binary, 0, 0, NULL);
188         }
189
190         if(!op_imm) {
191                 int imm_opc = get_next_ir_opcode();
192                 ir_op_ops ops;
193
194                 memset(&ops, 0, sizeof(ops));
195                 ops.dump_node = dump_node_Imm;
196
197                 op_imm = new_ir_op(imm_opc, "Imm",
198                                 op_pin_state_pinned, 0, oparity_zero, 0, sizeof(imm_attr_t), &ops);
199         }
200
201         return isa;
202 }
203
204 static void firm_done(void *self)
205 {
206         free(self);
207 }
208
209 static int firm_get_n_reg_class(const void *self)
210 {
211   return N_CLASSES;
212 }
213
214 static const arch_register_class_t *firm_get_reg_class(const void *self, int i)
215 {
216   assert(i >= 0 && i < N_CLASSES);
217   return &reg_classes[i];
218 }
219
220 static const arch_register_class_t *firm_get_reg_class_for_mode(const void *self, const ir_mode *irm)
221 {
222         return mode_is_datab(irm) ? &reg_classes[CLS_DATAB] : NULL;
223 }
224
225 static ir_type *firm_abi_get_between_type(void *self) {
226         static ir_type *between_type = NULL;
227
228         if(!between_type) {
229                 between_type = new_type_class(new_id_from_str("firm_be_between"));
230                 set_type_size_bytes(between_type, 0);
231         }
232
233         return between_type;
234 }
235
236 static const be_abi_callbacks_t firm_abi_callbacks = {
237         NULL,
238         NULL,
239         firm_abi_get_between_type,
240         NULL,
241         NULL,
242         NULL,
243 };
244
245 static void firm_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi)
246 {
247         const arch_register_class_t *cls = &reg_classes[CLS_DATAB];
248         int i, n;
249         be_abi_call_flags_t flags = { { 0, 0, 0, 0, 0 } };
250
251
252         for(i = 0, n = get_method_n_params(method_type); i < n; ++i) {
253                 ir_type *t = get_method_param_type(method_type, i);
254                 if(is_Primitive_type(t))
255                         be_abi_call_param_reg(abi, i, &cls->regs[i]);
256                 else
257                         be_abi_call_param_stack(abi, i, 1, 0, 0);
258         }
259
260         for(i = 0, n = get_method_n_ress(method_type); i < n; ++i) {
261                 ir_type *t = get_method_res_type(method_type, i);
262                 if(is_Primitive_type(t))
263                         be_abi_call_res_reg(abi, i, &cls->regs[i]);
264         }
265
266         flags.val = 0;
267         be_abi_call_set_flags(abi, flags, &firm_abi_callbacks);
268 }
269
270
271 static const arch_register_req_t firm_std_reg_req = {
272   arch_register_req_type_normal,
273   &reg_classes[CLS_DATAB],
274   0,
275   0
276 };
277
278 static const arch_register_req_t *
279 firm_get_irn_reg_req(const void *self, const ir_node *irn, int pos)
280 {
281   if(is_firm_be_mode(get_irn_mode(irn)))
282           return &firm_std_reg_req;
283
284   return NULL;
285 }
286
287 struct irn_reg_assoc {
288   const ir_node *irn;
289   const arch_register_t *reg;
290 };
291
292 static int cmp_irn_reg_assoc(const void *a, const void *b, size_t len)
293 {
294   const struct irn_reg_assoc *x = a;
295   const struct irn_reg_assoc *y = b;
296
297   return x->irn != y->irn;
298 }
299
300 static struct irn_reg_assoc *get_irn_reg_assoc(const ir_node *irn)
301 {
302   static set *reg_set = NULL;
303   struct irn_reg_assoc templ;
304
305   if(!reg_set)
306     reg_set = new_set(cmp_irn_reg_assoc, 1024);
307
308   templ.irn = irn;
309   templ.reg = NULL;
310
311   return set_insert(reg_set, &templ, sizeof(templ), HASH_PTR(irn));
312 }
313
314 static void firm_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg)
315 {
316   struct irn_reg_assoc *assoc = get_irn_reg_assoc(irn);
317   assoc->reg = reg;
318 }
319
320 static const arch_register_t *firm_get_irn_reg(const void *self, const ir_node *irn)
321 {
322   struct irn_reg_assoc *assoc = get_irn_reg_assoc(irn);
323   return assoc->reg;
324 }
325
326 static arch_irn_class_t firm_classify(const void *self, const ir_node *irn)
327 {
328     arch_irn_class_t res;
329
330     switch(get_irn_opcode(irn)) {
331         case iro_Cond:
332         case iro_Jmp:
333             res = arch_irn_class_branch;
334             break;
335                 case iro_Call:
336                         res = arch_irn_class_call;
337                         break;
338         default:
339             res = arch_irn_class_normal;
340     }
341
342         return res;
343 }
344
345 static arch_irn_flags_t firm_get_flags(const void *self, const ir_node *irn)
346 {
347         arch_irn_flags_t res = 0;
348
349         if(get_irn_op(irn) == op_imm)
350                 res |= arch_irn_flags_rematerializable;
351
352         switch(get_irn_opcode(irn)) {
353                 case iro_Add:
354                 case iro_Sub:
355                 case iro_Shl:
356                 case iro_Shr:
357                 case iro_Shrs:
358                 case iro_And:
359                 case iro_Or:
360                 case iro_Eor:
361                 case iro_Not:
362                         res |= arch_irn_flags_rematerializable;
363                 default:
364                         res = res;
365         }
366
367         return res;
368 }
369
370 static void firm_set_stack_bias(const void *self, ir_node *irn, int bias)
371 {
372 }
373
374 static ir_entity *firm_get_frame_entity(const void *self, const ir_node *irn)
375 {
376         return NULL;
377 }
378
379 static void firm_set_frame_entity(const void *self, ir_node *irn, ir_entity *ent)
380 {
381 }
382
383 static const arch_irn_ops_if_t firm_irn_ops_if = {
384         firm_get_irn_reg_req,
385         firm_set_irn_reg,
386         firm_get_irn_reg,
387         firm_classify,
388         firm_get_flags,
389         firm_get_frame_entity,
390         firm_set_frame_entity,
391         firm_set_stack_bias,
392         NULL,    /* get_inverse             */
393         NULL,    /* get_op_estimated_cost   */
394         NULL,    /* possible_memory_operand */
395         NULL,    /* perform_memory_operand  */
396 };
397
398 static const arch_irn_ops_t firm_irn_ops = {
399         &firm_irn_ops_if
400 };
401
402 static const void *firm_get_irn_ops(const arch_irn_handler_t *self,
403         const ir_node *irn)
404 {
405         return &firm_irn_ops;
406 }
407
408 const arch_irn_handler_t firm_irn_handler = {
409         firm_get_irn_ops,
410 };
411
412 static ir_node *new_Push(ir_graph *irg, ir_node *bl, ir_node *push, ir_node *arg)
413 {
414         ir_node *ins[2];
415         ins[0] = push;
416         ins[1] = arg;
417         return new_ir_node(NULL, irg, bl, op_push, mode_M, 2, ins);
418 }
419
420 /**
421  * Creates an op_Imm node from an op_Const.
422  */
423 static ir_node *new_Imm(ir_graph *irg, ir_node *bl, ir_node *cnst) {
424   ir_node    *ins[1];
425   ir_node    *res;
426   imm_attr_t *attr;
427
428   res = new_ir_node(NULL, irg, bl, op_imm, get_irn_mode(cnst), 0, ins);
429   attr = (imm_attr_t *) &res->attr;
430
431   switch (get_irn_opcode(cnst)) {
432     case iro_Const:
433       attr->tp      = imm_Const;
434       attr->data.cnst_attr = get_irn_const_attr(cnst);
435       break;
436     case iro_SymConst:
437       attr->tp             = imm_SymConst;
438       attr->data.symc_attr = get_irn_symconst_attr(cnst);
439       break;
440     case iro_Unknown:
441       break;
442     default:
443       assert(0 && "Cannot create Imm for this opcode");
444   }
445
446   return res;
447 }
448
449 static void prepare_walker(ir_node *irn, void *data)
450 {
451         ir_opcode opc = get_irn_opcode(irn);
452
453         /* A replacement for this node has already been computed. */
454         if(get_irn_link(irn))
455                 return;
456
457         if(opc == iro_Call) {
458                 ir_node *bl   = get_nodes_block(irn);
459                 ir_graph *irg = get_irn_irg(bl);
460
461                 ir_node *store   = get_Call_mem(irn);
462                 ir_node *ptr     = get_Call_ptr(irn);
463                 ir_type *ct      = get_Call_type(irn);
464                 int np           = get_Call_n_params(irn) > 0 ? 1 : 0;
465
466                 if(np > 0) {
467                         ir_node *ins[1];
468                         char buf[128];
469                         ir_node *nc;
470                         int i, n = get_Call_n_params(irn);
471                         ir_type *nt;
472       unsigned cc = get_method_calling_convention(get_Call_type(irn));
473
474       if (cc & cc_last_on_top) {
475                           store = new_Push(irg, bl, store, get_Call_param(irn, 0));
476
477                           for (i = 1; i < n; ++i)
478                                   store = new_Push(irg, bl, store, get_Call_param(irn, i));
479       }
480       else {
481         store = new_Push(irg, bl, store, get_Call_param(irn, n - 1));
482
483         for (i = n - 2; i >= 0; --i)
484           store = new_Push(irg, bl, store, get_Call_param(irn, i));
485       }
486
487                         snprintf(buf, sizeof(buf), "push_%s", get_type_name(ct));
488
489                         n = get_method_n_ress(ct);
490                         nt = new_type_method(new_id_from_str(buf), 0, n);
491                         for(i = 0; i < n; ++i)
492                                 set_method_res_type(nt, i, get_method_res_type(ct, i));
493
494                         nc = new_r_Call(irg, bl, store, ptr, 0, ins, nt);
495                         exchange(irn, nc);
496                         set_irn_link(nc, nc);
497                 }
498         }
499 }
500
501 static void localize_const_walker(ir_node *irn, void *data)
502 {
503         if(!is_Block(irn)) {
504                 int i, n;
505                 ir_node *bl = get_nodes_block(irn);
506
507                 for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
508                         ir_node *op   = get_irn_n(irn, i);
509                         ir_opcode opc = get_irn_opcode(op);
510
511                         if(opc == iro_Const
512                         || opc == iro_Unknown
513                         || (opc == iro_SymConst /*&& get_SymConst_kind(op) == symconst_addr_ent*/)) {
514                                 ir_graph *irg   = get_irn_irg(bl);
515                                 ir_node *imm_bl = is_Phi(irn) ? get_Block_cfgpred_block(bl, i) : bl;
516
517                                 ir_node *imm = new_Imm(irg, imm_bl, op);
518                                 set_irn_n(irn, i, imm);
519                         }
520                 }
521         }
522 }
523
524 static const arch_irn_handler_t *firm_get_irn_handler(const void *self)
525 {
526         return &firm_irn_handler;
527 }
528
529 typedef struct _firm_code_gen_t {
530         const arch_code_generator_if_t *impl;
531         ir_graph *irg;
532 } firm_code_gen_t;
533
534
535 static void firm_prepare_graph(void *self)
536 {
537         firm_code_gen_t *cg = self;
538
539         irg_walk_graph(cg->irg, firm_clear_link, localize_const_walker, NULL);
540         irg_walk_graph(cg->irg, NULL, prepare_walker, NULL);
541 }
542
543 static void firm_before_sched(void *self)
544 {
545 }
546
547 static void imm_scheduler(ir_node *irn, void *env) {
548         if(is_Imm(irn)) {
549                 const ir_edge_t *e;
550                 ir_node *user, *user_block, *before, *tgt_block;
551
552                 if (1 != get_irn_n_edges(irn)) {
553                         printf("Out edges: %d\n", get_irn_n_edges(irn));
554                         assert(1 == get_irn_n_edges(irn));
555                 }
556
557                 e = get_irn_out_edge_first(irn);
558                 user = e->src;
559                 user_block = get_nodes_block(user);
560                 if (is_Phi(user)) {
561                         before = get_Block_cfgpred_block(user_block, e->pos);
562                         tgt_block = before;
563                 } else {
564                         before = user;
565                         tgt_block = user_block;
566                 }
567
568                 sched_remove(irn);
569                 set_nodes_block(irn, tgt_block);
570                 sched_add_before(before, irn);
571         }
572 }
573
574 static void firm_before_ra(void *self)
575 {
576         firm_code_gen_t *cg = self;
577         irg_walk_graph(cg->irg, imm_scheduler, NULL, NULL);
578 }
579
580 static void firm_after_ra(void *self)
581 {
582 }
583
584 static void firm_codegen_done(void *self)
585 {
586         free(self);
587 }
588
589 static void *firm_cg_init(be_irg_t *birg);
590
591 static const arch_code_generator_if_t firm_code_gen_if = {
592         firm_cg_init,
593         NULL,
594         firm_prepare_graph,
595         NULL,                /* spill */
596         firm_before_sched,
597         firm_before_ra,
598         firm_after_ra,
599         firm_codegen_done
600 };
601
602 static void *firm_cg_init(be_irg_t *birg)
603 {
604         firm_code_gen_t *cg = xmalloc(sizeof(*cg));
605         cg->impl = &firm_code_gen_if;
606         cg->irg  = be_get_birg_irg(birg);
607         return cg;
608 }
609
610
611 static const arch_code_generator_if_t *firm_get_code_generator_if(void *self)
612 {
613         return &firm_code_gen_if;
614 }
615
616 static const list_sched_selector_t *firm_get_list_sched_selector(const void *self, list_sched_selector_t *selector) {
617         return trivial_selector;
618 }
619
620 static const ilp_sched_selector_t *firm_get_ilp_sched_selector(const void *self) {
621         return NULL;
622 }
623
624 /**
625  * Returns the necessary byte alignment for storing a register of given class.
626  */
627 static int firm_get_reg_class_alignment(const void *self, const arch_register_class_t *cls) {
628         ir_mode *mode = arch_register_class_mode(cls);
629         return get_mode_size_bytes(mode);
630 }
631
632 static const be_execution_unit_t ***firm_get_allowed_execution_units(const void *self, const ir_node *irn) {
633         /* TODO */
634         assert(0);
635         return NULL;
636 }
637
638 static const be_machine_t *firm_get_machine(const void *self) {
639         /* TODO */
640         assert(0);
641         return NULL;
642 }
643
644 /**
645  * Return irp irgs in the desired order.
646  */
647 static ir_graph **firm_get_irg_list(const void *self, ir_graph ***irg_list) {
648         return NULL;
649 }
650
651 /**
652  * Returns the libFirm configuration parameter for this backend.
653  */
654 static const backend_params *firm_get_libfirm_params(void) {
655         static arch_dep_params_t ad = {
656                 1,  /* allow subs */
657                 0,      /* Muls are fast enough on Firm */
658                 31, /* shift would be ok */
659                 0,  /* no Mulhs */
660                 0,  /* no Mulhu */
661                 0,  /* no Mulh */
662         };
663         static backend_params p = {
664                 NULL,  /* no additional opcodes */
665                 NULL,  /* will be set later */
666                 0,     /* no dword lowering */
667                 NULL,  /* no creator function */
668                 NULL,  /* context for create_intrinsic_fkt */
669         };
670
671         p.dep_param = &ad;
672         return &p;
673 }
674
675 const arch_isa_if_t firm_isa = {
676         firm_init,
677         firm_done,
678         firm_get_n_reg_class,
679         firm_get_reg_class,
680         firm_get_reg_class_for_mode,
681         firm_get_call_abi,
682         firm_get_irn_handler,
683         firm_get_code_generator_if,
684         firm_get_list_sched_selector,
685         firm_get_ilp_sched_selector,
686         firm_get_reg_class_alignment,
687         firm_get_libfirm_params,
688         firm_get_allowed_execution_units,
689         firm_get_machine,
690         firm_get_irg_list,
691 };