arm: implement calling conventions for float and double parameter
[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  * @version $Id$
25  */
26 #include "config.h"
27
28 #include <limits.h>
29 #include <stdbool.h>
30
31 #include "xmalloc.h"
32 #include "tv.h"
33 #include "iredges.h"
34 #include "debug.h"
35 #include "irgwalk.h"
36 #include "irtools.h"
37 #include "irprintf.h"
38 #include "irop_t.h"
39 #include "irprog_t.h"
40 #include "irargs_t.h"
41 #include "error.h"
42 #include "raw_bitset.h"
43 #include "dbginfo.h"
44
45 #include "../besched.h"
46 #include "../beblocksched.h"
47 #include "../beirg.h"
48 #include "../begnuas.h"
49 #include "../be_dbgout.h"
50
51 #include "arm_emitter.h"
52 #include "arm_optimize.h"
53 #include "gen_arm_emitter.h"
54 #include "arm_nodes_attr.h"
55 #include "arm_new_nodes.h"
56 #include "arm_map_regs.h"
57 #include "gen_arm_regalloc_if.h"
58
59 #include "../benode.h"
60
61 #define SNPRINTF_BUF_LEN 128
62
63 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
64
65 static const arm_code_gen_t *cg;
66 static set                  *sym_or_tv;
67
68 /**
69  * Returns the register at in position pos.
70  */
71 static const arch_register_t *get_in_reg(const ir_node *irn, int pos)
72 {
73         ir_node                *op;
74         const arch_register_t  *reg = NULL;
75
76         assert(get_irn_arity(irn) > pos && "Invalid IN position");
77
78         /* The out register of the operator at position pos is the
79            in register we need. */
80         op = get_irn_n(irn, pos);
81
82         reg = arch_get_irn_register(op);
83
84         assert(reg && "no in register found");
85
86         /* in case of a joker register: just return a valid register */
87         if (arch_register_type_is(reg, joker)) {
88                 const arch_register_req_t *req = arch_get_register_req(irn, pos);
89
90                 if (arch_register_req_is(req, limited)) {
91                         /* in case of limited requirements: get the first allowed register */
92                         unsigned idx = rbitset_next(req->limited, 0, 1);
93                         reg = arch_register_for_index(req->cls, idx);
94                 } else {
95                         /* otherwise get first register in class */
96                         reg = arch_register_for_index(req->cls, 0);
97                 }
98         }
99         return reg;
100 }
101
102
103 /**
104  * Returns the register at out position pos.
105  */
106 static const arch_register_t *get_out_reg(const ir_node *node, int pos)
107 {
108     ir_node                *proj;
109     const arch_register_t  *reg = NULL;
110
111     /* 1st case: irn is not of mode_T, so it has only                 */
112     /*           one OUT register -> good                             */
113     /* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
114     /*           Proj with the corresponding projnum for the register */
115
116     if (get_irn_mode(node) != mode_T) {
117         reg = arch_get_irn_register(node);
118     } else if (is_arm_irn(node)) {
119         reg = arch_irn_get_register(node, pos);
120     } else {
121         const ir_edge_t *edge;
122
123         foreach_out_edge(node, edge) {
124             proj = get_edge_src_irn(edge);
125             assert(is_Proj(proj) && "non-Proj from mode_T node");
126             if (get_Proj_proj(proj) == pos) {
127                 reg = arch_get_irn_register(proj);
128                 break;
129             }
130         }
131     }
132
133     assert(reg && "no out register found");
134     return reg;
135 }
136
137 void arm_emit_source_register(const ir_node *node, int pos)
138 {
139         const arch_register_t *reg = get_in_reg(node, pos);
140         be_emit_string(arch_register_get_name(reg));
141 }
142
143 void arm_emit_dest_register(const ir_node *node, int pos)
144 {
145         const arch_register_t *reg = get_out_reg(node, pos);
146         be_emit_string(arch_register_get_name(reg));
147 }
148
149 void arm_emit_offset(const ir_node *node)
150 {
151         const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
152         assert(attr->base.is_load_store);
153
154         be_emit_irprintf("0x%X", attr->offset);
155 }
156
157 /**
158  * Emit the arm fpa instruction suffix depending on the mode.
159  */
160 static void arm_emit_fpa_postfix(const ir_mode *mode)
161 {
162         int bits = get_mode_size_bits(mode);
163         char c = 'e';
164
165         if (bits == 32)
166                 c = 's';
167         else if (bits == 64)
168                 c = 'd';
169         be_emit_char(c);
170 }
171
172 void arm_emit_float_load_store_mode(const ir_node *node)
173 {
174         const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
175         arm_emit_fpa_postfix(attr->load_store_mode);
176 }
177
178 void arm_emit_float_arithmetic_mode(const ir_node *node)
179 {
180         const arm_farith_attr_t *attr = get_arm_farith_attr_const(node);
181         arm_emit_fpa_postfix(attr->mode);
182 }
183
184 void arm_emit_symconst(const ir_node *node)
185 {
186         const arm_SymConst_attr_t *symconst = get_arm_SymConst_attr_const(node);
187         ir_entity                 *entity   = symconst->entity;
188
189         be_gas_emit_entity(entity);
190
191         /* TODO do something with offset */
192 }
193
194 void arm_emit_load_mode(const ir_node *node)
195 {
196         const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
197         ir_mode *mode      = attr->load_store_mode;
198         int      bits      = get_mode_size_bits(mode);
199         bool     is_signed = mode_is_signed(mode);
200         if (bits == 16) {
201                 be_emit_string(is_signed ? "sh" : "h");
202         } else if (bits == 8) {
203                 be_emit_string(is_signed ? "sb" : "b");
204         } else {
205                 assert(bits == 32);
206         }
207 }
208
209 void arm_emit_store_mode(const ir_node *node)
210 {
211         const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
212         ir_mode *mode      = attr->load_store_mode;
213         int      bits      = get_mode_size_bits(mode);
214         if (bits == 16) {
215                 be_emit_cstring("h");
216         } else if (bits == 8) {
217                 be_emit_cstring("b");
218         } else {
219                 assert(bits == 32);
220         }
221 }
222
223
224 static void emit_shf_mod_name(arm_shift_modifier_t mod)
225 {
226         switch (mod) {
227         case ARM_SHF_ASR_REG:
228         case ARM_SHF_ASR_IMM:
229                 be_emit_cstring("asr");
230                 return;
231         case ARM_SHF_LSL_REG:
232         case ARM_SHF_LSL_IMM:
233                 be_emit_cstring("lsl");
234                 return;
235         case ARM_SHF_LSR_REG:
236         case ARM_SHF_LSR_IMM:
237                 be_emit_cstring("lsr");
238                 return;
239         case ARM_SHF_ROR_REG:
240         case ARM_SHF_ROR_IMM:
241                 be_emit_cstring("ror");
242                 return;
243         default:
244                 break;
245         }
246         panic("can't emit this shf_mod_name %d", (int) mod);
247 }
248
249 void arm_emit_shifter_operand(const ir_node *node)
250 {
251         const arm_shifter_operand_t *attr = get_irn_generic_attr_const(node);
252
253         switch (attr->shift_modifier) {
254         case ARM_SHF_REG:
255                 arm_emit_source_register(node, get_irn_arity(node) - 1);
256                 return;
257         case ARM_SHF_IMM: {
258                 unsigned val = attr->immediate_value;
259                 val = (val >> attr->shift_immediate)
260                         | (val << (32-attr->shift_immediate));
261                 val &= 0xFFFFFFFF;
262                 be_emit_irprintf("#0x%X", val);
263                 return;
264         }
265         case ARM_SHF_ASR_IMM:
266         case ARM_SHF_LSL_IMM:
267         case ARM_SHF_LSR_IMM:
268         case ARM_SHF_ROR_IMM:
269                 arm_emit_source_register(node, get_irn_arity(node) - 1);
270                 be_emit_cstring(", ");
271                 emit_shf_mod_name(attr->shift_modifier);
272                 be_emit_irprintf(" #0x%X", attr->shift_immediate);
273                 return;
274
275         case ARM_SHF_ASR_REG:
276         case ARM_SHF_LSL_REG:
277         case ARM_SHF_LSR_REG:
278         case ARM_SHF_ROR_REG:
279                 arm_emit_source_register(node, get_irn_arity(node) - 2);
280                 be_emit_cstring(", ");
281                 emit_shf_mod_name(attr->shift_modifier);
282                 be_emit_cstring(" ");
283                 arm_emit_source_register(node, get_irn_arity(node) - 1);
284                 return;
285
286         case ARM_SHF_RRX:
287                 arm_emit_source_register(node, get_irn_arity(node) - 1);
288                 panic("RRX shifter emitter TODO");
289
290         case ARM_SHF_INVALID:
291                 break;
292         }
293         panic("Invalid shift_modifier while emitting %+F", node);
294 }
295
296 /** An entry in the sym_or_tv set. */
297 typedef struct sym_or_tv_t {
298         union {
299                 ir_entity  *entity;  /**< An entity. */
300                 tarval     *tv;      /**< A tarval. */
301                 const void *generic; /**< For generic compare. */
302         } u;
303         unsigned label;      /**< the associated label. */
304         bool     is_entity;  /**< true if an entity is stored. */
305 } sym_or_tv_t;
306
307 /**
308  * Returns a unique label. This number will not be used a second time.
309  */
310 static unsigned get_unique_label(void)
311 {
312         static unsigned id = 0;
313         return ++id;
314 }
315
316 static void emit_constant_name(const sym_or_tv_t *entry)
317 {
318         be_emit_irprintf("%sC%u", be_gas_get_private_prefix(), entry->label);
319 }
320
321 /**
322  * Emit a SymConst.
323  */
324 static void emit_arm_SymConst(const ir_node *irn)
325 {
326         const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
327         sym_or_tv_t key, *entry;
328         unsigned label;
329
330         key.u.entity  = attr->entity;
331         key.is_entity = true;
332         key.label     = 0;
333         entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
334         if (entry->label == 0) {
335                 /* allocate a label */
336                 entry->label = get_unique_label();
337         }
338         label = entry->label;
339
340         /* load the symbol indirect */
341         be_emit_cstring("\tldr ");
342         arm_emit_dest_register(irn, 0);
343         be_emit_cstring(", ");
344         emit_constant_name(entry);
345         be_emit_finish_line_gas(irn);
346 }
347
348 static void emit_arm_FrameAddr(const ir_node *irn)
349 {
350         const arm_SymConst_attr_t *attr = get_irn_generic_attr_const(irn);
351
352         be_emit_cstring("\tadd ");
353         arm_emit_dest_register(irn, 0);
354         be_emit_cstring(", ");
355         arm_emit_source_register(irn, 0);
356         be_emit_cstring(", ");
357         be_emit_irprintf("#0x%X", attr->fp_offset);
358         be_emit_finish_line_gas(irn);
359 }
360
361 /**
362  * Emit a floating point fpa constant.
363  */
364 static void emit_arm_fConst(const ir_node *irn)
365 {
366         sym_or_tv_t key, *entry;
367         unsigned label;
368         ir_mode *mode;
369
370         key.u.tv      = get_fConst_value(irn);
371         key.is_entity = false;
372         key.label     = 0;
373         entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
374         if (entry->label == 0) {
375                 /* allocate a label */
376                 entry->label = get_unique_label();
377         }
378         label = entry->label;
379
380         /* load the tarval indirect */
381         mode = get_irn_mode(irn);
382         be_emit_cstring("\tldf");
383         arm_emit_fpa_postfix(mode);
384         be_emit_char(' ');
385
386         arm_emit_dest_register(irn, 0);
387         be_emit_cstring(", ");
388         emit_constant_name(entry);
389         be_emit_finish_line_gas(irn);
390 }
391
392 /**
393  * Returns the next block in a block schedule.
394  */
395 static ir_node *sched_next_block(const ir_node *block)
396 {
397     return get_irn_link(block);
398 }
399
400 /**
401  * Returns the target block for a control flow node.
402  */
403 static ir_node *get_cfop_target_block(const ir_node *irn)
404 {
405         return get_irn_link(irn);
406 }
407
408 /**
409  * Emit the target label for a control flow node.
410  */
411 static void arm_emit_cfop_target(const ir_node *irn)
412 {
413         ir_node *block = get_cfop_target_block(irn);
414
415         be_gas_emit_block_name(block);
416 }
417
418 /**
419  * Emit a Compare with conditional branch.
420  */
421 static void emit_arm_B(const ir_node *irn)
422 {
423         const ir_edge_t *edge;
424         const ir_node *proj_true  = NULL;
425         const ir_node *proj_false = NULL;
426         const ir_node *block;
427         const ir_node *next_block;
428         ir_node *op1 = get_irn_n(irn, 0);
429         const char *suffix;
430         pn_Cmp pnc = get_arm_CondJmp_pnc(irn);
431         const arm_cmp_attr_t *cmp_attr = get_irn_generic_attr_const(op1);
432         bool is_signed = !cmp_attr->is_unsigned;
433
434         assert(is_arm_Cmp(op1) || is_arm_Tst(op1));
435
436         foreach_out_edge(irn, edge) {
437                 ir_node *proj = get_edge_src_irn(edge);
438                 long nr = get_Proj_proj(proj);
439                 if (nr == pn_Cond_true) {
440                         proj_true = proj;
441                 } else {
442                         proj_false = proj;
443                 }
444         }
445
446         if (cmp_attr->ins_permuted) {
447                 pnc = get_mirrored_pnc(pnc);
448         }
449
450         /* for now, the code works for scheduled and non-schedules blocks */
451         block = get_nodes_block(irn);
452
453         /* we have a block schedule */
454         next_block = sched_next_block(block);
455
456         assert(pnc != pn_Cmp_False);
457         assert(pnc != pn_Cmp_True);
458
459         if (get_cfop_target_block(proj_true) == next_block) {
460                 /* exchange both proj's so the second one can be omitted */
461                 const ir_node *t = proj_true;
462
463                 proj_true  = proj_false;
464                 proj_false = t;
465                 pnc        = get_negated_pnc(pnc, mode_Iu);
466         }
467
468         switch (pnc) {
469                 case pn_Cmp_Eq:  suffix = "eq"; break;
470                 case pn_Cmp_Lt:  suffix = is_signed ? "lt" : "lo"; break;
471                 case pn_Cmp_Le:  suffix = is_signed ? "le" : "ls"; break;
472                 case pn_Cmp_Gt:  suffix = is_signed ? "gt" : "hi"; break;
473                 case pn_Cmp_Ge:  suffix = is_signed ? "ge" : "hs"; break;
474                 case pn_Cmp_Lg:  suffix = "ne"; break;
475                 case pn_Cmp_Leg: suffix = "al"; break;
476                 default: panic("Cmp has unsupported pnc");
477         }
478
479         /* emit the true proj */
480         be_emit_irprintf("\tb%s ", suffix);
481         arm_emit_cfop_target(proj_true);
482         be_emit_finish_line_gas(proj_true);
483
484         if (get_cfop_target_block(proj_false) == next_block) {
485                 be_emit_cstring("\t/* fallthrough to ");
486                 arm_emit_cfop_target(proj_false);
487                 be_emit_cstring(" */");
488                 be_emit_finish_line_gas(proj_false);
489         } else {
490                 be_emit_cstring("\tb ");
491                 arm_emit_cfop_target(proj_false);
492                 be_emit_finish_line_gas(proj_false);
493         }
494 }
495
496 /** Sort register in ascending order. */
497 static int reg_cmp(const void *a, const void *b)
498 {
499         const arch_register_t * const *ra = a;
500         const arch_register_t * const *rb = b;
501
502         return *ra < *rb ? -1 : (*ra != *rb);
503 }
504
505 /**
506  * Create the CopyB instruction sequence.
507  */
508 static void emit_arm_CopyB(const ir_node *irn)
509 {
510         const arm_CopyB_attr_t *attr = get_irn_generic_attr_const(irn);
511         unsigned size = attr->size;
512
513         const char *tgt = arch_register_get_name(get_in_reg(irn, 0));
514         const char *src = arch_register_get_name(get_in_reg(irn, 1));
515         const char *t0, *t1, *t2, *t3;
516
517         const arch_register_t *tmpregs[4];
518
519         /* collect the temporary registers and sort them, we need ascending order */
520         tmpregs[0] = get_in_reg(irn, 2);
521         tmpregs[1] = get_in_reg(irn, 3);
522         tmpregs[2] = get_in_reg(irn, 4);
523         tmpregs[3] = &arm_gp_regs[REG_R12];
524
525         /* Note: R12 is always the last register because the RA did not assign higher ones */
526         qsort((void *)tmpregs, 3, sizeof(tmpregs[0]), reg_cmp);
527
528         /* need ascending order */
529         t0 = arch_register_get_name(tmpregs[0]);
530         t1 = arch_register_get_name(tmpregs[1]);
531         t2 = arch_register_get_name(tmpregs[2]);
532         t3 = arch_register_get_name(tmpregs[3]);
533
534         be_emit_cstring("/* MemCopy (");
535         be_emit_string(src);
536         be_emit_cstring(")->(");
537         arm_emit_source_register(irn, 0);
538         be_emit_irprintf(" [%u bytes], Uses ", size);
539         be_emit_string(t0);
540         be_emit_cstring(", ");
541         be_emit_string(t1);
542         be_emit_cstring(", ");
543         be_emit_string(t2);
544         be_emit_cstring(", and ");
545         be_emit_string(t3);
546         be_emit_cstring("*/");
547         be_emit_finish_line_gas(NULL);
548
549         assert(size > 0 && "CopyB needs size > 0" );
550
551         if (size & 3) {
552                 fprintf(stderr, "strange hack enabled: copy more bytes than needed!");
553                 size += 4;
554         }
555
556         size >>= 2;
557         switch (size & 3) {
558         case 0:
559                 break;
560         case 1:
561                 be_emit_cstring("\tldr ");
562                 be_emit_string(t3);
563                 be_emit_cstring(", [");
564                 be_emit_string(src);
565                 be_emit_cstring(", #0]");
566                 be_emit_finish_line_gas(NULL);
567
568                 be_emit_cstring("\tstr ");
569                 be_emit_string(t3);
570                 be_emit_cstring(", [");
571                 be_emit_string(tgt);
572                 be_emit_cstring(", #0]");
573                 be_emit_finish_line_gas(irn);
574                 break;
575         case 2:
576                 be_emit_cstring("\tldmia ");
577                 be_emit_string(src);
578                 be_emit_cstring("!, {");
579                 be_emit_string(t0);
580                 be_emit_cstring(", ");
581                 be_emit_string(t1);
582                 be_emit_char('}');
583                 be_emit_finish_line_gas(NULL);
584
585                 be_emit_cstring("\tstmia ");
586                 be_emit_string(tgt);
587                 be_emit_cstring("!, {");
588                 be_emit_string(t0);
589                 be_emit_cstring(", ");
590                 be_emit_string(t1);
591                 be_emit_char('}');
592                 be_emit_finish_line_gas(irn);
593                 break;
594         case 3:
595                 be_emit_cstring("\tldmia ");
596                 be_emit_string(src);
597                 be_emit_cstring("!, {");
598                 be_emit_string(t0);
599                 be_emit_cstring(", ");
600                 be_emit_string(t1);
601                 be_emit_cstring(", ");
602                 be_emit_string(t2);
603                 be_emit_char('}');
604                 be_emit_finish_line_gas(NULL);
605
606                 be_emit_cstring("\tstmia ");
607                 be_emit_string(tgt);
608                 be_emit_cstring("!, {");
609                 be_emit_string(t0);
610                 be_emit_cstring(", ");
611                 be_emit_string(t1);
612                 be_emit_cstring(", ");
613                 be_emit_string(t2);
614                 be_emit_char('}');
615                 be_emit_finish_line_gas(irn);
616                 break;
617         }
618         size >>= 2;
619         while (size) {
620                 be_emit_cstring("\tldmia ");
621                 be_emit_string(src);
622                 be_emit_cstring("!, {");
623                 be_emit_string(t0);
624                 be_emit_cstring(", ");
625                 be_emit_string(t1);
626                 be_emit_cstring(", ");
627                 be_emit_string(t2);
628                 be_emit_cstring(", ");
629                 be_emit_string(t3);
630                 be_emit_char('}');
631                 be_emit_finish_line_gas(NULL);
632
633                 be_emit_cstring("\tstmia ");
634                 be_emit_string(tgt);
635                 be_emit_cstring("!, {");
636                 be_emit_string(t0);
637                 be_emit_cstring(", ");
638                 be_emit_string(t1);
639                 be_emit_cstring(", ");
640                 be_emit_string(t2);
641                 be_emit_cstring(", ");
642                 be_emit_string(t3);
643                 be_emit_char('}');
644                 be_emit_finish_line_gas(irn);
645                 --size;
646         }
647 }
648
649 static void emit_arm_SwitchJmp(const ir_node *irn)
650 {
651         const ir_edge_t    *edge;
652         ir_node            *proj;
653         int i;
654         ir_node **projs;
655         int n_projs;
656         int block_nr;
657         ir_node *default_proj = NULL;
658
659         block_nr = get_irn_node_nr(irn);
660         n_projs = get_arm_SwitchJmp_n_projs(irn);
661
662         projs = XMALLOCNZ(ir_node*, n_projs);
663
664         foreach_out_edge(irn, edge) {
665                 proj = get_edge_src_irn(edge);
666                 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
667
668                 if (get_Proj_proj(proj) == get_arm_SwitchJmp_default_proj_num(irn))
669                         default_proj = proj;
670
671                 projs[get_Proj_proj(proj)] = proj;
672         }
673         assert(default_proj != NULL && "SwitchJmp should have a Default Proj");
674
675         /*
676            CMP %1S, n_projs - 1
677            BHI default
678         */
679
680         be_emit_cstring("\tcmp ");
681         arm_emit_source_register(irn, 0);
682         be_emit_irprintf(", #%u", n_projs - 1);
683         be_emit_finish_line_gas(irn);
684
685         be_emit_cstring("\tbhi ");
686         arm_emit_cfop_target(default_proj);
687         be_emit_finish_line_gas(default_proj);
688
689         /*
690            LDR %r12, .TABLE_X_START
691            ADD %r12, %r12, [%1S, LSL #2]
692            LDR %r15, %r12
693          */
694
695         be_emit_irprintf("\tldr %%r12, TABLE_%d_START", block_nr);
696         be_emit_finish_line_gas(NULL);
697
698         be_emit_irprintf("\tadd %%r12, %%r12, ");
699         arm_emit_source_register(irn, 0);
700         be_emit_cstring(", LSL #2");
701         be_emit_finish_line_gas(NULL);
702
703         be_emit_cstring("\tldr %r15, [%r12, #0]");
704         be_emit_finish_line_gas(NULL);
705
706         be_emit_irprintf("TABLE_%d_START:\n\t.word\tTABLE_%d", block_nr, block_nr);
707         be_emit_finish_line_gas(NULL);
708         be_emit_irprintf("\t.align 2");
709         be_emit_finish_line_gas(NULL);
710         be_emit_irprintf("TABLE_%d:", block_nr);
711         be_emit_finish_line_gas(NULL);
712
713         for (i = 0; i < n_projs; ++i) {
714                 proj = projs[i];
715                 if (proj == NULL) {
716                         proj = projs[get_arm_SwitchJmp_default_proj_num(irn)];
717                 }
718                 be_emit_cstring("\t.word\t");
719                 arm_emit_cfop_target(proj);
720                 be_emit_finish_line_gas(proj);
721         }
722         be_emit_irprintf("\t.align 2\n");
723         be_emit_finish_line_gas(NULL);
724         xfree(projs);
725 }
726
727
728 static void arm_emit_entity(ir_entity *entity)
729 {
730         be_emit_ident(get_entity_ld_ident(entity));
731 }
732
733 static void emit_be_Call(const ir_node *irn)
734 {
735         ir_entity *entity = be_Call_get_entity(irn);
736
737         if (entity != NULL) {
738                 be_emit_cstring("\tbl ");
739                 arm_emit_entity(entity);
740                 be_emit_finish_line_gas(irn);
741         } else {
742                 be_emit_cstring("\tmov lr, pc");
743                 be_emit_finish_line_gas(irn);
744                 be_emit_cstring("\tmov pc, ");
745                 arm_emit_source_register(irn, be_pos_Call_ptr);
746                 be_emit_finish_line_gas(irn);
747         }
748 }
749
750 /** Emit an IncSP node */
751 static void emit_be_IncSP(const ir_node *irn)
752 {
753         int offs = -be_get_IncSP_offset(irn);
754
755         if (offs != 0) {
756                 if (offs < 0) {
757                         be_emit_cstring("\tsub ");
758                         offs = -offs;
759                 } else {
760                         be_emit_cstring("\tadd ");
761                 }
762                 arm_emit_dest_register(irn, 0);
763                 be_emit_cstring(", ");
764                 arm_emit_source_register(irn, 0);
765                 be_emit_irprintf(", #0x%X", offs);
766         } else {
767                 /* omitted IncSP(0) */
768                 return;
769         }
770         be_emit_finish_line_gas(irn);
771 }
772
773 static void emit_be_Copy(const ir_node *irn)
774 {
775         ir_mode *mode = get_irn_mode(irn);
776
777         if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
778                 /* omitted Copy */
779                 return;
780         }
781
782         if (mode_is_float(mode)) {
783                 if (USE_FPA(cg->isa)) {
784                         be_emit_cstring("\tmvf");
785                         be_emit_char(' ');
786                         arm_emit_dest_register(irn, 0);
787                         be_emit_cstring(", ");
788                         arm_emit_source_register(irn, 0);
789                         be_emit_finish_line_gas(irn);
790                 } else {
791                         panic("emit_be_Copy: move not supported for this mode");
792                 }
793         } else if (mode_is_data(mode)) {
794                 be_emit_cstring("\tmov ");
795                 arm_emit_dest_register(irn, 0);
796                 be_emit_cstring(", ");
797                 arm_emit_source_register(irn, 0);
798                 be_emit_finish_line_gas(irn);
799         } else {
800                 panic("emit_be_Copy: move not supported for this mode");
801         }
802 }
803
804 static void emit_be_Perm(const ir_node *irn)
805 {
806         be_emit_cstring("\teor ");
807         arm_emit_source_register(irn, 0);
808         be_emit_cstring(", ");
809         arm_emit_source_register(irn, 0);
810         be_emit_cstring(", ");
811         arm_emit_source_register(irn, 1);
812         be_emit_finish_line_gas(NULL);
813
814         be_emit_cstring("\teor ");
815         arm_emit_source_register(irn, 1);
816         be_emit_cstring(", ");
817         arm_emit_source_register(irn, 0);
818         be_emit_cstring(", ");
819         arm_emit_source_register(irn, 1);
820         be_emit_finish_line_gas(NULL);
821
822         be_emit_cstring("\teor ");
823         arm_emit_source_register(irn, 0);
824         be_emit_cstring(", ");
825         arm_emit_source_register(irn, 0);
826         be_emit_cstring(", ");
827         arm_emit_source_register(irn, 1);
828         be_emit_finish_line_gas(irn);
829 }
830
831 static void emit_be_MemPerm(const ir_node *node)
832 {
833         int i;
834         int memperm_arity;
835         int sp_change = 0;
836
837         /* TODO: this implementation is slower than necessary.
838            The longterm goal is however to avoid the memperm node completely */
839
840         memperm_arity = be_get_MemPerm_entity_arity(node);
841         if (memperm_arity > 12)
842                 panic("memperm with more than 12 inputs not supported yet");
843
844         for (i = 0; i < memperm_arity; ++i) {
845                 int offset;
846                 ir_entity *entity = be_get_MemPerm_in_entity(node, i);
847
848                 /* spill register */
849                 be_emit_irprintf("\tstr r%d, [sp, #-4]!", i);
850                 be_emit_finish_line_gas(node);
851                 sp_change += 4;
852                 /* load from entity */
853                 offset = get_entity_offset(entity) + sp_change;
854                 be_emit_irprintf("\tldr r%d, [sp, #%d]", i, offset);
855                 be_emit_finish_line_gas(node);
856         }
857
858         for (i = memperm_arity-1; i >= 0; --i) {
859                 int        offset;
860                 ir_entity *entity = be_get_MemPerm_out_entity(node, i);
861
862                 /* store to new entity */
863                 offset = get_entity_offset(entity) + sp_change;
864                 be_emit_irprintf("\tstr r%d, [sp, #%d]", i, offset);
865                 be_emit_finish_line_gas(node);
866                 /* restore register */
867                 be_emit_irprintf("\tldr r%d, [sp], #4", i);
868                 sp_change -= 4;
869                 be_emit_finish_line_gas(node);
870         }
871         assert(sp_change == 0);
872 }
873
874 static void emit_be_Return(const ir_node *node)
875 {
876         be_emit_cstring("\tmov pc, lr");
877         be_emit_finish_line_gas(node);
878 }
879
880
881 static void emit_arm_Jmp(const ir_node *node)
882 {
883         ir_node *block, *next_block;
884
885         /* for now, the code works for scheduled and non-schedules blocks */
886         block = get_nodes_block(node);
887
888         /* we have a block schedule */
889         next_block = sched_next_block(block);
890         if (get_cfop_target_block(node) != next_block) {
891                 be_emit_cstring("\tb ");
892                 arm_emit_cfop_target(node);
893         } else {
894                 be_emit_cstring("\t/* fallthrough to ");
895                 arm_emit_cfop_target(node);
896                 be_emit_cstring(" */");
897         }
898         be_emit_finish_line_gas(node);
899 }
900
901 static void emit_nothing(const ir_node *irn)
902 {
903         (void) irn;
904 }
905
906 /**
907  * The type of a emitter function.
908  */
909 typedef void (emit_func)(const ir_node *irn);
910
911 /**
912  * Set a node emitter. Make it a bit more type safe.
913  */
914 static inline void set_emitter(ir_op *op, emit_func arm_emit_node)
915 {
916         op->ops.generic = (op_func)arm_emit_node;
917 }
918
919 /**
920  * Enters the emitter functions for handled nodes into the generic
921  * pointer of an opcode.
922  */
923 static void arm_register_emitters(void)
924 {
925         /* first clear the generic function pointer for all ops */
926         clear_irp_opcodes_generic_func();
927
928         /* register all emitter functions defined in spec */
929         arm_register_spec_emitters();
930
931         /* custom emitter */
932         set_emitter(op_arm_B,         emit_arm_B);
933         set_emitter(op_arm_CopyB,     emit_arm_CopyB);
934         set_emitter(op_arm_fConst,    emit_arm_fConst);
935         set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
936         set_emitter(op_arm_Jmp,       emit_arm_Jmp);
937         set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
938         set_emitter(op_arm_SymConst,  emit_arm_SymConst);
939         set_emitter(op_be_Call,       emit_be_Call);
940         set_emitter(op_be_Copy,       emit_be_Copy);
941         set_emitter(op_be_CopyKeep,   emit_be_Copy);
942         set_emitter(op_be_IncSP,      emit_be_IncSP);
943         set_emitter(op_be_MemPerm,    emit_be_MemPerm);
944         set_emitter(op_be_Perm,       emit_be_Perm);
945         set_emitter(op_be_Return,     emit_be_Return);
946
947         /* no need to emit anything for the following nodes */
948         set_emitter(op_Phi,           emit_nothing);
949         set_emitter(op_be_Keep,       emit_nothing);
950         set_emitter(op_be_Start,      emit_nothing);
951         set_emitter(op_be_Barrier,    emit_nothing);
952 }
953
954 /**
955  * Emits code for a node.
956  */
957 static void arm_emit_node(const ir_node *irn)
958 {
959         ir_op *op = get_irn_op(irn);
960
961         if (op->ops.generic) {
962                 emit_func *emit = (emit_func *)op->ops.generic;
963                 be_dbg_set_dbg_info(get_irn_dbg_info(irn));
964                 (*emit)(irn);
965         } else {
966                 panic("Error: No emit handler for node %+F (graph %+F)\n",
967                       irn, current_ir_graph);
968         }
969 }
970
971 /**
972  * emit the block label if needed.
973  */
974 static void arm_emit_block_header(ir_node *block, ir_node *prev)
975 {
976         int           n_cfgpreds;
977         int           need_label;
978         int           i, arity;
979         ir_exec_freq  *exec_freq = be_get_irg_exec_freq(cg->irg);
980
981         need_label = 0;
982         n_cfgpreds = get_Block_n_cfgpreds(block);
983         if (n_cfgpreds == 1) {
984                 ir_node *pred       = get_Block_cfgpred(block, 0);
985                 ir_node *pred_block = get_nodes_block(pred);
986
987                 /* we don't need labels for fallthrough blocks, however switch-jmps
988                  * are no fallthroughs */
989                 if (pred_block == prev &&
990                                 !(is_Proj(pred) && is_arm_SwitchJmp(get_Proj_pred(pred)))) {
991                         need_label = 0;
992                 } else {
993                         need_label = 1;
994                 }
995         } else {
996                 need_label = 1;
997         }
998
999         if (need_label) {
1000                 be_gas_emit_block_name(block);
1001                 be_emit_char(':');
1002
1003                 be_emit_pad_comment();
1004                 be_emit_cstring("   /* preds:");
1005
1006                 /* emit list of pred blocks in comment */
1007                 arity = get_irn_arity(block);
1008                 for (i = 0; i < arity; ++i) {
1009                         ir_node *predblock = get_Block_cfgpred_block(block, i);
1010                         be_emit_irprintf(" %d", get_irn_node_nr(predblock));
1011                 }
1012         } else {
1013                 be_emit_cstring("\t/* ");
1014                 be_gas_emit_block_name(block);
1015                 be_emit_cstring(": ");
1016         }
1017         if (exec_freq != NULL) {
1018                 be_emit_irprintf(" freq: %f",
1019                                  get_block_execfreq(exec_freq, block));
1020         }
1021         be_emit_cstring(" */\n");
1022         be_emit_write_line();
1023 }
1024
1025 /**
1026  * Walks over the nodes in a block connected by scheduling edges
1027  * and emits code for each node.
1028  */
1029 static void arm_gen_block(ir_node *block, ir_node *prev_block)
1030 {
1031         ir_node *irn;
1032
1033         arm_emit_block_header(block, prev_block);
1034         be_dbg_set_dbg_info(get_irn_dbg_info(block));
1035         sched_foreach(block, irn) {
1036                 arm_emit_node(irn);
1037         }
1038 }
1039
1040 /**
1041  * Block-walker:
1042  * Sets labels for control flow nodes (jump target)
1043  */
1044 static void arm_gen_labels(ir_node *block, void *env)
1045 {
1046         ir_node *pred;
1047         int n = get_Block_n_cfgpreds(block);
1048         (void)env;
1049
1050         for (n--; n >= 0; n--) {
1051                 pred = get_Block_cfgpred(block, n);
1052                 set_irn_link(pred, block);
1053         }
1054 }
1055
1056 /**
1057  * Compare two entries of the symbol or tarval set.
1058  */
1059 static int cmp_sym_or_tv(const void *elt, const void *key, size_t size)
1060 {
1061         const sym_or_tv_t *p1 = elt;
1062         const sym_or_tv_t *p2 = key;
1063         (void) size;
1064
1065         /* as an identifier NEVER can point to a tarval, it's enough
1066            to compare it this way */
1067         return p1->u.generic != p2->u.generic;
1068 }
1069
1070 void arm_gen_routine(const arm_code_gen_t *arm_cg, ir_graph *irg)
1071 {
1072         ir_node   **blk_sched;
1073         int       i, n;
1074         ir_node   *last_block = NULL;
1075         ir_entity *entity     = get_irg_entity(irg);
1076
1077         cg        = arm_cg;
1078         sym_or_tv = new_set(cmp_sym_or_tv, 8);
1079
1080         be_gas_elf_type_char = '%';
1081
1082         arm_register_emitters();
1083
1084         be_dbg_method_begin(entity);
1085
1086         /* create the block schedule */
1087         blk_sched = be_create_block_schedule(irg);
1088
1089         be_gas_emit_function_prolog(entity, 4);
1090
1091         irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
1092
1093         n = ARR_LEN(blk_sched);
1094         for (i = 0; i < n;) {
1095                 ir_node *block, *next_bl;
1096
1097                 block   = blk_sched[i];
1098                 ++i;
1099                 next_bl = i < n ? blk_sched[i] : NULL;
1100
1101                 /* set here the link. the emitter expects to find the next block here */
1102                 set_irn_link(block, next_bl);
1103                 arm_gen_block(block, last_block);
1104                 last_block = block;
1105         }
1106
1107         /* emit SymConst values */
1108         if (set_count(sym_or_tv) > 0) {
1109                 sym_or_tv_t *entry;
1110
1111                 be_emit_cstring("\t.align 2\n");
1112
1113                 foreach_set(sym_or_tv, entry) {
1114                         emit_constant_name(entry);
1115                         be_emit_cstring(":\n");
1116                         be_emit_write_line();
1117
1118                         if (entry->is_entity) {
1119                                 be_emit_cstring("\t.word\t");
1120                                 be_gas_emit_entity(entry->u.entity);
1121                                 be_emit_char('\n');
1122                                 be_emit_write_line();
1123                         } else {
1124                                 tarval *tv = entry->u.tv;
1125                                 int i, size = get_mode_size_bytes(get_tarval_mode(tv));
1126                                 unsigned v;
1127
1128                                 /* beware: ARM fpa uses big endian format */
1129                                 for (i = ((size + 3) & ~3) - 4; i >= 0; i -= 4) {
1130                                         /* get 32 bits */
1131                                         v =            get_tarval_sub_bits(tv, i+3);
1132                                         v = (v << 8) | get_tarval_sub_bits(tv, i+2);
1133                                         v = (v << 8) | get_tarval_sub_bits(tv, i+1);
1134                                         v = (v << 8) | get_tarval_sub_bits(tv, i+0);
1135                                         be_emit_irprintf("\t.word\t%u\n", v);
1136                                         be_emit_write_line();
1137                                 }
1138                         }
1139                 }
1140                 be_emit_char('\n');
1141                 be_emit_write_line();
1142         }
1143         del_set(sym_or_tv);
1144
1145         be_gas_emit_function_epilog(entity);
1146         be_dbg_method_end();
1147 }
1148
1149 void arm_init_emitter(void)
1150 {
1151         FIRM_DBG_REGISTER(dbg, "firm.be.arm.emit");
1152 }