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