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 = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), hash_ptr(key.u.generic));
265 if (entry->label == 0) {
266 /* allocate a label */
267 entry->label = get_unique_label();
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 = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), hash_ptr(key.u.generic));
303 if (entry->label == 0) {
304 /* allocate a label */
305 entry->label = get_unique_label();
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_edge_t *edge;
352 const ir_node *proj_true = NULL;
353 const ir_node *proj_false = NULL;
354 const ir_node *block;
355 const ir_node *next_block;
356 ir_node *op1 = get_irn_n(irn, 0);
358 ir_relation relation = get_arm_CondJmp_relation(irn);
359 const arm_cmp_attr_t *cmp_attr = get_arm_cmp_attr_const(op1);
360 bool is_signed = !cmp_attr->is_unsigned;
362 assert(is_arm_Cmp(op1) || is_arm_Tst(op1));
364 foreach_out_edge(irn, edge) {
365 ir_node *proj = get_edge_src_irn(edge);
366 long nr = get_Proj_proj(proj);
367 if (nr == pn_Cond_true) {
374 if (cmp_attr->ins_permuted) {
375 relation = get_inversed_relation(relation);
378 /* for now, the code works for scheduled and non-schedules blocks */
379 block = get_nodes_block(irn);
381 /* we have a block schedule */
382 next_block = sched_next_block(block);
384 assert(relation != ir_relation_false);
385 assert(relation != ir_relation_true);
387 if (get_cfop_target_block(proj_true) == next_block) {
388 /* exchange both proj's so the second one can be omitted */
389 const ir_node *t = proj_true;
391 proj_true = proj_false;
393 relation = get_negated_relation(relation);
396 switch (relation & (ir_relation_less_equal_greater)) {
397 case ir_relation_equal: suffix = "eq"; break;
398 case ir_relation_less: suffix = is_signed ? "lt" : "lo"; break;
399 case ir_relation_less_equal: suffix = is_signed ? "le" : "ls"; break;
400 case ir_relation_greater: suffix = is_signed ? "gt" : "hi"; break;
401 case ir_relation_greater_equal: suffix = is_signed ? "ge" : "hs"; break;
402 case ir_relation_less_greater: suffix = "ne"; break;
403 case ir_relation_less_equal_greater: suffix = "al"; break;
404 default: panic("Cmp has unsupported relation");
407 /* emit the true proj */
408 be_emit_irprintf("\tb%s ", suffix);
409 arm_emit_cfop_target(proj_true);
410 be_emit_finish_line_gas(proj_true);
412 if (get_cfop_target_block(proj_false) == next_block) {
413 if (be_options.verbose_asm) {
414 be_emit_cstring("\t/* fallthrough to ");
415 arm_emit_cfop_target(proj_false);
416 be_emit_cstring(" */");
417 be_emit_finish_line_gas(proj_false);
420 be_emit_cstring("\tb ");
421 arm_emit_cfop_target(proj_false);
422 be_emit_finish_line_gas(proj_false);
426 /** Sort register in ascending order. */
427 static int reg_cmp(const void *a, const void *b)
429 const arch_register_t * const *ra = (const arch_register_t**)a;
430 const arch_register_t * const *rb = (const arch_register_t**)b;
432 return *ra < *rb ? -1 : (*ra != *rb);
436 * Create the CopyB instruction sequence.
438 static void emit_arm_CopyB(const ir_node *irn)
440 const arm_CopyB_attr_t *attr = get_arm_CopyB_attr_const(irn);
441 unsigned size = attr->size;
443 const char *tgt = arch_register_get_name(arch_get_irn_register_in(irn, 0));
444 const char *src = arch_register_get_name(arch_get_irn_register_in(irn, 1));
445 const char *t0, *t1, *t2, *t3;
447 const arch_register_t *tmpregs[4];
449 /* collect the temporary registers and sort them, we need ascending order */
450 tmpregs[0] = arch_get_irn_register_in(irn, 2);
451 tmpregs[1] = arch_get_irn_register_in(irn, 3);
452 tmpregs[2] = arch_get_irn_register_in(irn, 4);
453 tmpregs[3] = &arm_registers[REG_R12];
455 /* Note: R12 is always the last register because the RA did not assign higher ones */
456 qsort((void *)tmpregs, 3, sizeof(tmpregs[0]), reg_cmp);
458 /* need ascending order */
459 t0 = arch_register_get_name(tmpregs[0]);
460 t1 = arch_register_get_name(tmpregs[1]);
461 t2 = arch_register_get_name(tmpregs[2]);
462 t3 = arch_register_get_name(tmpregs[3]);
464 if (be_options.verbose_asm) {
465 be_emit_cstring("/* MemCopy (");
467 be_emit_cstring(")->(");
468 arm_emit_source_register(irn, 0);
469 be_emit_irprintf(" [%u bytes], Uses ", size);
471 be_emit_cstring(", ");
473 be_emit_cstring(", ");
475 be_emit_cstring(", and ");
477 be_emit_cstring("*/");
478 be_emit_finish_line_gas(NULL);
481 assert(size > 0 && "CopyB needs size > 0" );
484 fprintf(stderr, "strange hack enabled: copy more bytes than needed!");
493 be_emit_cstring("\tldr ");
495 be_emit_cstring(", [");
497 be_emit_cstring(", #0]");
498 be_emit_finish_line_gas(NULL);
500 be_emit_cstring("\tstr ");
502 be_emit_cstring(", [");
504 be_emit_cstring(", #0]");
505 be_emit_finish_line_gas(irn);
508 be_emit_cstring("\tldmia ");
510 be_emit_cstring("!, {");
512 be_emit_cstring(", ");
515 be_emit_finish_line_gas(NULL);
517 be_emit_cstring("\tstmia ");
519 be_emit_cstring("!, {");
521 be_emit_cstring(", ");
524 be_emit_finish_line_gas(irn);
527 be_emit_cstring("\tldmia ");
529 be_emit_cstring("!, {");
531 be_emit_cstring(", ");
533 be_emit_cstring(", ");
536 be_emit_finish_line_gas(NULL);
538 be_emit_cstring("\tstmia ");
540 be_emit_cstring("!, {");
542 be_emit_cstring(", ");
544 be_emit_cstring(", ");
547 be_emit_finish_line_gas(irn);
552 be_emit_cstring("\tldmia ");
554 be_emit_cstring("!, {");
556 be_emit_cstring(", ");
558 be_emit_cstring(", ");
560 be_emit_cstring(", ");
563 be_emit_finish_line_gas(NULL);
565 be_emit_cstring("\tstmia ");
567 be_emit_cstring("!, {");
569 be_emit_cstring(", ");
571 be_emit_cstring(", ");
573 be_emit_cstring(", ");
576 be_emit_finish_line_gas(irn);
581 static void emit_arm_SwitchJmp(const ir_node *irn)
583 const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(irn);
584 be_emit_cstring("\tldrls pc, [pc, ");
585 arm_emit_source_register(irn, 0);
586 be_emit_cstring(", asl #2]");
587 be_emit_finish_line_gas(irn);
589 be_emit_jump_table(irn, attr->table, NULL, get_cfop_target_block);
592 /** Emit an IncSP node */
593 static void emit_be_IncSP(const ir_node *irn)
595 int offs = -be_get_IncSP_offset(irn);
599 be_emit_cstring("\tsub ");
602 be_emit_cstring("\tadd ");
604 arm_emit_dest_register(irn, 0);
605 be_emit_cstring(", ");
606 arm_emit_source_register(irn, 0);
607 be_emit_irprintf(", #0x%X", offs);
608 be_emit_finish_line_gas(irn);
610 /* omitted IncSP(0) */
615 static void emit_be_Copy(const ir_node *irn)
617 ir_mode *mode = get_irn_mode(irn);
619 if (arch_get_irn_register_in(irn, 0) == arch_get_irn_register_out(irn, 0)) {
624 if (mode_is_float(mode)) {
626 be_emit_cstring("\tmvf");
628 arm_emit_dest_register(irn, 0);
629 be_emit_cstring(", ");
630 arm_emit_source_register(irn, 0);
631 be_emit_finish_line_gas(irn);
633 panic("emit_be_Copy: move not supported for this mode");
635 } else if (mode_is_data(mode)) {
636 be_emit_cstring("\tmov ");
637 arm_emit_dest_register(irn, 0);
638 be_emit_cstring(", ");
639 arm_emit_source_register(irn, 0);
640 be_emit_finish_line_gas(irn);
642 panic("emit_be_Copy: move not supported for this mode");
646 static void emit_be_Perm(const ir_node *irn)
648 be_emit_cstring("\teor ");
649 arm_emit_source_register(irn, 0);
650 be_emit_cstring(", ");
651 arm_emit_source_register(irn, 0);
652 be_emit_cstring(", ");
653 arm_emit_source_register(irn, 1);
654 be_emit_finish_line_gas(NULL);
656 be_emit_cstring("\teor ");
657 arm_emit_source_register(irn, 1);
658 be_emit_cstring(", ");
659 arm_emit_source_register(irn, 0);
660 be_emit_cstring(", ");
661 arm_emit_source_register(irn, 1);
662 be_emit_finish_line_gas(NULL);
664 be_emit_cstring("\teor ");
665 arm_emit_source_register(irn, 0);
666 be_emit_cstring(", ");
667 arm_emit_source_register(irn, 0);
668 be_emit_cstring(", ");
669 arm_emit_source_register(irn, 1);
670 be_emit_finish_line_gas(irn);
673 static void emit_be_MemPerm(const ir_node *node)
679 /* TODO: this implementation is slower than necessary.
680 The longterm goal is however to avoid the memperm node completely */
682 memperm_arity = be_get_MemPerm_entity_arity(node);
683 if (memperm_arity > 12)
684 panic("memperm with more than 12 inputs not supported yet");
686 for (i = 0; i < memperm_arity; ++i) {
688 ir_entity *entity = be_get_MemPerm_in_entity(node, i);
691 be_emit_irprintf("\tstr r%d, [sp, #-4]!", i);
692 be_emit_finish_line_gas(node);
694 /* load from entity */
695 offset = get_entity_offset(entity) + sp_change;
696 be_emit_irprintf("\tldr r%d, [sp, #%d]", i, offset);
697 be_emit_finish_line_gas(node);
700 for (i = memperm_arity-1; i >= 0; --i) {
702 ir_entity *entity = be_get_MemPerm_out_entity(node, i);
704 /* store to new entity */
705 offset = get_entity_offset(entity) + sp_change;
706 be_emit_irprintf("\tstr r%d, [sp, #%d]", i, offset);
707 be_emit_finish_line_gas(node);
708 /* restore register */
709 be_emit_irprintf("\tldr r%d, [sp], #4", i);
711 be_emit_finish_line_gas(node);
713 assert(sp_change == 0);
716 static void emit_be_Start(const ir_node *node)
718 ir_graph *irg = get_irn_irg(node);
719 ir_type *frame_type = get_irg_frame_type(irg);
720 unsigned size = get_type_size_bytes(frame_type);
722 /* allocate stackframe */
724 be_emit_cstring("\tsub ");
725 arm_emit_register(&arm_registers[REG_SP]);
726 be_emit_cstring(", ");
727 arm_emit_register(&arm_registers[REG_SP]);
728 be_emit_irprintf(", #0x%X", size);
729 be_emit_finish_line_gas(node);
733 static void emit_be_Return(const ir_node *node)
735 ir_graph *irg = get_irn_irg(node);
736 ir_type *frame_type = get_irg_frame_type(irg);
737 unsigned size = get_type_size_bytes(frame_type);
739 /* deallocate stackframe */
741 be_emit_cstring("\tadd ");
742 arm_emit_register(&arm_registers[REG_SP]);
743 be_emit_cstring(", ");
744 arm_emit_register(&arm_registers[REG_SP]);
745 be_emit_irprintf(", #0x%X", size);
746 be_emit_finish_line_gas(node);
749 be_emit_cstring("\tmov pc, lr");
750 be_emit_finish_line_gas(node);
754 static void emit_arm_Jmp(const ir_node *node)
756 ir_node *block, *next_block;
758 /* for now, the code works for scheduled and non-schedules blocks */
759 block = get_nodes_block(node);
761 /* we have a block schedule */
762 next_block = sched_next_block(block);
763 if (get_cfop_target_block(node) != next_block) {
764 be_emit_cstring("\tb ");
765 arm_emit_cfop_target(node);
766 be_emit_finish_line_gas(node);
768 if (be_options.verbose_asm) {
769 be_emit_cstring("\t/* fallthrough to ");
770 arm_emit_cfop_target(node);
771 be_emit_cstring(" */");
772 be_emit_finish_line_gas(node);
777 static void emit_nothing(const ir_node *irn)
783 * The type of a emitter function.
785 typedef void (emit_func)(const ir_node *irn);
788 * Set a node emitter. Make it a bit more type safe.
790 static inline void set_emitter(ir_op *op, emit_func arm_emit_node)
792 op->ops.generic = (op_func)arm_emit_node;
796 * Enters the emitter functions for handled nodes into the generic
797 * pointer of an opcode.
799 static void arm_register_emitters(void)
801 /* first clear the generic function pointer for all ops */
802 ir_clear_opcodes_generic_func();
804 /* register all emitter functions defined in spec */
805 arm_register_spec_emitters();
808 set_emitter(op_arm_B, emit_arm_B);
809 set_emitter(op_arm_CopyB, emit_arm_CopyB);
810 set_emitter(op_arm_fConst, emit_arm_fConst);
811 set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
812 set_emitter(op_arm_Jmp, emit_arm_Jmp);
813 set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
814 set_emitter(op_arm_SymConst, emit_arm_SymConst);
815 set_emitter(op_be_Copy, emit_be_Copy);
816 set_emitter(op_be_CopyKeep, emit_be_Copy);
817 set_emitter(op_be_IncSP, emit_be_IncSP);
818 set_emitter(op_be_MemPerm, emit_be_MemPerm);
819 set_emitter(op_be_Perm, emit_be_Perm);
820 set_emitter(op_be_Return, emit_be_Return);
821 set_emitter(op_be_Start, emit_be_Start);
823 /* no need to emit anything for the following nodes */
824 set_emitter(op_Phi, emit_nothing);
825 set_emitter(op_be_Keep, emit_nothing);
829 * Emits code for a node.
831 static void arm_emit_node(const ir_node *irn)
833 ir_op *op = get_irn_op(irn);
835 if (op->ops.generic) {
836 emit_func *emit = (emit_func *)op->ops.generic;
837 be_dwarf_location(get_irn_dbg_info(irn));
840 panic("Error: No emit handler for node %+F (graph %+F)\n",
841 irn, get_irn_irg(irn));
846 * emit the block label if needed.
848 static void arm_emit_block_header(ir_node *block, ir_node *prev)
850 bool need_label = false;
853 n_cfgpreds = get_Block_n_cfgpreds(block);
854 if (n_cfgpreds == 1) {
855 ir_node *pred = get_Block_cfgpred(block, 0);
856 ir_node *pred_block = get_nodes_block(pred);
858 /* we don't need labels for fallthrough blocks, however switch-jmps
859 * are no fallthroughs */
860 if (pred_block == prev &&
861 !(is_Proj(pred) && is_arm_SwitchJmp(get_Proj_pred(pred)))) {
870 be_gas_begin_block(block, need_label);
874 * Walks over the nodes in a block connected by scheduling edges
875 * and emits code for each node.
877 static void arm_gen_block(ir_node *block, ir_node *prev_block)
881 arm_emit_block_header(block, prev_block);
882 be_dwarf_location(get_irn_dbg_info(block));
883 sched_foreach(block, irn) {
890 * Sets labels for control flow nodes (jump target)
892 static void arm_gen_labels(ir_node *block, void *env)
895 int n = get_Block_n_cfgpreds(block);
898 for (n--; n >= 0; n--) {
899 pred = get_Block_cfgpred(block, n);
900 set_irn_link(pred, block);
905 * Compare two entries of the symbol or tarval set.
907 static int cmp_sym_or_tv(const void *elt, const void *key, size_t size)
909 const sym_or_tv_t *p1 = (const sym_or_tv_t*)elt;
910 const sym_or_tv_t *p2 = (const sym_or_tv_t*)key;
913 /* as an identifier NEVER can point to a tarval, it's enough
914 to compare it this way */
915 return p1->u.generic != p2->u.generic;
918 void arm_gen_routine(ir_graph *irg)
920 ir_node *last_block = NULL;
921 ir_entity *entity = get_irg_entity(irg);
922 const arch_env_t *arch_env = be_get_irg_arch_env(irg);
926 isa = (arm_isa_t*) arch_env;
927 sym_or_tv = new_set(cmp_sym_or_tv, 8);
929 be_gas_elf_type_char = '%';
931 arm_register_emitters();
933 /* create the block schedule */
934 blk_sched = be_create_block_schedule(irg);
936 be_gas_emit_function_prolog(entity, 4, NULL);
938 irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
940 n = ARR_LEN(blk_sched);
941 for (i = 0; i < n;) {
942 ir_node *block, *next_bl;
944 block = blk_sched[i];
946 next_bl = i < n ? blk_sched[i] : NULL;
948 /* set here the link. the emitter expects to find the next block here */
949 set_irn_link(block, next_bl);
950 arm_gen_block(block, last_block);
954 /* emit SymConst values */
955 if (set_count(sym_or_tv) > 0) {
958 be_emit_cstring("\t.align 2\n");
960 foreach_set(sym_or_tv, sym_or_tv_t*, entry) {
961 emit_constant_name(entry);
962 be_emit_cstring(":\n");
963 be_emit_write_line();
965 if (entry->is_entity) {
966 be_emit_cstring("\t.word\t");
967 be_gas_emit_entity(entry->u.entity);
969 be_emit_write_line();
971 ir_tarval *tv = entry->u.tv;
973 int size = get_mode_size_bytes(get_tarval_mode(tv));
975 /* beware: ARM fpa uses big endian format */
976 for (vi = ((size + 3) & ~3) - 4; vi >= 0; vi -= 4) {
979 v = get_tarval_sub_bits(tv, vi+3);
980 v = (v << 8) | get_tarval_sub_bits(tv, vi+2);
981 v = (v << 8) | get_tarval_sub_bits(tv, vi+1);
982 v = (v << 8) | get_tarval_sub_bits(tv, vi+0);
983 be_emit_irprintf("\t.word\t%u\n", v);
984 be_emit_write_line();
989 be_emit_write_line();
993 be_gas_emit_function_epilog(entity);
996 void arm_init_emitter(void)
998 FIRM_DBG_REGISTER(dbg, "firm.be.arm.emit");