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