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