2bdb84139b6f230e502471aa3e84b506490583a6
[libfirm] / ir / be / arm / arm_emitter.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   arm emitter
23  * @author  Oliver Richter, Tobias Gneist, Michael Beck
24  */
25 #include "config.h"
26
27 #include <limits.h>
28 #include <stdbool.h>
29
30 #include "xmalloc.h"
31 #include "tv.h"
32 #include "iredges.h"
33 #include "debug.h"
34 #include "irgwalk.h"
35 #include "irtools.h"
36 #include "irprintf.h"
37 #include "irop_t.h"
38 #include "irprog_t.h"
39 #include "irargs_t.h"
40 #include "error.h"
41 #include "raw_bitset.h"
42 #include "dbginfo.h"
43
44 #include "besched.h"
45 #include "beblocksched.h"
46 #include "beirg.h"
47 #include "begnuas.h"
48 #include "bedwarf.h"
49
50 #include "arm_emitter.h"
51 #include "arm_optimize.h"
52 #include "gen_arm_emitter.h"
53 #include "arm_nodes_attr.h"
54 #include "arm_new_nodes.h"
55 #include "arm_map_regs.h"
56 #include "gen_arm_regalloc_if.h"
57
58 #include "benode.h"
59
60 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
61
62 static set       *sym_or_tv;
63 static arm_isa_t *isa;
64
65 static void arm_emit_register(const arch_register_t *reg)
66 {
67         be_emit_string(arch_register_get_name(reg));
68 }
69
70 static void arm_emit_source_register(const ir_node *node, int pos)
71 {
72         const arch_register_t *reg = arch_get_irn_register_in(node, pos);
73         arm_emit_register(reg);
74 }
75
76 static void arm_emit_dest_register(const ir_node *node, int pos)
77 {
78         const arch_register_t *reg = arch_get_irn_register_out(node, pos);
79         arm_emit_register(reg);
80 }
81
82 static void arm_emit_offset(const ir_node *node)
83 {
84         const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
85         assert(attr->base.is_load_store);
86
87         be_emit_irprintf("0x%X", attr->offset);
88 }
89
90 /**
91  * Emit the arm fpa instruction suffix depending on the mode.
92  */
93 static void arm_emit_fpa_postfix(const ir_mode *mode)
94 {
95         int bits = get_mode_size_bits(mode);
96         char c = 'e';
97
98         if (bits == 32)
99                 c = 's';
100         else if (bits == 64)
101                 c = 'd';
102         be_emit_char(c);
103 }
104
105 static void arm_emit_float_load_store_mode(const ir_node *node)
106 {
107         const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
108         arm_emit_fpa_postfix(attr->load_store_mode);
109 }
110
111 static void arm_emit_float_arithmetic_mode(const ir_node *node)
112 {
113         const arm_farith_attr_t *attr = get_arm_farith_attr_const(node);
114         arm_emit_fpa_postfix(attr->mode);
115 }
116
117 static void arm_emit_symconst(const ir_node *node)
118 {
119         const arm_SymConst_attr_t *symconst = get_arm_SymConst_attr_const(node);
120         ir_entity                 *entity   = symconst->entity;
121
122         be_gas_emit_entity(entity);
123
124         /* TODO do something with offset */
125 }
126
127 static void arm_emit_load_mode(const ir_node *node)
128 {
129         const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
130         ir_mode *mode      = attr->load_store_mode;
131         int      bits      = get_mode_size_bits(mode);
132         bool     is_signed = mode_is_signed(mode);
133         if (bits == 16) {
134                 be_emit_string(is_signed ? "sh" : "h");
135         } else if (bits == 8) {
136                 be_emit_string(is_signed ? "sb" : "b");
137         } else {
138                 assert(bits == 32);
139         }
140 }
141
142 static void arm_emit_store_mode(const ir_node *node)
143 {
144         const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
145         ir_mode *mode      = attr->load_store_mode;
146         int      bits      = get_mode_size_bits(mode);
147         if (bits == 16) {
148                 be_emit_cstring("h");
149         } else if (bits == 8) {
150                 be_emit_cstring("b");
151         } else {
152                 assert(bits == 32);
153         }
154 }
155
156 static void emit_shf_mod_name(arm_shift_modifier_t mod)
157 {
158         switch (mod) {
159         case ARM_SHF_ASR_REG:
160         case ARM_SHF_ASR_IMM:
161                 be_emit_cstring("asr");
162                 return;
163         case ARM_SHF_LSL_REG:
164         case ARM_SHF_LSL_IMM:
165                 be_emit_cstring("lsl");
166                 return;
167         case ARM_SHF_LSR_REG:
168         case ARM_SHF_LSR_IMM:
169                 be_emit_cstring("lsr");
170                 return;
171         case ARM_SHF_ROR_REG:
172         case ARM_SHF_ROR_IMM:
173                 be_emit_cstring("ror");
174                 return;
175         default:
176                 break;
177         }
178         panic("can't emit this shf_mod_name %d", (int) mod);
179 }
180
181 static void arm_emit_shifter_operand(const ir_node *node)
182 {
183         const arm_shifter_operand_t *attr = get_arm_shifter_operand_attr_const(node);
184
185         switch (attr->shift_modifier) {
186         case ARM_SHF_REG:
187                 arm_emit_source_register(node, get_irn_arity(node) - 1);
188                 return;
189         case ARM_SHF_IMM: {
190                 unsigned val = attr->immediate_value;
191                 val = (val >> attr->shift_immediate)
192                         | (val << (32-attr->shift_immediate));
193                 val &= 0xFFFFFFFF;
194                 be_emit_irprintf("#0x%X", val);
195                 return;
196         }
197         case ARM_SHF_ASR_IMM:
198         case ARM_SHF_LSL_IMM:
199         case ARM_SHF_LSR_IMM:
200         case ARM_SHF_ROR_IMM:
201                 arm_emit_source_register(node, get_irn_arity(node) - 1);
202                 be_emit_cstring(", ");
203                 emit_shf_mod_name(attr->shift_modifier);
204                 be_emit_irprintf(" #0x%X", attr->shift_immediate);
205                 return;
206
207         case ARM_SHF_ASR_REG:
208         case ARM_SHF_LSL_REG:
209         case ARM_SHF_LSR_REG:
210         case ARM_SHF_ROR_REG:
211                 arm_emit_source_register(node, get_irn_arity(node) - 2);
212                 be_emit_cstring(", ");
213                 emit_shf_mod_name(attr->shift_modifier);
214                 be_emit_cstring(" ");
215                 arm_emit_source_register(node, get_irn_arity(node) - 1);
216                 return;
217
218         case ARM_SHF_RRX:
219                 arm_emit_source_register(node, get_irn_arity(node) - 1);
220                 panic("RRX shifter emitter TODO");
221
222         case ARM_SHF_INVALID:
223                 break;
224         }
225         panic("Invalid shift_modifier while emitting %+F", node);
226 }
227
228 /** An entry in the sym_or_tv set. */
229 typedef struct sym_or_tv_t {
230         union {
231                 ir_entity  *entity;  /**< An entity. */
232                 ir_tarval  *tv;      /**< A tarval. */
233                 const void *generic; /**< For generic compare. */
234         } u;
235         unsigned label;      /**< the associated label. */
236         bool     is_entity;  /**< true if an entity is stored. */
237 } sym_or_tv_t;
238
239 /**
240  * Returns a unique label. This number will not be used a second time.
241  */
242 static unsigned get_unique_label(void)
243 {
244         static unsigned id = 0;
245         return ++id;
246 }
247
248 static void emit_constant_name(const sym_or_tv_t *entry)
249 {
250         be_emit_irprintf("%sC%u", be_gas_get_private_prefix(), entry->label);
251 }
252
253 /**
254  * Returns the target block for a control flow node.
255  */
256 static ir_node *get_cfop_target_block(const ir_node *irn)
257 {
258         return (ir_node*)get_irn_link(irn);
259 }
260
261 /**
262  * Emit the target label for a control flow node.
263  */
264 static void arm_emit_cfop_target(const ir_node *irn)
265 {
266         ir_node *block = get_cfop_target_block(irn);
267
268         be_gas_emit_block_name(block);
269 }
270
271 void arm_emitf(const ir_node *node, const char *format, ...)
272 {
273         va_list ap;
274         va_start(ap, format);
275         be_emit_char('\t');
276         for (;;) {
277                 const char *start = format;
278                 while (*format != '%' && *format != '\n'  && *format != '\0')
279                         ++format;
280                 be_emit_string_len(start, format - start);
281
282                 if (*format == '\0')
283                         break;
284
285                 if (*format == '\n') {
286                         ++format;
287                         be_emit_char('\n');
288                         be_emit_write_line();
289                         be_emit_char('\t');
290                         continue;
291                 }
292
293                 ++format;
294
295                 switch (*format++) {
296                 case '%':
297                         be_emit_char('%');
298                         break;
299
300                 case 'S': {
301                         if (*format < '0' || '9' <= *format)
302                                 goto unknown;
303                         unsigned const pos = *format++ - '0';
304                         arm_emit_source_register(node, pos);
305                         break;
306                 }
307
308                 case 'D': {
309                         if (*format < '0' || '9' <= *format)
310                                 goto unknown;
311                         unsigned const pos = *format++ - '0';
312                         arm_emit_dest_register(node, pos);
313                         break;
314                 }
315
316                 case 'I':
317                         arm_emit_symconst(node);
318                         break;
319
320                 case 'o':
321                         arm_emit_offset(node);
322                         break;
323
324                 case 'O':
325                         arm_emit_shifter_operand(node);
326                         break;
327
328                 case 'C': {
329                         const sym_or_tv_t *name = va_arg(ap, const sym_or_tv_t*);
330                         emit_constant_name(name);
331                         break;
332                 }
333
334                 case 'm': {
335                         ir_mode *mode = va_arg(ap, ir_mode*);
336                         arm_emit_fpa_postfix(mode);
337                         break;
338                 }
339
340                 case 'M':
341                         switch (*format++) {
342                         case 'L': arm_emit_load_mode(node);             break;
343                         case 'S': arm_emit_store_mode(node);            break;
344                         case 'A': arm_emit_float_arithmetic_mode(node); break;
345                         case 'F': arm_emit_float_load_store_mode(node); break;
346                         default:
347                                 --format;
348                                 goto unknown;
349                         }
350                         break;
351
352                 case 'X': {
353                         int num = va_arg(ap, int);
354                         be_emit_irprintf("%X", num);
355                         break;
356                 }
357
358                 case 'u': {
359                         unsigned num = va_arg(ap, unsigned);
360                         be_emit_irprintf("%u", num);
361                         break;
362                 }
363
364                 case 'd': {
365                         int num = va_arg(ap, int);
366                         be_emit_irprintf("%d", num);
367                         break;
368                 }
369
370                 case 's': {
371                         const char *string = va_arg(ap, const char *);
372                         be_emit_string(string);
373                         break;
374                 }
375
376                 case 'r': {
377                         arch_register_t *reg = va_arg(ap, arch_register_t*);
378                         arm_emit_register(reg);
379                         break;
380                 }
381
382                 case 't': {
383                         const ir_node *n = va_arg(ap, const ir_node*);
384                         arm_emit_cfop_target(n);
385                         break;
386                 }
387
388                 default:
389 unknown:
390                         panic("unknown format conversion in arm_emitf()");
391                 }
392         }
393         va_end(ap);
394         be_emit_finish_line_gas(node);
395 }
396
397 /**
398  * Emit a SymConst.
399  */
400 static void emit_arm_SymConst(const ir_node *irn)
401 {
402         const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
403         sym_or_tv_t key, *entry;
404
405         key.u.entity  = attr->entity;
406         key.is_entity = true;
407         key.label     = 0;
408         entry = set_insert(sym_or_tv_t, sym_or_tv, &key, sizeof(key), hash_ptr(key.u.generic));
409         if (entry->label == 0) {
410                 /* allocate a label */
411                 entry->label = get_unique_label();
412         }
413
414         /* load the symbol indirect */
415         arm_emitf(irn, "ldr %D0, %C", entry);
416 }
417
418 static void emit_arm_FrameAddr(const ir_node *irn)
419 {
420         const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
421         arm_emitf(irn, "add %D0, %S0, #0x%X", attr->fp_offset);
422 }
423
424 /**
425  * Emit a floating point fpa constant.
426  */
427 static void emit_arm_fConst(const ir_node *irn)
428 {
429         sym_or_tv_t key;
430
431         key.u.tv      = get_fConst_value(irn);
432         key.is_entity = false;
433         key.label     = 0;
434         sym_or_tv_t *entry = set_insert(sym_or_tv_t, sym_or_tv, &key, sizeof(key), hash_ptr(key.u.generic));
435         if (entry->label == 0) {
436                 /* allocate a label */
437                 entry->label = get_unique_label();
438         }
439
440         /* load the tarval indirect */
441         ir_mode *mode = get_irn_mode(irn);
442         arm_emitf(irn, "ldf%m %D0, %C", mode, entry);
443 }
444
445 /**
446  * Returns the next block in a block schedule.
447  */
448 static ir_node *sched_next_block(const ir_node *block)
449 {
450     return (ir_node*)get_irn_link(block);
451 }
452
453 /**
454  * Emit a Compare with conditional branch.
455  */
456 static void emit_arm_B(const ir_node *irn)
457 {
458         const ir_node *proj_true  = NULL;
459         const ir_node *proj_false = NULL;
460         const ir_node *block;
461         const ir_node *next_block;
462         ir_node *op1 = get_irn_n(irn, 0);
463         const char *suffix;
464         ir_relation relation = get_arm_CondJmp_relation(irn);
465         const arm_cmp_attr_t *cmp_attr = get_arm_cmp_attr_const(op1);
466         bool is_signed = !cmp_attr->is_unsigned;
467
468         assert(is_arm_Cmp(op1) || is_arm_Tst(op1));
469
470         foreach_out_edge(irn, edge) {
471                 ir_node *proj = get_edge_src_irn(edge);
472                 long nr = get_Proj_proj(proj);
473                 if (nr == pn_Cond_true) {
474                         proj_true = proj;
475                 } else {
476                         proj_false = proj;
477                 }
478         }
479
480         if (cmp_attr->ins_permuted) {
481                 relation = get_inversed_relation(relation);
482         }
483
484         /* for now, the code works for scheduled and non-schedules blocks */
485         block = get_nodes_block(irn);
486
487         /* we have a block schedule */
488         next_block = sched_next_block(block);
489
490         assert(relation != ir_relation_false);
491         assert(relation != ir_relation_true);
492
493         if (get_cfop_target_block(proj_true) == next_block) {
494                 /* exchange both proj's so the second one can be omitted */
495                 const ir_node *t = proj_true;
496
497                 proj_true  = proj_false;
498                 proj_false = t;
499                 relation   = get_negated_relation(relation);
500         }
501
502         switch (relation & (ir_relation_less_equal_greater)) {
503                 case ir_relation_equal:         suffix = "eq"; break;
504                 case ir_relation_less:          suffix = is_signed ? "lt" : "lo"; break;
505                 case ir_relation_less_equal:    suffix = is_signed ? "le" : "ls"; break;
506                 case ir_relation_greater:       suffix = is_signed ? "gt" : "hi"; break;
507                 case ir_relation_greater_equal: suffix = is_signed ? "ge" : "hs"; break;
508                 case ir_relation_less_greater:  suffix = "ne"; break;
509                 case ir_relation_less_equal_greater: suffix = "al"; break;
510                 default: panic("Cmp has unsupported relation");
511         }
512
513         /* emit the true proj */
514         arm_emitf(irn, "b%s %t", suffix, proj_true);
515
516         if (get_cfop_target_block(proj_false) == next_block) {
517                 if (be_options.verbose_asm) {
518                         arm_emitf(irn, "/* fallthrough to %t */", proj_false);
519                 }
520         } else {
521                 arm_emitf(irn, "b %t", proj_false);
522         }
523 }
524
525 /** Sort register in ascending order. */
526 static int reg_cmp(const void *a, const void *b)
527 {
528         const arch_register_t * const *ra = (const arch_register_t**)a;
529         const arch_register_t * const *rb = (const arch_register_t**)b;
530
531         return *ra < *rb ? -1 : (*ra != *rb);
532 }
533
534 /**
535  * Create the CopyB instruction sequence.
536  */
537 static void emit_arm_CopyB(const ir_node *irn)
538 {
539         const arm_CopyB_attr_t *attr = get_arm_CopyB_attr_const(irn);
540         unsigned size = attr->size;
541         const arch_register_t *tmpregs[4];
542
543         /* collect the temporary registers and sort them, we need ascending order */
544         tmpregs[0] = arch_get_irn_register_in(irn, 2);
545         tmpregs[1] = arch_get_irn_register_in(irn, 3);
546         tmpregs[2] = arch_get_irn_register_in(irn, 4);
547         tmpregs[3] = &arm_registers[REG_R12];
548
549         /* Note: R12 is always the last register because the RA did not assign higher ones */
550         qsort((void *)tmpregs, 3, sizeof(tmpregs[0]), reg_cmp);
551
552         if (be_options.verbose_asm) {
553                 arm_emitf(irn, "/* MemCopy (%S1)->(%S0) [%u bytes], Uses %r, %r, %r and %r */",
554                           size, tmpregs[0], tmpregs[1], tmpregs[2], tmpregs[3]);
555         }
556
557         assert(size > 0 && "CopyB needs size > 0" );
558
559         if (size & 3) {
560                 fprintf(stderr, "strange hack enabled: copy more bytes than needed!");
561                 size += 4;
562         }
563
564         size >>= 2;
565         switch (size & 3) {
566         case 0:
567                 break;
568         case 1:
569                 arm_emitf(irn, "ldr %r, [%S1, #0]", tmpregs[3]);
570                 arm_emitf(irn, "str %r, [%S0, #0]", tmpregs[3]);
571                 break;
572         case 2:
573                 arm_emitf(irn, "ldmia %S1!, {%r, %r}", tmpregs[0], tmpregs[1]);
574                 arm_emitf(irn, "stmia %S0!, {%r, %r}", tmpregs[0], tmpregs[1]);
575                 break;
576         case 3:
577                 arm_emitf(irn, "ldmia %S1!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2]);
578                 arm_emitf(irn, "stmia %S0!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2]);
579                 break;
580         }
581         size >>= 2;
582         while (size) {
583                 arm_emitf(irn, "ldmia %S1!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2], tmpregs[3]);
584                 arm_emitf(irn, "stmia %S0!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2], tmpregs[3]);
585                 --size;
586         }
587 }
588
589 static void emit_arm_SwitchJmp(const ir_node *irn)
590 {
591         const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(irn);
592         arm_emitf(irn, "ldrls pc, [pc, %S0, asl #2]");
593
594         be_emit_jump_table(irn, attr->table, NULL, get_cfop_target_block);
595 }
596
597 /** Emit an IncSP node */
598 static void emit_be_IncSP(const ir_node *irn)
599 {
600         int offs = -be_get_IncSP_offset(irn);
601
602         if (offs == 0)
603                 return;
604
605         const char *op = "add";
606         if (offs < 0) {
607                 op   = "sub";
608                 offs = -offs;
609         }
610         arm_emitf(irn, "%s %D0, %S0, #0x%X", op, offs);
611 }
612
613 static void emit_be_Copy(const ir_node *irn)
614 {
615         ir_mode *mode = get_irn_mode(irn);
616
617         if (arch_get_irn_register_in(irn, 0) == arch_get_irn_register_out(irn, 0)) {
618                 /* omitted Copy */
619                 return;
620         }
621
622         if (mode_is_float(mode)) {
623                 if (USE_FPA(isa)) {
624                         arm_emitf(irn, "mvf %D0, %S0");
625                 } else {
626                         panic("emit_be_Copy: move not supported for this mode");
627                 }
628         } else if (mode_is_data(mode)) {
629                 arm_emitf(irn, "mov %D0, %S0");
630         } else {
631                 panic("emit_be_Copy: move not supported for this mode");
632         }
633 }
634
635 static void emit_be_Perm(const ir_node *irn)
636 {
637         arm_emitf(irn,
638                 "eor %S0, %S0, %S1\n"
639                 "eor %S1, %S0, %S1\n"
640                 "eor %S0, %S0, %S1");
641 }
642
643 static void emit_be_MemPerm(const ir_node *node)
644 {
645         int i;
646         int memperm_arity;
647         int sp_change = 0;
648
649         /* TODO: this implementation is slower than necessary.
650            The longterm goal is however to avoid the memperm node completely */
651
652         memperm_arity = be_get_MemPerm_entity_arity(node);
653         if (memperm_arity > 12)
654                 panic("memperm with more than 12 inputs not supported yet");
655
656         for (i = 0; i < memperm_arity; ++i) {
657                 /* spill register */
658                 arm_emitf(node, "str r%d, [sp, #-4]!", i);
659                 sp_change += 4;
660                 /* load from entity */
661                 ir_entity *entity = be_get_MemPerm_in_entity(node, i);
662                 int        offset = get_entity_offset(entity) + sp_change;
663                 arm_emitf(node, "ldr r%d, [sp, #%d]", i, offset);
664         }
665
666         for (i = memperm_arity-1; i >= 0; --i) {
667                 /* store to new entity */
668                 ir_entity *entity = be_get_MemPerm_out_entity(node, i);
669                 int        offset = get_entity_offset(entity) + sp_change;
670                 arm_emitf(node, "str r%d, [sp, #%d]", i, offset);
671                 /* restore register */
672                 arm_emitf(node, "ldr r%d, [sp], #4", i);
673                 sp_change -= 4;
674         }
675         assert(sp_change == 0);
676 }
677
678 static void emit_be_Start(const ir_node *node)
679 {
680         ir_graph *irg        = get_irn_irg(node);
681         ir_type  *frame_type = get_irg_frame_type(irg);
682         unsigned  size       = get_type_size_bytes(frame_type);
683
684         /* allocate stackframe */
685         if (size > 0) {
686                 arm_emitf(node, "sub sp, sp, #0x%X", size);
687         }
688 }
689
690 static void emit_be_Return(const ir_node *node)
691 {
692         ir_graph *irg        = get_irn_irg(node);
693         ir_type  *frame_type = get_irg_frame_type(irg);
694         unsigned  size       = get_type_size_bytes(frame_type);
695
696         /* deallocate stackframe */
697         if (size > 0) {
698                 arm_emitf(node, "add sp, sp, #0x%X", size);
699         }
700         arm_emitf(node, "mov pc, lr");
701 }
702
703
704 static void emit_arm_Jmp(const ir_node *node)
705 {
706         ir_node *block, *next_block;
707
708         /* for now, the code works for scheduled and non-schedules blocks */
709         block = get_nodes_block(node);
710
711         /* we have a block schedule */
712         next_block = sched_next_block(block);
713         if (get_cfop_target_block(node) != next_block) {
714                 arm_emitf(node, "b %t", node);
715         } else {
716                 if (be_options.verbose_asm) {
717                         arm_emitf(node, "/* fallthrough to %t */", node);
718                 }
719         }
720 }
721
722 static void emit_nothing(const ir_node *irn)
723 {
724         (void) irn;
725 }
726
727 /**
728  * The type of a emitter function.
729  */
730 typedef void (emit_func)(const ir_node *irn);
731
732 /**
733  * Set a node emitter. Make it a bit more type safe.
734  */
735 static inline void set_emitter(ir_op *op, emit_func arm_emit_node)
736 {
737         op->ops.generic = (op_func)arm_emit_node;
738 }
739
740 /**
741  * Enters the emitter functions for handled nodes into the generic
742  * pointer of an opcode.
743  */
744 static void arm_register_emitters(void)
745 {
746         /* first clear the generic function pointer for all ops */
747         ir_clear_opcodes_generic_func();
748
749         /* register all emitter functions defined in spec */
750         arm_register_spec_emitters();
751
752         /* custom emitter */
753         set_emitter(op_arm_B,         emit_arm_B);
754         set_emitter(op_arm_CopyB,     emit_arm_CopyB);
755         set_emitter(op_arm_fConst,    emit_arm_fConst);
756         set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
757         set_emitter(op_arm_Jmp,       emit_arm_Jmp);
758         set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
759         set_emitter(op_arm_SymConst,  emit_arm_SymConst);
760         set_emitter(op_be_Copy,       emit_be_Copy);
761         set_emitter(op_be_CopyKeep,   emit_be_Copy);
762         set_emitter(op_be_IncSP,      emit_be_IncSP);
763         set_emitter(op_be_MemPerm,    emit_be_MemPerm);
764         set_emitter(op_be_Perm,       emit_be_Perm);
765         set_emitter(op_be_Return,     emit_be_Return);
766         set_emitter(op_be_Start,      emit_be_Start);
767
768         /* no need to emit anything for the following nodes */
769         set_emitter(op_Phi,           emit_nothing);
770         set_emitter(op_be_Keep,       emit_nothing);
771 }
772
773 /**
774  * Emits code for a node.
775  */
776 static void arm_emit_node(const ir_node *irn)
777 {
778         ir_op *op = get_irn_op(irn);
779
780         if (op->ops.generic) {
781                 emit_func *emit = (emit_func *)op->ops.generic;
782                 be_dwarf_location(get_irn_dbg_info(irn));
783                 (*emit)(irn);
784         } else {
785                 panic("Error: No emit handler for node %+F (graph %+F)\n",
786                       irn, get_irn_irg(irn));
787         }
788 }
789
790 /**
791  * emit the block label if needed.
792  */
793 static void arm_emit_block_header(ir_node *block, ir_node *prev)
794 {
795         bool need_label = false;
796         int  n_cfgpreds;
797
798         n_cfgpreds = get_Block_n_cfgpreds(block);
799         if (n_cfgpreds == 1) {
800                 ir_node *pred       = get_Block_cfgpred(block, 0);
801                 ir_node *pred_block = get_nodes_block(pred);
802
803                 /* we don't need labels for fallthrough blocks, however switch-jmps
804                  * are no fallthroughs */
805                 if (pred_block == prev &&
806                                 !(is_Proj(pred) && is_arm_SwitchJmp(get_Proj_pred(pred)))) {
807                         need_label = false;
808                 } else {
809                         need_label = true;
810                 }
811         } else {
812                 need_label = true;
813         }
814
815         be_gas_begin_block(block, need_label);
816 }
817
818 /**
819  * Walks over the nodes in a block connected by scheduling edges
820  * and emits code for each node.
821  */
822 static void arm_gen_block(ir_node *block, ir_node *prev_block)
823 {
824         arm_emit_block_header(block, prev_block);
825         be_dwarf_location(get_irn_dbg_info(block));
826         sched_foreach(block, irn) {
827                 arm_emit_node(irn);
828         }
829 }
830
831 /**
832  * Block-walker:
833  * Sets labels for control flow nodes (jump target)
834  */
835 static void arm_gen_labels(ir_node *block, void *env)
836 {
837         ir_node *pred;
838         int n = get_Block_n_cfgpreds(block);
839         (void)env;
840
841         for (n--; n >= 0; n--) {
842                 pred = get_Block_cfgpred(block, n);
843                 set_irn_link(pred, block);
844         }
845 }
846
847 /**
848  * Compare two entries of the symbol or tarval set.
849  */
850 static int cmp_sym_or_tv(const void *elt, const void *key, size_t size)
851 {
852         const sym_or_tv_t *p1 = (const sym_or_tv_t*)elt;
853         const sym_or_tv_t *p2 = (const sym_or_tv_t*)key;
854         (void) size;
855
856         /* as an identifier NEVER can point to a tarval, it's enough
857            to compare it this way */
858         return p1->u.generic != p2->u.generic;
859 }
860
861 void arm_gen_routine(ir_graph *irg)
862 {
863         ir_node          *last_block = NULL;
864         ir_entity        *entity     = get_irg_entity(irg);
865         const arch_env_t *arch_env   = be_get_irg_arch_env(irg);
866         ir_node          **blk_sched;
867         size_t           i, n;
868
869         isa = (arm_isa_t*) arch_env;
870         sym_or_tv = new_set(cmp_sym_or_tv, 8);
871
872         be_gas_elf_type_char = '%';
873
874         arm_register_emitters();
875
876         /* create the block schedule */
877         blk_sched = be_create_block_schedule(irg);
878
879         be_gas_emit_function_prolog(entity, 4, NULL);
880
881         irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
882
883         n = ARR_LEN(blk_sched);
884         for (i = 0; i < n;) {
885                 ir_node *block, *next_bl;
886
887                 block   = blk_sched[i];
888                 ++i;
889                 next_bl = i < n ? blk_sched[i] : NULL;
890
891                 /* set here the link. the emitter expects to find the next block here */
892                 set_irn_link(block, next_bl);
893                 arm_gen_block(block, last_block);
894                 last_block = block;
895         }
896
897         /* emit SymConst values */
898         if (set_count(sym_or_tv) > 0) {
899                 be_emit_cstring("\t.align 2\n");
900
901                 foreach_set(sym_or_tv, sym_or_tv_t, entry) {
902                         emit_constant_name(entry);
903                         be_emit_cstring(":\n");
904                         be_emit_write_line();
905
906                         if (entry->is_entity) {
907                                 be_emit_cstring("\t.word\t");
908                                 be_gas_emit_entity(entry->u.entity);
909                                 be_emit_char('\n');
910                                 be_emit_write_line();
911                         } else {
912                                 ir_tarval *tv = entry->u.tv;
913                                 int vi;
914                                 int size = get_mode_size_bytes(get_tarval_mode(tv));
915
916                                 /* beware: ARM fpa uses big endian format */
917                                 for (vi = ((size + 3) & ~3) - 4; vi >= 0; vi -= 4) {
918                                         /* get 32 bits */
919                                         unsigned v;
920                                         v =            get_tarval_sub_bits(tv, vi+3);
921                                         v = (v << 8) | get_tarval_sub_bits(tv, vi+2);
922                                         v = (v << 8) | get_tarval_sub_bits(tv, vi+1);
923                                         v = (v << 8) | get_tarval_sub_bits(tv, vi+0);
924                                         be_emit_irprintf("\t.word\t%u\n", v);
925                                         be_emit_write_line();
926                                 }
927                         }
928                 }
929                 be_emit_char('\n');
930                 be_emit_write_line();
931         }
932         del_set(sym_or_tv);
933
934         be_gas_emit_function_epilog(entity);
935 }
936
937 void arm_init_emitter(void)
938 {
939         FIRM_DBG_REGISTER(dbg, "firm.be.arm.emit");
940 }