2 * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
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.
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.
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
23 * @author Oliver Richter, Tobias Gneist, Michael Beck
42 #include "raw_bitset.h"
45 #include "../besched.h"
46 #include "../beblocksched.h"
48 #include "../begnuas.h"
49 #include "../be_dbgout.h"
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"
59 #include "../benode.h"
61 #define SNPRINTF_BUF_LEN 128
63 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
65 static const arm_code_gen_t *cg;
66 static set *sym_or_tv;
69 * Returns the register at in position pos.
71 static const arch_register_t *get_in_reg(const ir_node *irn, int pos)
74 const arch_register_t *reg = NULL;
76 assert(get_irn_arity(irn) > pos && "Invalid IN position");
78 /* The out register of the operator at position pos is the
79 in register we need. */
80 op = get_irn_n(irn, pos);
82 reg = arch_get_irn_register(op);
84 assert(reg && "no in register found");
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);
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);
95 /* otherwise get first register in class */
96 reg = arch_register_for_index(req->cls, 0);
104 * Returns the register at out position pos.
106 static const arch_register_t *get_out_reg(const ir_node *node, int pos)
109 const arch_register_t *reg = NULL;
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 */
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);
121 const ir_edge_t *edge;
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);
133 assert(reg && "no out register found");
137 void arm_emit_source_register(const ir_node *node, int pos)
139 const arch_register_t *reg = get_in_reg(node, pos);
140 be_emit_string(arch_register_get_name(reg));
143 void arm_emit_dest_register(const ir_node *node, int pos)
145 const arch_register_t *reg = get_out_reg(node, pos);
146 be_emit_string(arch_register_get_name(reg));
149 void arm_emit_offset(const ir_node *node)
151 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
152 assert(attr->base.is_load_store);
154 be_emit_irprintf("0x%X", attr->offset);
158 * Emit the arm fpa instruction suffix depending on the mode.
160 static void arm_emit_fpa_postfix(const ir_mode *mode)
162 int bits = get_mode_size_bits(mode);
172 void arm_emit_float_load_store_mode(const ir_node *node)
174 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
175 arm_emit_fpa_postfix(attr->load_store_mode);
178 void arm_emit_float_arithmetic_mode(const ir_node *node)
180 const arm_farith_attr_t *attr = get_arm_farith_attr_const(node);
181 arm_emit_fpa_postfix(attr->mode);
184 void arm_emit_symconst(const ir_node *node)
186 const arm_SymConst_attr_t *symconst = get_arm_SymConst_attr_const(node);
187 ir_entity *entity = symconst->entity;
189 be_gas_emit_entity(entity);
191 /* TODO do something with offset */
194 void arm_emit_load_mode(const ir_node *node)
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);
201 be_emit_string(is_signed ? "sh" : "h");
202 } else if (bits == 8) {
203 be_emit_string(is_signed ? "sb" : "b");
209 void arm_emit_store_mode(const ir_node *node)
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);
215 be_emit_cstring("h");
216 } else if (bits == 8) {
217 be_emit_cstring("b");
223 static void emit_shf_mod_name(arm_shift_modifier_t mod)
226 case ARM_SHF_ASR_REG:
227 case ARM_SHF_ASR_IMM:
228 be_emit_cstring("asr");
230 case ARM_SHF_LSL_REG:
231 case ARM_SHF_LSL_IMM:
232 be_emit_cstring("lsl");
234 case ARM_SHF_LSR_REG:
235 case ARM_SHF_LSR_IMM:
236 be_emit_cstring("lsr");
238 case ARM_SHF_ROR_REG:
239 case ARM_SHF_ROR_IMM:
240 be_emit_cstring("ror");
245 panic("can't emit this shf_mod_name %d", (int) mod);
248 void arm_emit_shifter_operand(const ir_node *node)
250 const arm_shifter_operand_t *attr = get_irn_generic_attr_const(node);
252 switch (attr->shift_modifier) {
254 arm_emit_source_register(node, get_irn_arity(node) - 1);
257 unsigned val = attr->immediate_value;
258 val = (val >> attr->shift_immediate)
259 | (val << (32-attr->shift_immediate));
261 be_emit_irprintf("#0x%X", val);
264 case ARM_SHF_ASR_IMM:
265 case ARM_SHF_LSL_IMM:
266 case ARM_SHF_LSR_IMM:
267 case ARM_SHF_ROR_IMM:
268 arm_emit_source_register(node, get_irn_arity(node) - 1);
269 be_emit_cstring(", ");
270 emit_shf_mod_name(attr->shift_modifier);
271 be_emit_irprintf(" #0x%X", attr->shift_immediate);
274 case ARM_SHF_ASR_REG:
275 case ARM_SHF_LSL_REG:
276 case ARM_SHF_LSR_REG:
277 case ARM_SHF_ROR_REG:
278 arm_emit_source_register(node, get_irn_arity(node) - 2);
279 be_emit_cstring(", ");
280 emit_shf_mod_name(attr->shift_modifier);
281 be_emit_cstring(" ");
282 arm_emit_source_register(node, get_irn_arity(node) - 1);
286 arm_emit_source_register(node, get_irn_arity(node) - 1);
287 panic("RRX shifter emitter TODO");
289 case ARM_SHF_INVALID:
292 panic("Invalid shift_modifier while emitting %+F", node);
295 /** An entry in the sym_or_tv set. */
296 typedef struct sym_or_tv_t {
298 ir_entity *entity; /**< An entity. */
299 tarval *tv; /**< A tarval. */
300 const void *generic; /**< For generic compare. */
302 unsigned label; /**< the associated label. */
303 bool is_entity; /**< true if an entity is stored. */
307 * Returns a unique label. This number will not be used a second time.
309 static unsigned get_unique_label(void)
311 static unsigned id = 0;
315 static void emit_constant_name(const sym_or_tv_t *entry)
317 be_emit_irprintf("%sC%u", be_gas_get_private_prefix(), entry->label);
323 static void emit_arm_SymConst(const ir_node *irn)
325 const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
326 sym_or_tv_t key, *entry;
329 key.u.entity = attr->entity;
330 key.is_entity = true;
332 entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
333 if (entry->label == 0) {
334 /* allocate a label */
335 entry->label = get_unique_label();
337 label = entry->label;
339 /* load the symbol indirect */
340 be_emit_cstring("\tldr ");
341 arm_emit_dest_register(irn, 0);
342 be_emit_cstring(", ");
343 emit_constant_name(entry);
344 be_emit_finish_line_gas(irn);
347 static void emit_arm_FrameAddr(const ir_node *irn)
349 const arm_SymConst_attr_t *attr = get_irn_generic_attr_const(irn);
351 be_emit_cstring("\tadd ");
352 arm_emit_dest_register(irn, 0);
353 be_emit_cstring(", ");
354 arm_emit_source_register(irn, 0);
355 be_emit_cstring(", ");
356 be_emit_irprintf("#0x%X", attr->fp_offset);
357 be_emit_finish_line_gas(irn);
361 * Emit a floating point fpa constant.
363 static void emit_arm_fConst(const ir_node *irn)
365 sym_or_tv_t key, *entry;
369 key.u.tv = get_fConst_value(irn);
370 key.is_entity = false;
372 entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
373 if (entry->label == 0) {
374 /* allocate a label */
375 entry->label = get_unique_label();
377 label = entry->label;
379 /* load the tarval indirect */
380 mode = get_irn_mode(irn);
381 be_emit_cstring("\tldf");
382 arm_emit_fpa_postfix(mode);
385 arm_emit_dest_register(irn, 0);
386 be_emit_cstring(", ");
387 emit_constant_name(entry);
388 be_emit_finish_line_gas(irn);
392 * Returns the next block in a block schedule.
394 static ir_node *sched_next_block(const ir_node *block)
396 return get_irn_link(block);
400 * Returns the target block for a control flow node.
402 static ir_node *get_cfop_target_block(const ir_node *irn)
404 return get_irn_link(irn);
408 * Emit the target label for a control flow node.
410 static void arm_emit_cfop_target(const ir_node *irn)
412 ir_node *block = get_cfop_target_block(irn);
414 be_gas_emit_block_name(block);
418 * Emit a Compare with conditional branch.
420 static void emit_arm_B(const ir_node *irn)
422 const ir_edge_t *edge;
423 const ir_node *proj_true = NULL;
424 const ir_node *proj_false = NULL;
425 const ir_node *block;
426 const ir_node *next_block;
427 ir_node *op1 = get_irn_n(irn, 0);
429 pn_Cmp pnc = get_arm_CondJmp_pnc(irn);
430 const arm_cmp_attr_t *cmp_attr = get_irn_generic_attr_const(op1);
431 bool is_signed = !cmp_attr->is_unsigned;
433 assert(is_arm_Cmp(op1) || is_arm_Tst(op1));
435 foreach_out_edge(irn, edge) {
436 ir_node *proj = get_edge_src_irn(edge);
437 long nr = get_Proj_proj(proj);
438 if (nr == pn_Cond_true) {
445 if (cmp_attr->ins_permuted) {
446 pnc = get_mirrored_pnc(pnc);
449 /* for now, the code works for scheduled and non-schedules blocks */
450 block = get_nodes_block(irn);
452 /* we have a block schedule */
453 next_block = sched_next_block(block);
455 assert(pnc != pn_Cmp_False);
456 assert(pnc != pn_Cmp_True);
458 if (get_cfop_target_block(proj_true) == next_block) {
459 /* exchange both proj's so the second one can be omitted */
460 const ir_node *t = proj_true;
462 proj_true = proj_false;
464 pnc = get_negated_pnc(pnc, mode_Iu);
468 case pn_Cmp_Eq: suffix = "eq"; break;
469 case pn_Cmp_Lt: suffix = is_signed ? "lt" : "lo"; break;
470 case pn_Cmp_Le: suffix = is_signed ? "le" : "ls"; break;
471 case pn_Cmp_Gt: suffix = is_signed ? "gt" : "hi"; break;
472 case pn_Cmp_Ge: suffix = is_signed ? "ge" : "hs"; break;
473 case pn_Cmp_Lg: suffix = "ne"; break;
474 case pn_Cmp_Leg: suffix = "al"; break;
475 default: panic("Cmp has unsupported pnc");
478 /* emit the true proj */
479 be_emit_irprintf("\tb%s ", suffix);
480 arm_emit_cfop_target(proj_true);
481 be_emit_finish_line_gas(proj_true);
483 if (get_cfop_target_block(proj_false) == next_block) {
484 be_emit_cstring("\t/* fallthrough to ");
485 arm_emit_cfop_target(proj_false);
486 be_emit_cstring(" */");
487 be_emit_finish_line_gas(proj_false);
489 be_emit_cstring("\tb ");
490 arm_emit_cfop_target(proj_false);
491 be_emit_finish_line_gas(proj_false);
495 /** Sort register in ascending order. */
496 static int reg_cmp(const void *a, const void *b)
498 const arch_register_t * const *ra = a;
499 const arch_register_t * const *rb = b;
501 return *ra < *rb ? -1 : (*ra != *rb);
505 * Create the CopyB instruction sequence.
507 static void emit_arm_CopyB(const ir_node *irn)
509 const arm_CopyB_attr_t *attr = get_irn_generic_attr_const(irn);
510 unsigned size = attr->size;
512 const char *tgt = arch_register_get_name(get_in_reg(irn, 0));
513 const char *src = arch_register_get_name(get_in_reg(irn, 1));
514 const char *t0, *t1, *t2, *t3;
516 const arch_register_t *tmpregs[4];
518 /* collect the temporary registers and sort them, we need ascending order */
519 tmpregs[0] = get_in_reg(irn, 2);
520 tmpregs[1] = get_in_reg(irn, 3);
521 tmpregs[2] = get_in_reg(irn, 4);
522 tmpregs[3] = &arm_gp_regs[REG_R12];
524 /* Note: R12 is always the last register because the RA did not assign higher ones */
525 qsort((void *)tmpregs, 3, sizeof(tmpregs[0]), reg_cmp);
527 /* need ascending order */
528 t0 = arch_register_get_name(tmpregs[0]);
529 t1 = arch_register_get_name(tmpregs[1]);
530 t2 = arch_register_get_name(tmpregs[2]);
531 t3 = arch_register_get_name(tmpregs[3]);
533 be_emit_cstring("/* MemCopy (");
535 be_emit_cstring(")->(");
536 arm_emit_source_register(irn, 0);
537 be_emit_irprintf(" [%u bytes], Uses ", size);
539 be_emit_cstring(", ");
541 be_emit_cstring(", ");
543 be_emit_cstring(", and ");
545 be_emit_cstring("*/");
546 be_emit_finish_line_gas(NULL);
548 assert(size > 0 && "CopyB needs size > 0" );
551 fprintf(stderr, "strange hack enabled: copy more bytes than needed!");
560 be_emit_cstring("\tldr ");
562 be_emit_cstring(", [");
564 be_emit_cstring(", #0]");
565 be_emit_finish_line_gas(NULL);
567 be_emit_cstring("\tstr ");
569 be_emit_cstring(", [");
571 be_emit_cstring(", #0]");
572 be_emit_finish_line_gas(irn);
575 be_emit_cstring("\tldmia ");
577 be_emit_cstring("!, {");
579 be_emit_cstring(", ");
582 be_emit_finish_line_gas(NULL);
584 be_emit_cstring("\tstmia ");
586 be_emit_cstring("!, {");
588 be_emit_cstring(", ");
591 be_emit_finish_line_gas(irn);
594 be_emit_cstring("\tldmia ");
596 be_emit_cstring("!, {");
598 be_emit_cstring(", ");
600 be_emit_cstring(", ");
603 be_emit_finish_line_gas(NULL);
605 be_emit_cstring("\tstmia ");
607 be_emit_cstring("!, {");
609 be_emit_cstring(", ");
611 be_emit_cstring(", ");
614 be_emit_finish_line_gas(irn);
619 be_emit_cstring("\tldmia ");
621 be_emit_cstring("!, {");
623 be_emit_cstring(", ");
625 be_emit_cstring(", ");
627 be_emit_cstring(", ");
630 be_emit_finish_line_gas(NULL);
632 be_emit_cstring("\tstmia ");
634 be_emit_cstring("!, {");
636 be_emit_cstring(", ");
638 be_emit_cstring(", ");
640 be_emit_cstring(", ");
643 be_emit_finish_line_gas(irn);
648 static void emit_arm_SwitchJmp(const ir_node *irn)
650 const ir_edge_t *edge;
656 ir_node *default_proj = NULL;
658 block_nr = get_irn_node_nr(irn);
659 n_projs = get_arm_SwitchJmp_n_projs(irn);
661 projs = XMALLOCNZ(ir_node*, n_projs);
663 foreach_out_edge(irn, edge) {
664 proj = get_edge_src_irn(edge);
665 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
667 if (get_Proj_proj(proj) == get_arm_SwitchJmp_default_proj_num(irn))
670 projs[get_Proj_proj(proj)] = proj;
672 assert(default_proj != NULL && "SwitchJmp should have a Default Proj");
679 be_emit_cstring("\tcmp ");
680 arm_emit_source_register(irn, 0);
681 be_emit_irprintf(", #%u", n_projs - 1);
682 be_emit_finish_line_gas(irn);
684 be_emit_cstring("\tbhi ");
685 arm_emit_cfop_target(default_proj);
686 be_emit_finish_line_gas(default_proj);
689 LDR %r12, .TABLE_X_START
690 ADD %r12, %r12, [%1S, LSL #2]
694 be_emit_irprintf("\tldr %%r12, TABLE_%d_START", block_nr);
695 be_emit_finish_line_gas(NULL);
697 be_emit_irprintf("\tadd %%r12, %%r12, ");
698 arm_emit_source_register(irn, 0);
699 be_emit_cstring(", LSL #2");
700 be_emit_finish_line_gas(NULL);
702 be_emit_cstring("\tldr %r15, [%r12, #0]");
703 be_emit_finish_line_gas(NULL);
705 be_emit_irprintf("TABLE_%d_START:\n\t.word\tTABLE_%d", block_nr, block_nr);
706 be_emit_finish_line_gas(NULL);
707 be_emit_irprintf("\t.align 2");
708 be_emit_finish_line_gas(NULL);
709 be_emit_irprintf("TABLE_%d:", block_nr);
710 be_emit_finish_line_gas(NULL);
712 for (i = 0; i < n_projs; ++i) {
715 proj = projs[get_arm_SwitchJmp_default_proj_num(irn)];
717 be_emit_cstring("\t.word\t");
718 arm_emit_cfop_target(proj);
719 be_emit_finish_line_gas(proj);
721 be_emit_irprintf("\t.align 2\n");
722 be_emit_finish_line_gas(NULL);
726 /** Emit an IncSP node */
727 static void emit_be_IncSP(const ir_node *irn)
729 int offs = -be_get_IncSP_offset(irn);
733 be_emit_cstring("\tsub ");
736 be_emit_cstring("\tadd ");
738 arm_emit_dest_register(irn, 0);
739 be_emit_cstring(", ");
740 arm_emit_source_register(irn, 0);
741 be_emit_irprintf(", #0x%X", offs);
743 /* omitted IncSP(0) */
746 be_emit_finish_line_gas(irn);
749 static void emit_be_Copy(const ir_node *irn)
751 ir_mode *mode = get_irn_mode(irn);
753 if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
758 if (mode_is_float(mode)) {
759 if (USE_FPA(cg->isa)) {
760 be_emit_cstring("\tmvf");
762 arm_emit_dest_register(irn, 0);
763 be_emit_cstring(", ");
764 arm_emit_source_register(irn, 0);
765 be_emit_finish_line_gas(irn);
767 panic("emit_be_Copy: move not supported for this mode");
769 } else if (mode_is_data(mode)) {
770 be_emit_cstring("\tmov ");
771 arm_emit_dest_register(irn, 0);
772 be_emit_cstring(", ");
773 arm_emit_source_register(irn, 0);
774 be_emit_finish_line_gas(irn);
776 panic("emit_be_Copy: move not supported for this mode");
780 static void emit_be_Perm(const ir_node *irn)
782 be_emit_cstring("\teor ");
783 arm_emit_source_register(irn, 0);
784 be_emit_cstring(", ");
785 arm_emit_source_register(irn, 0);
786 be_emit_cstring(", ");
787 arm_emit_source_register(irn, 1);
788 be_emit_finish_line_gas(NULL);
790 be_emit_cstring("\teor ");
791 arm_emit_source_register(irn, 1);
792 be_emit_cstring(", ");
793 arm_emit_source_register(irn, 0);
794 be_emit_cstring(", ");
795 arm_emit_source_register(irn, 1);
796 be_emit_finish_line_gas(NULL);
798 be_emit_cstring("\teor ");
799 arm_emit_source_register(irn, 0);
800 be_emit_cstring(", ");
801 arm_emit_source_register(irn, 0);
802 be_emit_cstring(", ");
803 arm_emit_source_register(irn, 1);
804 be_emit_finish_line_gas(irn);
807 static void emit_be_MemPerm(const ir_node *node)
813 /* TODO: this implementation is slower than necessary.
814 The longterm goal is however to avoid the memperm node completely */
816 memperm_arity = be_get_MemPerm_entity_arity(node);
817 if (memperm_arity > 12)
818 panic("memperm with more than 12 inputs not supported yet");
820 for (i = 0; i < memperm_arity; ++i) {
822 ir_entity *entity = be_get_MemPerm_in_entity(node, i);
825 be_emit_irprintf("\tstr r%d, [sp, #-4]!", i);
826 be_emit_finish_line_gas(node);
828 /* load from entity */
829 offset = get_entity_offset(entity) + sp_change;
830 be_emit_irprintf("\tldr r%d, [sp, #%d]", i, offset);
831 be_emit_finish_line_gas(node);
834 for (i = memperm_arity-1; i >= 0; --i) {
836 ir_entity *entity = be_get_MemPerm_out_entity(node, i);
838 /* store to new entity */
839 offset = get_entity_offset(entity) + sp_change;
840 be_emit_irprintf("\tstr r%d, [sp, #%d]", i, offset);
841 be_emit_finish_line_gas(node);
842 /* restore register */
843 be_emit_irprintf("\tldr r%d, [sp], #4", i);
845 be_emit_finish_line_gas(node);
847 assert(sp_change == 0);
850 static void emit_be_Return(const ir_node *node)
852 be_emit_cstring("\tmov pc, lr");
853 be_emit_finish_line_gas(node);
857 static void emit_arm_Jmp(const ir_node *node)
859 ir_node *block, *next_block;
861 /* for now, the code works for scheduled and non-schedules blocks */
862 block = get_nodes_block(node);
864 /* we have a block schedule */
865 next_block = sched_next_block(block);
866 if (get_cfop_target_block(node) != next_block) {
867 be_emit_cstring("\tb ");
868 arm_emit_cfop_target(node);
870 be_emit_cstring("\t/* fallthrough to ");
871 arm_emit_cfop_target(node);
872 be_emit_cstring(" */");
874 be_emit_finish_line_gas(node);
877 static void emit_nothing(const ir_node *irn)
883 * The type of a emitter function.
885 typedef void (emit_func)(const ir_node *irn);
888 * Set a node emitter. Make it a bit more type safe.
890 static inline void set_emitter(ir_op *op, emit_func arm_emit_node)
892 op->ops.generic = (op_func)arm_emit_node;
896 * Enters the emitter functions for handled nodes into the generic
897 * pointer of an opcode.
899 static void arm_register_emitters(void)
901 /* first clear the generic function pointer for all ops */
902 clear_irp_opcodes_generic_func();
904 /* register all emitter functions defined in spec */
905 arm_register_spec_emitters();
908 set_emitter(op_arm_B, emit_arm_B);
909 set_emitter(op_arm_CopyB, emit_arm_CopyB);
910 set_emitter(op_arm_fConst, emit_arm_fConst);
911 set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
912 set_emitter(op_arm_Jmp, emit_arm_Jmp);
913 set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
914 set_emitter(op_arm_SymConst, emit_arm_SymConst);
915 set_emitter(op_be_Copy, emit_be_Copy);
916 set_emitter(op_be_CopyKeep, emit_be_Copy);
917 set_emitter(op_be_IncSP, emit_be_IncSP);
918 set_emitter(op_be_MemPerm, emit_be_MemPerm);
919 set_emitter(op_be_Perm, emit_be_Perm);
920 set_emitter(op_be_Return, emit_be_Return);
922 /* no need to emit anything for the following nodes */
923 set_emitter(op_Phi, emit_nothing);
924 set_emitter(op_be_Keep, emit_nothing);
925 set_emitter(op_be_Start, emit_nothing);
926 set_emitter(op_be_Barrier, emit_nothing);
930 * Emits code for a node.
932 static void arm_emit_node(const ir_node *irn)
934 ir_op *op = get_irn_op(irn);
936 if (op->ops.generic) {
937 emit_func *emit = (emit_func *)op->ops.generic;
938 be_dbg_set_dbg_info(get_irn_dbg_info(irn));
941 panic("Error: No emit handler for node %+F (graph %+F)\n",
942 irn, current_ir_graph);
947 * emit the block label if needed.
949 static void arm_emit_block_header(ir_node *block, ir_node *prev)
954 ir_exec_freq *exec_freq = be_get_irg_exec_freq(cg->irg);
957 n_cfgpreds = get_Block_n_cfgpreds(block);
958 if (n_cfgpreds == 1) {
959 ir_node *pred = get_Block_cfgpred(block, 0);
960 ir_node *pred_block = get_nodes_block(pred);
962 /* we don't need labels for fallthrough blocks, however switch-jmps
963 * are no fallthroughs */
964 if (pred_block == prev &&
965 !(is_Proj(pred) && is_arm_SwitchJmp(get_Proj_pred(pred)))) {
975 be_gas_emit_block_name(block);
978 be_emit_pad_comment();
979 be_emit_cstring(" /* preds:");
981 /* emit list of pred blocks in comment */
982 arity = get_irn_arity(block);
983 for (i = 0; i < arity; ++i) {
984 ir_node *predblock = get_Block_cfgpred_block(block, i);
985 be_emit_irprintf(" %d", get_irn_node_nr(predblock));
988 be_emit_cstring("\t/* ");
989 be_gas_emit_block_name(block);
990 be_emit_cstring(": ");
992 if (exec_freq != NULL) {
993 be_emit_irprintf(" freq: %f",
994 get_block_execfreq(exec_freq, block));
996 be_emit_cstring(" */\n");
997 be_emit_write_line();
1001 * Walks over the nodes in a block connected by scheduling edges
1002 * and emits code for each node.
1004 static void arm_gen_block(ir_node *block, ir_node *prev_block)
1008 arm_emit_block_header(block, prev_block);
1009 be_dbg_set_dbg_info(get_irn_dbg_info(block));
1010 sched_foreach(block, irn) {
1017 * Sets labels for control flow nodes (jump target)
1019 static void arm_gen_labels(ir_node *block, void *env)
1022 int n = get_Block_n_cfgpreds(block);
1025 for (n--; n >= 0; n--) {
1026 pred = get_Block_cfgpred(block, n);
1027 set_irn_link(pred, block);
1032 * Compare two entries of the symbol or tarval set.
1034 static int cmp_sym_or_tv(const void *elt, const void *key, size_t size)
1036 const sym_or_tv_t *p1 = elt;
1037 const sym_or_tv_t *p2 = key;
1040 /* as an identifier NEVER can point to a tarval, it's enough
1041 to compare it this way */
1042 return p1->u.generic != p2->u.generic;
1045 void arm_gen_routine(const arm_code_gen_t *arm_cg, ir_graph *irg)
1047 ir_node **blk_sched;
1049 ir_node *last_block = NULL;
1050 ir_entity *entity = get_irg_entity(irg);
1053 sym_or_tv = new_set(cmp_sym_or_tv, 8);
1055 be_gas_elf_type_char = '%';
1057 arm_register_emitters();
1059 be_dbg_method_begin(entity);
1061 /* create the block schedule */
1062 blk_sched = be_create_block_schedule(irg);
1064 be_gas_emit_function_prolog(entity, 4);
1066 irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
1068 n = ARR_LEN(blk_sched);
1069 for (i = 0; i < n;) {
1070 ir_node *block, *next_bl;
1072 block = blk_sched[i];
1074 next_bl = i < n ? blk_sched[i] : NULL;
1076 /* set here the link. the emitter expects to find the next block here */
1077 set_irn_link(block, next_bl);
1078 arm_gen_block(block, last_block);
1082 /* emit SymConst values */
1083 if (set_count(sym_or_tv) > 0) {
1086 be_emit_cstring("\t.align 2\n");
1088 foreach_set(sym_or_tv, entry) {
1089 emit_constant_name(entry);
1090 be_emit_cstring(":\n");
1091 be_emit_write_line();
1093 if (entry->is_entity) {
1094 be_emit_cstring("\t.word\t");
1095 be_gas_emit_entity(entry->u.entity);
1097 be_emit_write_line();
1099 tarval *tv = entry->u.tv;
1100 int i, size = get_mode_size_bytes(get_tarval_mode(tv));
1103 /* beware: ARM fpa uses big endian format */
1104 for (i = ((size + 3) & ~3) - 4; i >= 0; i -= 4) {
1106 v = get_tarval_sub_bits(tv, i+3);
1107 v = (v << 8) | get_tarval_sub_bits(tv, i+2);
1108 v = (v << 8) | get_tarval_sub_bits(tv, i+1);
1109 v = (v << 8) | get_tarval_sub_bits(tv, i+0);
1110 be_emit_irprintf("\t.word\t%u\n", v);
1111 be_emit_write_line();
1116 be_emit_write_line();
1120 be_gas_emit_function_epilog(entity);
1121 be_dbg_method_end();
1124 void arm_init_emitter(void)
1126 FIRM_DBG_REGISTER(dbg, "firm.be.arm.emit");