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
41 #include "raw_bitset.h"
45 #include "beblocksched.h"
50 #include "arm_emitter.h"
51 #include "arm_optimize.h"
52 #include "gen_arm_emitter.h"
53 #include "arm_nodes_attr.h"
54 #include "arm_new_nodes.h"
55 #include "arm_map_regs.h"
56 #include "gen_arm_regalloc_if.h"
60 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
62 static set *sym_or_tv;
63 static arm_isa_t *isa;
65 static void arm_emit_register(const arch_register_t *reg)
67 be_emit_string(arch_register_get_name(reg));
70 void arm_emit_source_register(const ir_node *node, int pos)
72 const arch_register_t *reg = arch_get_irn_register_in(node, pos);
73 arm_emit_register(reg);
76 void arm_emit_dest_register(const ir_node *node, int pos)
78 const arch_register_t *reg = arch_get_irn_register_out(node, pos);
79 arm_emit_register(reg);
82 void arm_emit_offset(const ir_node *node)
84 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
85 assert(attr->base.is_load_store);
87 be_emit_irprintf("0x%X", attr->offset);
91 * Emit the arm fpa instruction suffix depending on the mode.
93 static void arm_emit_fpa_postfix(const ir_mode *mode)
95 int bits = get_mode_size_bits(mode);
105 void arm_emit_float_load_store_mode(const ir_node *node)
107 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
108 arm_emit_fpa_postfix(attr->load_store_mode);
111 void arm_emit_float_arithmetic_mode(const ir_node *node)
113 const arm_farith_attr_t *attr = get_arm_farith_attr_const(node);
114 arm_emit_fpa_postfix(attr->mode);
117 void arm_emit_symconst(const ir_node *node)
119 const arm_SymConst_attr_t *symconst = get_arm_SymConst_attr_const(node);
120 ir_entity *entity = symconst->entity;
122 be_gas_emit_entity(entity);
124 /* TODO do something with offset */
127 void arm_emit_load_mode(const ir_node *node)
129 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
130 ir_mode *mode = attr->load_store_mode;
131 int bits = get_mode_size_bits(mode);
132 bool is_signed = mode_is_signed(mode);
134 be_emit_string(is_signed ? "sh" : "h");
135 } else if (bits == 8) {
136 be_emit_string(is_signed ? "sb" : "b");
142 void arm_emit_store_mode(const ir_node *node)
144 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
145 ir_mode *mode = attr->load_store_mode;
146 int bits = get_mode_size_bits(mode);
148 be_emit_cstring("h");
149 } else if (bits == 8) {
150 be_emit_cstring("b");
156 static void emit_shf_mod_name(arm_shift_modifier_t mod)
159 case ARM_SHF_ASR_REG:
160 case ARM_SHF_ASR_IMM:
161 be_emit_cstring("asr");
163 case ARM_SHF_LSL_REG:
164 case ARM_SHF_LSL_IMM:
165 be_emit_cstring("lsl");
167 case ARM_SHF_LSR_REG:
168 case ARM_SHF_LSR_IMM:
169 be_emit_cstring("lsr");
171 case ARM_SHF_ROR_REG:
172 case ARM_SHF_ROR_IMM:
173 be_emit_cstring("ror");
178 panic("can't emit this shf_mod_name %d", (int) mod);
181 void arm_emit_shifter_operand(const ir_node *node)
183 const arm_shifter_operand_t *attr = get_arm_shifter_operand_attr_const(node);
185 switch (attr->shift_modifier) {
187 arm_emit_source_register(node, get_irn_arity(node) - 1);
190 unsigned val = attr->immediate_value;
191 val = (val >> attr->shift_immediate)
192 | (val << (32-attr->shift_immediate));
194 be_emit_irprintf("#0x%X", val);
197 case ARM_SHF_ASR_IMM:
198 case ARM_SHF_LSL_IMM:
199 case ARM_SHF_LSR_IMM:
200 case ARM_SHF_ROR_IMM:
201 arm_emit_source_register(node, get_irn_arity(node) - 1);
202 be_emit_cstring(", ");
203 emit_shf_mod_name(attr->shift_modifier);
204 be_emit_irprintf(" #0x%X", attr->shift_immediate);
207 case ARM_SHF_ASR_REG:
208 case ARM_SHF_LSL_REG:
209 case ARM_SHF_LSR_REG:
210 case ARM_SHF_ROR_REG:
211 arm_emit_source_register(node, get_irn_arity(node) - 2);
212 be_emit_cstring(", ");
213 emit_shf_mod_name(attr->shift_modifier);
214 be_emit_cstring(" ");
215 arm_emit_source_register(node, get_irn_arity(node) - 1);
219 arm_emit_source_register(node, get_irn_arity(node) - 1);
220 panic("RRX shifter emitter TODO");
222 case ARM_SHF_INVALID:
225 panic("Invalid shift_modifier while emitting %+F", node);
228 /** An entry in the sym_or_tv set. */
229 typedef struct sym_or_tv_t {
231 ir_entity *entity; /**< An entity. */
232 ir_tarval *tv; /**< A tarval. */
233 const void *generic; /**< For generic compare. */
235 unsigned label; /**< the associated label. */
236 bool is_entity; /**< true if an entity is stored. */
240 * Returns a unique label. This number will not be used a second time.
242 static unsigned get_unique_label(void)
244 static unsigned id = 0;
248 static void emit_constant_name(const sym_or_tv_t *entry)
250 be_emit_irprintf("%sC%u", be_gas_get_private_prefix(), entry->label);
256 static void emit_arm_SymConst(const ir_node *irn)
258 const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
259 sym_or_tv_t key, *entry;
261 key.u.entity = attr->entity;
262 key.is_entity = true;
264 entry = set_insert(sym_or_tv_t, sym_or_tv, &key, sizeof(key), hash_ptr(key.u.generic));
265 if (entry->label == 0) {
266 /* allocate a label */
267 entry->label = get_unique_label();
270 /* load the symbol indirect */
271 be_emit_cstring("\tldr ");
272 arm_emit_dest_register(irn, 0);
273 be_emit_cstring(", ");
274 emit_constant_name(entry);
275 be_emit_finish_line_gas(irn);
278 static void emit_arm_FrameAddr(const ir_node *irn)
280 const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
282 be_emit_cstring("\tadd ");
283 arm_emit_dest_register(irn, 0);
284 be_emit_cstring(", ");
285 arm_emit_source_register(irn, 0);
286 be_emit_cstring(", ");
287 be_emit_irprintf("#0x%X", attr->fp_offset);
288 be_emit_finish_line_gas(irn);
292 * Emit a floating point fpa constant.
294 static void emit_arm_fConst(const ir_node *irn)
296 sym_or_tv_t key, *entry;
299 key.u.tv = get_fConst_value(irn);
300 key.is_entity = false;
302 entry = set_insert(sym_or_tv_t, sym_or_tv, &key, sizeof(key), hash_ptr(key.u.generic));
303 if (entry->label == 0) {
304 /* allocate a label */
305 entry->label = get_unique_label();
308 /* load the tarval indirect */
309 mode = get_irn_mode(irn);
310 be_emit_cstring("\tldf");
311 arm_emit_fpa_postfix(mode);
314 arm_emit_dest_register(irn, 0);
315 be_emit_cstring(", ");
316 emit_constant_name(entry);
317 be_emit_finish_line_gas(irn);
321 * Returns the next block in a block schedule.
323 static ir_node *sched_next_block(const ir_node *block)
325 return (ir_node*)get_irn_link(block);
329 * Returns the target block for a control flow node.
331 static ir_node *get_cfop_target_block(const ir_node *irn)
333 return (ir_node*)get_irn_link(irn);
337 * Emit the target label for a control flow node.
339 static void arm_emit_cfop_target(const ir_node *irn)
341 ir_node *block = get_cfop_target_block(irn);
343 be_gas_emit_block_name(block);
347 * Emit a Compare with conditional branch.
349 static void emit_arm_B(const ir_node *irn)
351 const ir_node *proj_true = NULL;
352 const ir_node *proj_false = NULL;
353 const ir_node *block;
354 const ir_node *next_block;
355 ir_node *op1 = get_irn_n(irn, 0);
357 ir_relation relation = get_arm_CondJmp_relation(irn);
358 const arm_cmp_attr_t *cmp_attr = get_arm_cmp_attr_const(op1);
359 bool is_signed = !cmp_attr->is_unsigned;
361 assert(is_arm_Cmp(op1) || is_arm_Tst(op1));
363 foreach_out_edge(irn, edge) {
364 ir_node *proj = get_edge_src_irn(edge);
365 long nr = get_Proj_proj(proj);
366 if (nr == pn_Cond_true) {
373 if (cmp_attr->ins_permuted) {
374 relation = get_inversed_relation(relation);
377 /* for now, the code works for scheduled and non-schedules blocks */
378 block = get_nodes_block(irn);
380 /* we have a block schedule */
381 next_block = sched_next_block(block);
383 assert(relation != ir_relation_false);
384 assert(relation != ir_relation_true);
386 if (get_cfop_target_block(proj_true) == next_block) {
387 /* exchange both proj's so the second one can be omitted */
388 const ir_node *t = proj_true;
390 proj_true = proj_false;
392 relation = get_negated_relation(relation);
395 switch (relation & (ir_relation_less_equal_greater)) {
396 case ir_relation_equal: suffix = "eq"; break;
397 case ir_relation_less: suffix = is_signed ? "lt" : "lo"; break;
398 case ir_relation_less_equal: suffix = is_signed ? "le" : "ls"; break;
399 case ir_relation_greater: suffix = is_signed ? "gt" : "hi"; break;
400 case ir_relation_greater_equal: suffix = is_signed ? "ge" : "hs"; break;
401 case ir_relation_less_greater: suffix = "ne"; break;
402 case ir_relation_less_equal_greater: suffix = "al"; break;
403 default: panic("Cmp has unsupported relation");
406 /* emit the true proj */
407 be_emit_irprintf("\tb%s ", suffix);
408 arm_emit_cfop_target(proj_true);
409 be_emit_finish_line_gas(proj_true);
411 if (get_cfop_target_block(proj_false) == next_block) {
412 if (be_options.verbose_asm) {
413 be_emit_cstring("\t/* fallthrough to ");
414 arm_emit_cfop_target(proj_false);
415 be_emit_cstring(" */");
416 be_emit_finish_line_gas(proj_false);
419 be_emit_cstring("\tb ");
420 arm_emit_cfop_target(proj_false);
421 be_emit_finish_line_gas(proj_false);
425 /** Sort register in ascending order. */
426 static int reg_cmp(const void *a, const void *b)
428 const arch_register_t * const *ra = (const arch_register_t**)a;
429 const arch_register_t * const *rb = (const arch_register_t**)b;
431 return *ra < *rb ? -1 : (*ra != *rb);
435 * Create the CopyB instruction sequence.
437 static void emit_arm_CopyB(const ir_node *irn)
439 const arm_CopyB_attr_t *attr = get_arm_CopyB_attr_const(irn);
440 unsigned size = attr->size;
442 const char *tgt = arch_register_get_name(arch_get_irn_register_in(irn, 0));
443 const char *src = arch_register_get_name(arch_get_irn_register_in(irn, 1));
444 const char *t0, *t1, *t2, *t3;
446 const arch_register_t *tmpregs[4];
448 /* collect the temporary registers and sort them, we need ascending order */
449 tmpregs[0] = arch_get_irn_register_in(irn, 2);
450 tmpregs[1] = arch_get_irn_register_in(irn, 3);
451 tmpregs[2] = arch_get_irn_register_in(irn, 4);
452 tmpregs[3] = &arm_registers[REG_R12];
454 /* Note: R12 is always the last register because the RA did not assign higher ones */
455 qsort((void *)tmpregs, 3, sizeof(tmpregs[0]), reg_cmp);
457 /* need ascending order */
458 t0 = arch_register_get_name(tmpregs[0]);
459 t1 = arch_register_get_name(tmpregs[1]);
460 t2 = arch_register_get_name(tmpregs[2]);
461 t3 = arch_register_get_name(tmpregs[3]);
463 if (be_options.verbose_asm) {
464 be_emit_cstring("/* MemCopy (");
466 be_emit_cstring(")->(");
467 arm_emit_source_register(irn, 0);
468 be_emit_irprintf(" [%u bytes], Uses ", size);
470 be_emit_cstring(", ");
472 be_emit_cstring(", ");
474 be_emit_cstring(", and ");
476 be_emit_cstring("*/");
477 be_emit_finish_line_gas(NULL);
480 assert(size > 0 && "CopyB needs size > 0" );
483 fprintf(stderr, "strange hack enabled: copy more bytes than needed!");
492 be_emit_cstring("\tldr ");
494 be_emit_cstring(", [");
496 be_emit_cstring(", #0]");
497 be_emit_finish_line_gas(NULL);
499 be_emit_cstring("\tstr ");
501 be_emit_cstring(", [");
503 be_emit_cstring(", #0]");
504 be_emit_finish_line_gas(irn);
507 be_emit_cstring("\tldmia ");
509 be_emit_cstring("!, {");
511 be_emit_cstring(", ");
514 be_emit_finish_line_gas(NULL);
516 be_emit_cstring("\tstmia ");
518 be_emit_cstring("!, {");
520 be_emit_cstring(", ");
523 be_emit_finish_line_gas(irn);
526 be_emit_cstring("\tldmia ");
528 be_emit_cstring("!, {");
530 be_emit_cstring(", ");
532 be_emit_cstring(", ");
535 be_emit_finish_line_gas(NULL);
537 be_emit_cstring("\tstmia ");
539 be_emit_cstring("!, {");
541 be_emit_cstring(", ");
543 be_emit_cstring(", ");
546 be_emit_finish_line_gas(irn);
551 be_emit_cstring("\tldmia ");
553 be_emit_cstring("!, {");
555 be_emit_cstring(", ");
557 be_emit_cstring(", ");
559 be_emit_cstring(", ");
562 be_emit_finish_line_gas(NULL);
564 be_emit_cstring("\tstmia ");
566 be_emit_cstring("!, {");
568 be_emit_cstring(", ");
570 be_emit_cstring(", ");
572 be_emit_cstring(", ");
575 be_emit_finish_line_gas(irn);
580 static void emit_arm_SwitchJmp(const ir_node *irn)
582 const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(irn);
583 be_emit_cstring("\tldrls pc, [pc, ");
584 arm_emit_source_register(irn, 0);
585 be_emit_cstring(", asl #2]");
586 be_emit_finish_line_gas(irn);
588 be_emit_jump_table(irn, attr->table, NULL, get_cfop_target_block);
591 /** Emit an IncSP node */
592 static void emit_be_IncSP(const ir_node *irn)
594 int offs = -be_get_IncSP_offset(irn);
598 be_emit_cstring("\tsub ");
601 be_emit_cstring("\tadd ");
603 arm_emit_dest_register(irn, 0);
604 be_emit_cstring(", ");
605 arm_emit_source_register(irn, 0);
606 be_emit_irprintf(", #0x%X", offs);
607 be_emit_finish_line_gas(irn);
609 /* omitted IncSP(0) */
614 static void emit_be_Copy(const ir_node *irn)
616 ir_mode *mode = get_irn_mode(irn);
618 if (arch_get_irn_register_in(irn, 0) == arch_get_irn_register_out(irn, 0)) {
623 if (mode_is_float(mode)) {
625 be_emit_cstring("\tmvf");
627 arm_emit_dest_register(irn, 0);
628 be_emit_cstring(", ");
629 arm_emit_source_register(irn, 0);
630 be_emit_finish_line_gas(irn);
632 panic("emit_be_Copy: move not supported for this mode");
634 } else if (mode_is_data(mode)) {
635 be_emit_cstring("\tmov ");
636 arm_emit_dest_register(irn, 0);
637 be_emit_cstring(", ");
638 arm_emit_source_register(irn, 0);
639 be_emit_finish_line_gas(irn);
641 panic("emit_be_Copy: move not supported for this mode");
645 static void emit_be_Perm(const ir_node *irn)
647 be_emit_cstring("\teor ");
648 arm_emit_source_register(irn, 0);
649 be_emit_cstring(", ");
650 arm_emit_source_register(irn, 0);
651 be_emit_cstring(", ");
652 arm_emit_source_register(irn, 1);
653 be_emit_finish_line_gas(NULL);
655 be_emit_cstring("\teor ");
656 arm_emit_source_register(irn, 1);
657 be_emit_cstring(", ");
658 arm_emit_source_register(irn, 0);
659 be_emit_cstring(", ");
660 arm_emit_source_register(irn, 1);
661 be_emit_finish_line_gas(NULL);
663 be_emit_cstring("\teor ");
664 arm_emit_source_register(irn, 0);
665 be_emit_cstring(", ");
666 arm_emit_source_register(irn, 0);
667 be_emit_cstring(", ");
668 arm_emit_source_register(irn, 1);
669 be_emit_finish_line_gas(irn);
672 static void emit_be_MemPerm(const ir_node *node)
678 /* TODO: this implementation is slower than necessary.
679 The longterm goal is however to avoid the memperm node completely */
681 memperm_arity = be_get_MemPerm_entity_arity(node);
682 if (memperm_arity > 12)
683 panic("memperm with more than 12 inputs not supported yet");
685 for (i = 0; i < memperm_arity; ++i) {
687 ir_entity *entity = be_get_MemPerm_in_entity(node, i);
690 be_emit_irprintf("\tstr r%d, [sp, #-4]!", i);
691 be_emit_finish_line_gas(node);
693 /* load from entity */
694 offset = get_entity_offset(entity) + sp_change;
695 be_emit_irprintf("\tldr r%d, [sp, #%d]", i, offset);
696 be_emit_finish_line_gas(node);
699 for (i = memperm_arity-1; i >= 0; --i) {
701 ir_entity *entity = be_get_MemPerm_out_entity(node, i);
703 /* store to new entity */
704 offset = get_entity_offset(entity) + sp_change;
705 be_emit_irprintf("\tstr r%d, [sp, #%d]", i, offset);
706 be_emit_finish_line_gas(node);
707 /* restore register */
708 be_emit_irprintf("\tldr r%d, [sp], #4", i);
710 be_emit_finish_line_gas(node);
712 assert(sp_change == 0);
715 static void emit_be_Start(const ir_node *node)
717 ir_graph *irg = get_irn_irg(node);
718 ir_type *frame_type = get_irg_frame_type(irg);
719 unsigned size = get_type_size_bytes(frame_type);
721 /* allocate stackframe */
723 be_emit_cstring("\tsub ");
724 arm_emit_register(&arm_registers[REG_SP]);
725 be_emit_cstring(", ");
726 arm_emit_register(&arm_registers[REG_SP]);
727 be_emit_irprintf(", #0x%X", size);
728 be_emit_finish_line_gas(node);
732 static void emit_be_Return(const ir_node *node)
734 ir_graph *irg = get_irn_irg(node);
735 ir_type *frame_type = get_irg_frame_type(irg);
736 unsigned size = get_type_size_bytes(frame_type);
738 /* deallocate stackframe */
740 be_emit_cstring("\tadd ");
741 arm_emit_register(&arm_registers[REG_SP]);
742 be_emit_cstring(", ");
743 arm_emit_register(&arm_registers[REG_SP]);
744 be_emit_irprintf(", #0x%X", size);
745 be_emit_finish_line_gas(node);
748 be_emit_cstring("\tmov pc, lr");
749 be_emit_finish_line_gas(node);
753 static void emit_arm_Jmp(const ir_node *node)
755 ir_node *block, *next_block;
757 /* for now, the code works for scheduled and non-schedules blocks */
758 block = get_nodes_block(node);
760 /* we have a block schedule */
761 next_block = sched_next_block(block);
762 if (get_cfop_target_block(node) != next_block) {
763 be_emit_cstring("\tb ");
764 arm_emit_cfop_target(node);
765 be_emit_finish_line_gas(node);
767 if (be_options.verbose_asm) {
768 be_emit_cstring("\t/* fallthrough to ");
769 arm_emit_cfop_target(node);
770 be_emit_cstring(" */");
771 be_emit_finish_line_gas(node);
776 static void emit_nothing(const ir_node *irn)
782 * The type of a emitter function.
784 typedef void (emit_func)(const ir_node *irn);
787 * Set a node emitter. Make it a bit more type safe.
789 static inline void set_emitter(ir_op *op, emit_func arm_emit_node)
791 op->ops.generic = (op_func)arm_emit_node;
795 * Enters the emitter functions for handled nodes into the generic
796 * pointer of an opcode.
798 static void arm_register_emitters(void)
800 /* first clear the generic function pointer for all ops */
801 ir_clear_opcodes_generic_func();
803 /* register all emitter functions defined in spec */
804 arm_register_spec_emitters();
807 set_emitter(op_arm_B, emit_arm_B);
808 set_emitter(op_arm_CopyB, emit_arm_CopyB);
809 set_emitter(op_arm_fConst, emit_arm_fConst);
810 set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
811 set_emitter(op_arm_Jmp, emit_arm_Jmp);
812 set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
813 set_emitter(op_arm_SymConst, emit_arm_SymConst);
814 set_emitter(op_be_Copy, emit_be_Copy);
815 set_emitter(op_be_CopyKeep, emit_be_Copy);
816 set_emitter(op_be_IncSP, emit_be_IncSP);
817 set_emitter(op_be_MemPerm, emit_be_MemPerm);
818 set_emitter(op_be_Perm, emit_be_Perm);
819 set_emitter(op_be_Return, emit_be_Return);
820 set_emitter(op_be_Start, emit_be_Start);
822 /* no need to emit anything for the following nodes */
823 set_emitter(op_Phi, emit_nothing);
824 set_emitter(op_be_Keep, emit_nothing);
828 * Emits code for a node.
830 static void arm_emit_node(const ir_node *irn)
832 ir_op *op = get_irn_op(irn);
834 if (op->ops.generic) {
835 emit_func *emit = (emit_func *)op->ops.generic;
836 be_dwarf_location(get_irn_dbg_info(irn));
839 panic("Error: No emit handler for node %+F (graph %+F)\n",
840 irn, get_irn_irg(irn));
845 * emit the block label if needed.
847 static void arm_emit_block_header(ir_node *block, ir_node *prev)
849 bool need_label = false;
852 n_cfgpreds = get_Block_n_cfgpreds(block);
853 if (n_cfgpreds == 1) {
854 ir_node *pred = get_Block_cfgpred(block, 0);
855 ir_node *pred_block = get_nodes_block(pred);
857 /* we don't need labels for fallthrough blocks, however switch-jmps
858 * are no fallthroughs */
859 if (pred_block == prev &&
860 !(is_Proj(pred) && is_arm_SwitchJmp(get_Proj_pred(pred)))) {
869 be_gas_begin_block(block, need_label);
873 * Walks over the nodes in a block connected by scheduling edges
874 * and emits code for each node.
876 static void arm_gen_block(ir_node *block, ir_node *prev_block)
878 arm_emit_block_header(block, prev_block);
879 be_dwarf_location(get_irn_dbg_info(block));
880 sched_foreach(block, irn) {
887 * Sets labels for control flow nodes (jump target)
889 static void arm_gen_labels(ir_node *block, void *env)
892 int n = get_Block_n_cfgpreds(block);
895 for (n--; n >= 0; n--) {
896 pred = get_Block_cfgpred(block, n);
897 set_irn_link(pred, block);
902 * Compare two entries of the symbol or tarval set.
904 static int cmp_sym_or_tv(const void *elt, const void *key, size_t size)
906 const sym_or_tv_t *p1 = (const sym_or_tv_t*)elt;
907 const sym_or_tv_t *p2 = (const sym_or_tv_t*)key;
910 /* as an identifier NEVER can point to a tarval, it's enough
911 to compare it this way */
912 return p1->u.generic != p2->u.generic;
915 void arm_gen_routine(ir_graph *irg)
917 ir_node *last_block = NULL;
918 ir_entity *entity = get_irg_entity(irg);
919 const arch_env_t *arch_env = be_get_irg_arch_env(irg);
923 isa = (arm_isa_t*) arch_env;
924 sym_or_tv = new_set(cmp_sym_or_tv, 8);
926 be_gas_elf_type_char = '%';
928 arm_register_emitters();
930 /* create the block schedule */
931 blk_sched = be_create_block_schedule(irg);
933 be_gas_emit_function_prolog(entity, 4, NULL);
935 irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
937 n = ARR_LEN(blk_sched);
938 for (i = 0; i < n;) {
939 ir_node *block, *next_bl;
941 block = blk_sched[i];
943 next_bl = i < n ? blk_sched[i] : NULL;
945 /* set here the link. the emitter expects to find the next block here */
946 set_irn_link(block, next_bl);
947 arm_gen_block(block, last_block);
951 /* emit SymConst values */
952 if (set_count(sym_or_tv) > 0) {
953 be_emit_cstring("\t.align 2\n");
955 foreach_set(sym_or_tv, sym_or_tv_t, entry) {
956 emit_constant_name(entry);
957 be_emit_cstring(":\n");
958 be_emit_write_line();
960 if (entry->is_entity) {
961 be_emit_cstring("\t.word\t");
962 be_gas_emit_entity(entry->u.entity);
964 be_emit_write_line();
966 ir_tarval *tv = entry->u.tv;
968 int size = get_mode_size_bytes(get_tarval_mode(tv));
970 /* beware: ARM fpa uses big endian format */
971 for (vi = ((size + 3) & ~3) - 4; vi >= 0; vi -= 4) {
974 v = get_tarval_sub_bits(tv, vi+3);
975 v = (v << 8) | get_tarval_sub_bits(tv, vi+2);
976 v = (v << 8) | get_tarval_sub_bits(tv, vi+1);
977 v = (v << 8) | get_tarval_sub_bits(tv, vi+0);
978 be_emit_irprintf("\t.word\t%u\n", v);
979 be_emit_write_line();
984 be_emit_write_line();
988 be_gas_emit_function_epilog(entity);
991 void arm_init_emitter(void)
993 FIRM_DBG_REGISTER(dbg, "firm.be.arm.emit");