c504abccdf00c0a8a5636e8e719047c024cb0663
[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 != '\0')
279                         ++format;
280                 be_emit_string_len(start, format-start);
281                 if (*format == '\0')
282                         break;
283                 ++format;
284
285                 switch (*format++) {
286                 case '%':
287                         be_emit_char('%');
288                         break;
289
290                 case 'S': {
291                         if (*format < '0' || '9' <= *format)
292                                 goto unknown;
293                         unsigned const pos = *format++ - '0';
294                         arm_emit_source_register(node, pos);
295                         break;
296                 }
297
298                 case 'D': {
299                         if (*format < '0' || '9' <= *format)
300                                 goto unknown;
301                         unsigned const pos = *format++ - '0';
302                         arm_emit_dest_register(node, pos);
303                         break;
304                 }
305
306                 case 'I':
307                         arm_emit_symconst(node);
308                         break;
309
310                 case 'o':
311                         arm_emit_offset(node);
312                         break;
313
314                 case 'O':
315                         arm_emit_shifter_operand(node);
316                         break;
317
318                 case 'C': {
319                         const sym_or_tv_t *name = va_arg(ap, const sym_or_tv_t*);
320                         emit_constant_name(name);
321                         break;
322                 }
323
324                 case 'm': {
325                         ir_mode *mode = va_arg(ap, ir_mode*);
326                         arm_emit_fpa_postfix(mode);
327                         break;
328                 }
329
330                 case 'M':
331                         switch (*format++) {
332                         case 'L': arm_emit_load_mode(node);             break;
333                         case 'S': arm_emit_store_mode(node);            break;
334                         case 'A': arm_emit_float_arithmetic_mode(node); break;
335                         case 'F': arm_emit_float_load_store_mode(node); break;
336                         default:
337                                 --format;
338                                 goto unknown;
339                         }
340                         break;
341
342                 case 'X': {
343                         int num = va_arg(ap, int);
344                         be_emit_irprintf("%X", num);
345                         break;
346                 }
347
348                 case 'u': {
349                         unsigned num = va_arg(ap, unsigned);
350                         be_emit_irprintf("%u", num);
351                         break;
352                 }
353
354                 case 'd': {
355                         int num = va_arg(ap, int);
356                         be_emit_irprintf("%d", num);
357                         break;
358                 }
359
360                 case 's': {
361                         const char *string = va_arg(ap, const char *);
362                         be_emit_string(string);
363                         break;
364                 }
365
366                 case 'r': {
367                         arch_register_t *reg = va_arg(ap, arch_register_t*);
368                         arm_emit_register(reg);
369                         break;
370                 }
371
372                 case 't': {
373                         const ir_node *n = va_arg(ap, const ir_node*);
374                         arm_emit_cfop_target(n);
375                         break;
376                 }
377
378                 case '\n':
379                         be_emit_char('\n');
380                         be_emit_write_line();
381                         be_emit_char('\t');
382                         break;
383
384                 default:
385 unknown:
386                         panic("unknown format conversion in arm_emitf()");
387                 }
388         }
389         va_end(ap);
390         be_emit_finish_line_gas(node);
391 }
392
393 /**
394  * Emit a SymConst.
395  */
396 static void emit_arm_SymConst(const ir_node *irn)
397 {
398         const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
399         sym_or_tv_t key, *entry;
400
401         key.u.entity  = attr->entity;
402         key.is_entity = true;
403         key.label     = 0;
404         entry = set_insert(sym_or_tv_t, sym_or_tv, &key, sizeof(key), hash_ptr(key.u.generic));
405         if (entry->label == 0) {
406                 /* allocate a label */
407                 entry->label = get_unique_label();
408         }
409
410         /* load the symbol indirect */
411         arm_emitf(irn, "ldr %D0, %C", entry);
412 }
413
414 static void emit_arm_FrameAddr(const ir_node *irn)
415 {
416         const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
417         arm_emitf(irn, "add %D0, %S0, #0x%X", attr->fp_offset);
418 }
419
420 /**
421  * Emit a floating point fpa constant.
422  */
423 static void emit_arm_fConst(const ir_node *irn)
424 {
425         sym_or_tv_t key;
426
427         key.u.tv      = get_fConst_value(irn);
428         key.is_entity = false;
429         key.label     = 0;
430         sym_or_tv_t *entry = set_insert(sym_or_tv_t, sym_or_tv, &key, sizeof(key), hash_ptr(key.u.generic));
431         if (entry->label == 0) {
432                 /* allocate a label */
433                 entry->label = get_unique_label();
434         }
435
436         /* load the tarval indirect */
437         ir_mode *mode = get_irn_mode(irn);
438         arm_emitf(irn, "ldf%m %D0, %C", mode, entry);
439 }
440
441 /**
442  * Returns the next block in a block schedule.
443  */
444 static ir_node *sched_next_block(const ir_node *block)
445 {
446     return (ir_node*)get_irn_link(block);
447 }
448
449 /**
450  * Emit a Compare with conditional branch.
451  */
452 static void emit_arm_B(const ir_node *irn)
453 {
454         const ir_node *proj_true  = NULL;
455         const ir_node *proj_false = NULL;
456         const ir_node *block;
457         const ir_node *next_block;
458         ir_node *op1 = get_irn_n(irn, 0);
459         const char *suffix;
460         ir_relation relation = get_arm_CondJmp_relation(irn);
461         const arm_cmp_attr_t *cmp_attr = get_arm_cmp_attr_const(op1);
462         bool is_signed = !cmp_attr->is_unsigned;
463
464         assert(is_arm_Cmp(op1) || is_arm_Tst(op1));
465
466         foreach_out_edge(irn, edge) {
467                 ir_node *proj = get_edge_src_irn(edge);
468                 long nr = get_Proj_proj(proj);
469                 if (nr == pn_Cond_true) {
470                         proj_true = proj;
471                 } else {
472                         proj_false = proj;
473                 }
474         }
475
476         if (cmp_attr->ins_permuted) {
477                 relation = get_inversed_relation(relation);
478         }
479
480         /* for now, the code works for scheduled and non-schedules blocks */
481         block = get_nodes_block(irn);
482
483         /* we have a block schedule */
484         next_block = sched_next_block(block);
485
486         assert(relation != ir_relation_false);
487         assert(relation != ir_relation_true);
488
489         if (get_cfop_target_block(proj_true) == next_block) {
490                 /* exchange both proj's so the second one can be omitted */
491                 const ir_node *t = proj_true;
492
493                 proj_true  = proj_false;
494                 proj_false = t;
495                 relation   = get_negated_relation(relation);
496         }
497
498         switch (relation & (ir_relation_less_equal_greater)) {
499                 case ir_relation_equal:         suffix = "eq"; break;
500                 case ir_relation_less:          suffix = is_signed ? "lt" : "lo"; break;
501                 case ir_relation_less_equal:    suffix = is_signed ? "le" : "ls"; break;
502                 case ir_relation_greater:       suffix = is_signed ? "gt" : "hi"; break;
503                 case ir_relation_greater_equal: suffix = is_signed ? "ge" : "hs"; break;
504                 case ir_relation_less_greater:  suffix = "ne"; break;
505                 case ir_relation_less_equal_greater: suffix = "al"; break;
506                 default: panic("Cmp has unsupported relation");
507         }
508
509         /* emit the true proj */
510         arm_emitf(irn, "b%s %t", suffix, proj_true);
511
512         if (get_cfop_target_block(proj_false) == next_block) {
513                 if (be_options.verbose_asm) {
514                         arm_emitf(irn, "/* fallthrough to %t */", proj_false);
515                 }
516         } else {
517                 arm_emitf(irn, "b %t", proj_false);
518         }
519 }
520
521 /** Sort register in ascending order. */
522 static int reg_cmp(const void *a, const void *b)
523 {
524         const arch_register_t * const *ra = (const arch_register_t**)a;
525         const arch_register_t * const *rb = (const arch_register_t**)b;
526
527         return *ra < *rb ? -1 : (*ra != *rb);
528 }
529
530 /**
531  * Create the CopyB instruction sequence.
532  */
533 static void emit_arm_CopyB(const ir_node *irn)
534 {
535         const arm_CopyB_attr_t *attr = get_arm_CopyB_attr_const(irn);
536         unsigned size = attr->size;
537         const arch_register_t *tmpregs[4];
538
539         /* collect the temporary registers and sort them, we need ascending order */
540         tmpregs[0] = arch_get_irn_register_in(irn, 2);
541         tmpregs[1] = arch_get_irn_register_in(irn, 3);
542         tmpregs[2] = arch_get_irn_register_in(irn, 4);
543         tmpregs[3] = &arm_registers[REG_R12];
544
545         /* Note: R12 is always the last register because the RA did not assign higher ones */
546         qsort((void *)tmpregs, 3, sizeof(tmpregs[0]), reg_cmp);
547
548         if (be_options.verbose_asm) {
549                 arm_emitf(irn, "/* MemCopy (%S1)->(%S0) [%u bytes], Uses %r, %r, %r and %r */",
550                           size, tmpregs[0], tmpregs[1], tmpregs[2], tmpregs[3]);
551         }
552
553         assert(size > 0 && "CopyB needs size > 0" );
554
555         if (size & 3) {
556                 fprintf(stderr, "strange hack enabled: copy more bytes than needed!");
557                 size += 4;
558         }
559
560         size >>= 2;
561         switch (size & 3) {
562         case 0:
563                 break;
564         case 1:
565                 arm_emitf(irn, "ldr %r, [%S1, #0]", tmpregs[3]);
566                 arm_emitf(irn, "str %r, [%S0, #0]", tmpregs[3]);
567                 break;
568         case 2:
569                 arm_emitf(irn, "ldmia %S1!, {%r, %r}", tmpregs[0], tmpregs[1]);
570                 arm_emitf(irn, "stmia %S0!, {%r, %r}", tmpregs[0], tmpregs[1]);
571                 break;
572         case 3:
573                 arm_emitf(irn, "ldmia %S1!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2]);
574                 arm_emitf(irn, "stmia %S0!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2]);
575                 break;
576         }
577         size >>= 2;
578         while (size) {
579                 arm_emitf(irn, "ldmia %S1!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2], tmpregs[3]);
580                 arm_emitf(irn, "stmia %S0!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2], tmpregs[3]);
581                 --size;
582         }
583 }
584
585 static void emit_arm_SwitchJmp(const ir_node *irn)
586 {
587         const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(irn);
588         arm_emitf(irn, "ldrls pc, [pc, %S0, asl #2]");
589
590         be_emit_jump_table(irn, attr->table, NULL, get_cfop_target_block);
591 }
592
593 /** Emit an IncSP node */
594 static void emit_be_IncSP(const ir_node *irn)
595 {
596         int offs = -be_get_IncSP_offset(irn);
597
598         if (offs == 0)
599                 return;
600
601         const char *op = "add";
602         if (offs < 0) {
603                 op   = "sub";
604                 offs = -offs;
605         }
606         arm_emitf(irn, "%s %D0, %S0, #0x%X", op, offs);
607 }
608
609 static void emit_be_Copy(const ir_node *irn)
610 {
611         ir_mode *mode = get_irn_mode(irn);
612
613         if (arch_get_irn_register_in(irn, 0) == arch_get_irn_register_out(irn, 0)) {
614                 /* omitted Copy */
615                 return;
616         }
617
618         if (mode_is_float(mode)) {
619                 if (USE_FPA(isa)) {
620                         arm_emitf(irn, "mvf %D0, %S0");
621                 } else {
622                         panic("emit_be_Copy: move not supported for this mode");
623                 }
624         } else if (mode_is_data(mode)) {
625                 arm_emitf(irn, "mov %D0, %S0");
626         } else {
627                 panic("emit_be_Copy: move not supported for this mode");
628         }
629 }
630
631 static void emit_be_Perm(const ir_node *irn)
632 {
633         arm_emitf(irn,
634                 "eor %S0, %S0, %S1\n"
635                 "eor %S1, %S0, %S1\n"
636                 "eor %S0, %S0, %S1");
637 }
638
639 static void emit_be_MemPerm(const ir_node *node)
640 {
641         int i;
642         int memperm_arity;
643         int sp_change = 0;
644
645         /* TODO: this implementation is slower than necessary.
646            The longterm goal is however to avoid the memperm node completely */
647
648         memperm_arity = be_get_MemPerm_entity_arity(node);
649         if (memperm_arity > 12)
650                 panic("memperm with more than 12 inputs not supported yet");
651
652         for (i = 0; i < memperm_arity; ++i) {
653                 /* spill register */
654                 arm_emitf(node, "str r%d, [sp, #-4]!", i);
655                 sp_change += 4;
656                 /* load from entity */
657                 ir_entity *entity = be_get_MemPerm_in_entity(node, i);
658                 int        offset = get_entity_offset(entity) + sp_change;
659                 arm_emitf(node, "ldr r%d, [sp, #%d]", i, offset);
660         }
661
662         for (i = memperm_arity-1; i >= 0; --i) {
663                 /* store to new entity */
664                 ir_entity *entity = be_get_MemPerm_out_entity(node, i);
665                 int        offset = get_entity_offset(entity) + sp_change;
666                 arm_emitf(node, "str r%d, [sp, #%d]", i, offset);
667                 /* restore register */
668                 arm_emitf(node, "ldr r%d, [sp], #4", i);
669                 sp_change -= 4;
670         }
671         assert(sp_change == 0);
672 }
673
674 static void emit_be_Start(const ir_node *node)
675 {
676         ir_graph *irg        = get_irn_irg(node);
677         ir_type  *frame_type = get_irg_frame_type(irg);
678         unsigned  size       = get_type_size_bytes(frame_type);
679
680         /* allocate stackframe */
681         if (size > 0) {
682                 arm_emitf(node, "sub sp, sp, #0x%X", size);
683         }
684 }
685
686 static void emit_be_Return(const ir_node *node)
687 {
688         ir_graph *irg        = get_irn_irg(node);
689         ir_type  *frame_type = get_irg_frame_type(irg);
690         unsigned  size       = get_type_size_bytes(frame_type);
691
692         /* deallocate stackframe */
693         if (size > 0) {
694                 arm_emitf(node, "add sp, sp, #0x%X", size);
695         }
696         arm_emitf(node, "mov pc, lr");
697 }
698
699
700 static void emit_arm_Jmp(const ir_node *node)
701 {
702         ir_node *block, *next_block;
703
704         /* for now, the code works for scheduled and non-schedules blocks */
705         block = get_nodes_block(node);
706
707         /* we have a block schedule */
708         next_block = sched_next_block(block);
709         if (get_cfop_target_block(node) != next_block) {
710                 arm_emitf(node, "b %t", node);
711         } else {
712                 if (be_options.verbose_asm) {
713                         arm_emitf(node, "/* fallthrough to %t */", node);
714                 }
715         }
716 }
717
718 static void emit_nothing(const ir_node *irn)
719 {
720         (void) irn;
721 }
722
723 /**
724  * The type of a emitter function.
725  */
726 typedef void (emit_func)(const ir_node *irn);
727
728 /**
729  * Set a node emitter. Make it a bit more type safe.
730  */
731 static inline void set_emitter(ir_op *op, emit_func arm_emit_node)
732 {
733         op->ops.generic = (op_func)arm_emit_node;
734 }
735
736 /**
737  * Enters the emitter functions for handled nodes into the generic
738  * pointer of an opcode.
739  */
740 static void arm_register_emitters(void)
741 {
742         /* first clear the generic function pointer for all ops */
743         ir_clear_opcodes_generic_func();
744
745         /* register all emitter functions defined in spec */
746         arm_register_spec_emitters();
747
748         /* custom emitter */
749         set_emitter(op_arm_B,         emit_arm_B);
750         set_emitter(op_arm_CopyB,     emit_arm_CopyB);
751         set_emitter(op_arm_fConst,    emit_arm_fConst);
752         set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
753         set_emitter(op_arm_Jmp,       emit_arm_Jmp);
754         set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
755         set_emitter(op_arm_SymConst,  emit_arm_SymConst);
756         set_emitter(op_be_Copy,       emit_be_Copy);
757         set_emitter(op_be_CopyKeep,   emit_be_Copy);
758         set_emitter(op_be_IncSP,      emit_be_IncSP);
759         set_emitter(op_be_MemPerm,    emit_be_MemPerm);
760         set_emitter(op_be_Perm,       emit_be_Perm);
761         set_emitter(op_be_Return,     emit_be_Return);
762         set_emitter(op_be_Start,      emit_be_Start);
763
764         /* no need to emit anything for the following nodes */
765         set_emitter(op_Phi,           emit_nothing);
766         set_emitter(op_be_Keep,       emit_nothing);
767 }
768
769 /**
770  * Emits code for a node.
771  */
772 static void arm_emit_node(const ir_node *irn)
773 {
774         ir_op *op = get_irn_op(irn);
775
776         if (op->ops.generic) {
777                 emit_func *emit = (emit_func *)op->ops.generic;
778                 be_dwarf_location(get_irn_dbg_info(irn));
779                 (*emit)(irn);
780         } else {
781                 panic("Error: No emit handler for node %+F (graph %+F)\n",
782                       irn, get_irn_irg(irn));
783         }
784 }
785
786 /**
787  * emit the block label if needed.
788  */
789 static void arm_emit_block_header(ir_node *block, ir_node *prev)
790 {
791         bool need_label = false;
792         int  n_cfgpreds;
793
794         n_cfgpreds = get_Block_n_cfgpreds(block);
795         if (n_cfgpreds == 1) {
796                 ir_node *pred       = get_Block_cfgpred(block, 0);
797                 ir_node *pred_block = get_nodes_block(pred);
798
799                 /* we don't need labels for fallthrough blocks, however switch-jmps
800                  * are no fallthroughs */
801                 if (pred_block == prev &&
802                                 !(is_Proj(pred) && is_arm_SwitchJmp(get_Proj_pred(pred)))) {
803                         need_label = false;
804                 } else {
805                         need_label = true;
806                 }
807         } else {
808                 need_label = true;
809         }
810
811         be_gas_begin_block(block, need_label);
812 }
813
814 /**
815  * Walks over the nodes in a block connected by scheduling edges
816  * and emits code for each node.
817  */
818 static void arm_gen_block(ir_node *block, ir_node *prev_block)
819 {
820         arm_emit_block_header(block, prev_block);
821         be_dwarf_location(get_irn_dbg_info(block));
822         sched_foreach(block, irn) {
823                 arm_emit_node(irn);
824         }
825 }
826
827 /**
828  * Block-walker:
829  * Sets labels for control flow nodes (jump target)
830  */
831 static void arm_gen_labels(ir_node *block, void *env)
832 {
833         ir_node *pred;
834         int n = get_Block_n_cfgpreds(block);
835         (void)env;
836
837         for (n--; n >= 0; n--) {
838                 pred = get_Block_cfgpred(block, n);
839                 set_irn_link(pred, block);
840         }
841 }
842
843 /**
844  * Compare two entries of the symbol or tarval set.
845  */
846 static int cmp_sym_or_tv(const void *elt, const void *key, size_t size)
847 {
848         const sym_or_tv_t *p1 = (const sym_or_tv_t*)elt;
849         const sym_or_tv_t *p2 = (const sym_or_tv_t*)key;
850         (void) size;
851
852         /* as an identifier NEVER can point to a tarval, it's enough
853            to compare it this way */
854         return p1->u.generic != p2->u.generic;
855 }
856
857 void arm_gen_routine(ir_graph *irg)
858 {
859         ir_node          *last_block = NULL;
860         ir_entity        *entity     = get_irg_entity(irg);
861         const arch_env_t *arch_env   = be_get_irg_arch_env(irg);
862         ir_node          **blk_sched;
863         size_t           i, n;
864
865         isa = (arm_isa_t*) arch_env;
866         sym_or_tv = new_set(cmp_sym_or_tv, 8);
867
868         be_gas_elf_type_char = '%';
869
870         arm_register_emitters();
871
872         /* create the block schedule */
873         blk_sched = be_create_block_schedule(irg);
874
875         be_gas_emit_function_prolog(entity, 4, NULL);
876
877         irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
878
879         n = ARR_LEN(blk_sched);
880         for (i = 0; i < n;) {
881                 ir_node *block, *next_bl;
882
883                 block   = blk_sched[i];
884                 ++i;
885                 next_bl = i < n ? blk_sched[i] : NULL;
886
887                 /* set here the link. the emitter expects to find the next block here */
888                 set_irn_link(block, next_bl);
889                 arm_gen_block(block, last_block);
890                 last_block = block;
891         }
892
893         /* emit SymConst values */
894         if (set_count(sym_or_tv) > 0) {
895                 be_emit_cstring("\t.align 2\n");
896
897                 foreach_set(sym_or_tv, sym_or_tv_t, entry) {
898                         emit_constant_name(entry);
899                         be_emit_cstring(":\n");
900                         be_emit_write_line();
901
902                         if (entry->is_entity) {
903                                 be_emit_cstring("\t.word\t");
904                                 be_gas_emit_entity(entry->u.entity);
905                                 be_emit_char('\n');
906                                 be_emit_write_line();
907                         } else {
908                                 ir_tarval *tv = entry->u.tv;
909                                 int vi;
910                                 int size = get_mode_size_bytes(get_tarval_mode(tv));
911
912                                 /* beware: ARM fpa uses big endian format */
913                                 for (vi = ((size + 3) & ~3) - 4; vi >= 0; vi -= 4) {
914                                         /* get 32 bits */
915                                         unsigned v;
916                                         v =            get_tarval_sub_bits(tv, vi+3);
917                                         v = (v << 8) | get_tarval_sub_bits(tv, vi+2);
918                                         v = (v << 8) | get_tarval_sub_bits(tv, vi+1);
919                                         v = (v << 8) | get_tarval_sub_bits(tv, vi+0);
920                                         be_emit_irprintf("\t.word\t%u\n", v);
921                                         be_emit_write_line();
922                                 }
923                         }
924                 }
925                 be_emit_char('\n');
926                 be_emit_write_line();
927         }
928         del_set(sym_or_tv);
929
930         be_gas_emit_function_epilog(entity);
931 }
932
933 void arm_init_emitter(void)
934 {
935         FIRM_DBG_REGISTER(dbg, "firm.be.arm.emit");
936 }