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