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"
46 #include "beblocksched.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"
61 #define SNPRINTF_BUF_LEN 128
63 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
65 static set *sym_or_tv;
66 static arm_isa_t *isa;
68 static void arm_emit_register(const arch_register_t *reg)
70 be_emit_string(arch_register_get_name(reg));
73 void arm_emit_source_register(const ir_node *node, int pos)
75 const arch_register_t *reg = arch_get_irn_register_in(node, pos);
76 arm_emit_register(reg);
79 void arm_emit_dest_register(const ir_node *node, int pos)
81 const arch_register_t *reg = arch_get_irn_register_out(node, pos);
82 arm_emit_register(reg);
85 void arm_emit_offset(const ir_node *node)
87 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
88 assert(attr->base.is_load_store);
90 be_emit_irprintf("0x%X", attr->offset);
94 * Emit the arm fpa instruction suffix depending on the mode.
96 static void arm_emit_fpa_postfix(const ir_mode *mode)
98 int bits = get_mode_size_bits(mode);
108 void arm_emit_float_load_store_mode(const ir_node *node)
110 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
111 arm_emit_fpa_postfix(attr->load_store_mode);
114 void arm_emit_float_arithmetic_mode(const ir_node *node)
116 const arm_farith_attr_t *attr = get_arm_farith_attr_const(node);
117 arm_emit_fpa_postfix(attr->mode);
120 void arm_emit_symconst(const ir_node *node)
122 const arm_SymConst_attr_t *symconst = get_arm_SymConst_attr_const(node);
123 ir_entity *entity = symconst->entity;
125 be_gas_emit_entity(entity);
127 /* TODO do something with offset */
130 void arm_emit_load_mode(const ir_node *node)
132 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
133 ir_mode *mode = attr->load_store_mode;
134 int bits = get_mode_size_bits(mode);
135 bool is_signed = mode_is_signed(mode);
137 be_emit_string(is_signed ? "sh" : "h");
138 } else if (bits == 8) {
139 be_emit_string(is_signed ? "sb" : "b");
145 void arm_emit_store_mode(const ir_node *node)
147 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
148 ir_mode *mode = attr->load_store_mode;
149 int bits = get_mode_size_bits(mode);
151 be_emit_cstring("h");
152 } else if (bits == 8) {
153 be_emit_cstring("b");
159 static void emit_shf_mod_name(arm_shift_modifier_t mod)
162 case ARM_SHF_ASR_REG:
163 case ARM_SHF_ASR_IMM:
164 be_emit_cstring("asr");
166 case ARM_SHF_LSL_REG:
167 case ARM_SHF_LSL_IMM:
168 be_emit_cstring("lsl");
170 case ARM_SHF_LSR_REG:
171 case ARM_SHF_LSR_IMM:
172 be_emit_cstring("lsr");
174 case ARM_SHF_ROR_REG:
175 case ARM_SHF_ROR_IMM:
176 be_emit_cstring("ror");
181 panic("can't emit this shf_mod_name %d", (int) mod);
184 void arm_emit_shifter_operand(const ir_node *node)
186 const arm_shifter_operand_t *attr = get_arm_shifter_operand_attr_const(node);
188 switch (attr->shift_modifier) {
190 arm_emit_source_register(node, get_irn_arity(node) - 1);
193 unsigned val = attr->immediate_value;
194 val = (val >> attr->shift_immediate)
195 | (val << (32-attr->shift_immediate));
197 be_emit_irprintf("#0x%X", val);
200 case ARM_SHF_ASR_IMM:
201 case ARM_SHF_LSL_IMM:
202 case ARM_SHF_LSR_IMM:
203 case ARM_SHF_ROR_IMM:
204 arm_emit_source_register(node, get_irn_arity(node) - 1);
205 be_emit_cstring(", ");
206 emit_shf_mod_name(attr->shift_modifier);
207 be_emit_irprintf(" #0x%X", attr->shift_immediate);
210 case ARM_SHF_ASR_REG:
211 case ARM_SHF_LSL_REG:
212 case ARM_SHF_LSR_REG:
213 case ARM_SHF_ROR_REG:
214 arm_emit_source_register(node, get_irn_arity(node) - 2);
215 be_emit_cstring(", ");
216 emit_shf_mod_name(attr->shift_modifier);
217 be_emit_cstring(" ");
218 arm_emit_source_register(node, get_irn_arity(node) - 1);
222 arm_emit_source_register(node, get_irn_arity(node) - 1);
223 panic("RRX shifter emitter TODO");
225 case ARM_SHF_INVALID:
228 panic("Invalid shift_modifier while emitting %+F", node);
231 /** An entry in the sym_or_tv set. */
232 typedef struct sym_or_tv_t {
234 ir_entity *entity; /**< An entity. */
235 ir_tarval *tv; /**< A tarval. */
236 const void *generic; /**< For generic compare. */
238 unsigned label; /**< the associated label. */
239 bool is_entity; /**< true if an entity is stored. */
243 * Returns a unique label. This number will not be used a second time.
245 static unsigned get_unique_label(void)
247 static unsigned id = 0;
251 static void emit_constant_name(const sym_or_tv_t *entry)
253 be_emit_irprintf("%sC%u", be_gas_get_private_prefix(), entry->label);
259 static void emit_arm_SymConst(const ir_node *irn)
261 const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
262 sym_or_tv_t key, *entry;
264 key.u.entity = attr->entity;
265 key.is_entity = true;
267 entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
268 if (entry->label == 0) {
269 /* allocate a label */
270 entry->label = get_unique_label();
273 /* load the symbol indirect */
274 be_emit_cstring("\tldr ");
275 arm_emit_dest_register(irn, 0);
276 be_emit_cstring(", ");
277 emit_constant_name(entry);
278 be_emit_finish_line_gas(irn);
281 static void emit_arm_FrameAddr(const ir_node *irn)
283 const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
285 be_emit_cstring("\tadd ");
286 arm_emit_dest_register(irn, 0);
287 be_emit_cstring(", ");
288 arm_emit_source_register(irn, 0);
289 be_emit_cstring(", ");
290 be_emit_irprintf("#0x%X", attr->fp_offset);
291 be_emit_finish_line_gas(irn);
295 * Emit a floating point fpa constant.
297 static void emit_arm_fConst(const ir_node *irn)
299 sym_or_tv_t key, *entry;
302 key.u.tv = get_fConst_value(irn);
303 key.is_entity = false;
305 entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
306 if (entry->label == 0) {
307 /* allocate a label */
308 entry->label = get_unique_label();
311 /* load the tarval indirect */
312 mode = get_irn_mode(irn);
313 be_emit_cstring("\tldf");
314 arm_emit_fpa_postfix(mode);
317 arm_emit_dest_register(irn, 0);
318 be_emit_cstring(", ");
319 emit_constant_name(entry);
320 be_emit_finish_line_gas(irn);
324 * Returns the next block in a block schedule.
326 static ir_node *sched_next_block(const ir_node *block)
328 return (ir_node*)get_irn_link(block);
332 * Returns the target block for a control flow node.
334 static ir_node *get_cfop_target_block(const ir_node *irn)
336 return (ir_node*)get_irn_link(irn);
340 * Emit the target label for a control flow node.
342 static void arm_emit_cfop_target(const ir_node *irn)
344 ir_node *block = get_cfop_target_block(irn);
346 be_gas_emit_block_name(block);
350 * Emit a Compare with conditional branch.
352 static void emit_arm_B(const ir_node *irn)
354 const ir_edge_t *edge;
355 const ir_node *proj_true = NULL;
356 const ir_node *proj_false = NULL;
357 const ir_node *block;
358 const ir_node *next_block;
359 ir_node *op1 = get_irn_n(irn, 0);
361 ir_relation relation = get_arm_CondJmp_relation(irn);
362 const arm_cmp_attr_t *cmp_attr = get_arm_cmp_attr_const(op1);
363 bool is_signed = !cmp_attr->is_unsigned;
365 assert(is_arm_Cmp(op1) || is_arm_Tst(op1));
367 foreach_out_edge(irn, edge) {
368 ir_node *proj = get_edge_src_irn(edge);
369 long nr = get_Proj_proj(proj);
370 if (nr == pn_Cond_true) {
377 if (cmp_attr->ins_permuted) {
378 relation = get_inversed_relation(relation);
381 /* for now, the code works for scheduled and non-schedules blocks */
382 block = get_nodes_block(irn);
384 /* we have a block schedule */
385 next_block = sched_next_block(block);
387 assert(relation != ir_relation_false);
388 assert(relation != ir_relation_true);
390 if (get_cfop_target_block(proj_true) == next_block) {
391 /* exchange both proj's so the second one can be omitted */
392 const ir_node *t = proj_true;
394 proj_true = proj_false;
396 relation = get_negated_relation(relation);
399 switch (relation & (ir_relation_less_equal_greater)) {
400 case ir_relation_equal: suffix = "eq"; break;
401 case ir_relation_less: suffix = is_signed ? "lt" : "lo"; break;
402 case ir_relation_less_equal: suffix = is_signed ? "le" : "ls"; break;
403 case ir_relation_greater: suffix = is_signed ? "gt" : "hi"; break;
404 case ir_relation_greater_equal: suffix = is_signed ? "ge" : "hs"; break;
405 case ir_relation_less_greater: suffix = "ne"; break;
406 case ir_relation_less_equal_greater: suffix = "al"; break;
407 default: panic("Cmp has unsupported relation");
410 /* emit the true proj */
411 be_emit_irprintf("\tb%s ", suffix);
412 arm_emit_cfop_target(proj_true);
413 be_emit_finish_line_gas(proj_true);
415 if (get_cfop_target_block(proj_false) == next_block) {
416 be_emit_cstring("\t/* fallthrough to ");
417 arm_emit_cfop_target(proj_false);
418 be_emit_cstring(" */");
419 be_emit_finish_line_gas(proj_false);
421 be_emit_cstring("\tb ");
422 arm_emit_cfop_target(proj_false);
423 be_emit_finish_line_gas(proj_false);
427 /** Sort register in ascending order. */
428 static int reg_cmp(const void *a, const void *b)
430 const arch_register_t * const *ra = (const arch_register_t**)a;
431 const arch_register_t * const *rb = (const arch_register_t**)b;
433 return *ra < *rb ? -1 : (*ra != *rb);
437 * Create the CopyB instruction sequence.
439 static void emit_arm_CopyB(const ir_node *irn)
441 const arm_CopyB_attr_t *attr = get_arm_CopyB_attr_const(irn);
442 unsigned size = attr->size;
444 const char *tgt = arch_register_get_name(arch_get_irn_register_in(irn, 0));
445 const char *src = arch_register_get_name(arch_get_irn_register_in(irn, 1));
446 const char *t0, *t1, *t2, *t3;
448 const arch_register_t *tmpregs[4];
450 /* collect the temporary registers and sort them, we need ascending order */
451 tmpregs[0] = arch_get_irn_register_in(irn, 2);
452 tmpregs[1] = arch_get_irn_register_in(irn, 3);
453 tmpregs[2] = arch_get_irn_register_in(irn, 4);
454 tmpregs[3] = &arm_registers[REG_R12];
456 /* Note: R12 is always the last register because the RA did not assign higher ones */
457 qsort((void *)tmpregs, 3, sizeof(tmpregs[0]), reg_cmp);
459 /* need ascending order */
460 t0 = arch_register_get_name(tmpregs[0]);
461 t1 = arch_register_get_name(tmpregs[1]);
462 t2 = arch_register_get_name(tmpregs[2]);
463 t3 = arch_register_get_name(tmpregs[3]);
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);
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);
766 be_emit_cstring("\t/* fallthrough to ");
767 arm_emit_cfop_target(node);
768 be_emit_cstring(" */");
770 be_emit_finish_line_gas(node);
773 static void emit_nothing(const ir_node *irn)
779 * The type of a emitter function.
781 typedef void (emit_func)(const ir_node *irn);
784 * Set a node emitter. Make it a bit more type safe.
786 static inline void set_emitter(ir_op *op, emit_func arm_emit_node)
788 op->ops.generic = (op_func)arm_emit_node;
792 * Enters the emitter functions for handled nodes into the generic
793 * pointer of an opcode.
795 static void arm_register_emitters(void)
797 /* first clear the generic function pointer for all ops */
798 clear_irp_opcodes_generic_func();
800 /* register all emitter functions defined in spec */
801 arm_register_spec_emitters();
804 set_emitter(op_arm_B, emit_arm_B);
805 set_emitter(op_arm_CopyB, emit_arm_CopyB);
806 set_emitter(op_arm_fConst, emit_arm_fConst);
807 set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
808 set_emitter(op_arm_Jmp, emit_arm_Jmp);
809 set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
810 set_emitter(op_arm_SymConst, emit_arm_SymConst);
811 set_emitter(op_be_Copy, emit_be_Copy);
812 set_emitter(op_be_CopyKeep, emit_be_Copy);
813 set_emitter(op_be_IncSP, emit_be_IncSP);
814 set_emitter(op_be_MemPerm, emit_be_MemPerm);
815 set_emitter(op_be_Perm, emit_be_Perm);
816 set_emitter(op_be_Return, emit_be_Return);
817 set_emitter(op_be_Start, emit_be_Start);
819 /* no need to emit anything for the following nodes */
820 set_emitter(op_Phi, emit_nothing);
821 set_emitter(op_be_Keep, emit_nothing);
825 * Emits code for a node.
827 static void arm_emit_node(const ir_node *irn)
829 ir_op *op = get_irn_op(irn);
831 if (op->ops.generic) {
832 emit_func *emit = (emit_func *)op->ops.generic;
833 be_dbg_set_dbg_info(get_irn_dbg_info(irn));
836 panic("Error: No emit handler for node %+F (graph %+F)\n",
837 irn, current_ir_graph);
842 * emit the block label if needed.
844 static void arm_emit_block_header(ir_node *block, ir_node *prev)
849 ir_graph *irg = get_irn_irg(block);
850 ir_exec_freq *exec_freq = be_get_irg_exec_freq(irg);
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)))) {
871 be_gas_emit_block_name(block);
874 be_emit_pad_comment();
875 be_emit_cstring(" /* preds:");
877 /* emit list of pred blocks in comment */
878 arity = get_irn_arity(block);
879 for (i = 0; i < arity; ++i) {
880 ir_node *predblock = get_Block_cfgpred_block(block, i);
881 be_emit_irprintf(" %d", get_irn_node_nr(predblock));
884 be_emit_cstring("\t/* ");
885 be_gas_emit_block_name(block);
886 be_emit_cstring(": ");
888 if (exec_freq != NULL) {
889 be_emit_irprintf(" freq: %f",
890 get_block_execfreq(exec_freq, block));
892 be_emit_cstring(" */\n");
893 be_emit_write_line();
897 * Walks over the nodes in a block connected by scheduling edges
898 * and emits code for each node.
900 static void arm_gen_block(ir_node *block, ir_node *prev_block)
904 arm_emit_block_header(block, prev_block);
905 be_dbg_set_dbg_info(get_irn_dbg_info(block));
906 sched_foreach(block, irn) {
913 * Sets labels for control flow nodes (jump target)
915 static void arm_gen_labels(ir_node *block, void *env)
918 int n = get_Block_n_cfgpreds(block);
921 for (n--; n >= 0; n--) {
922 pred = get_Block_cfgpred(block, n);
923 set_irn_link(pred, block);
928 * Compare two entries of the symbol or tarval set.
930 static int cmp_sym_or_tv(const void *elt, const void *key, size_t size)
932 const sym_or_tv_t *p1 = (const sym_or_tv_t*)elt;
933 const sym_or_tv_t *p2 = (const sym_or_tv_t*)key;
936 /* as an identifier NEVER can point to a tarval, it's enough
937 to compare it this way */
938 return p1->u.generic != p2->u.generic;
941 void arm_gen_routine(ir_graph *irg)
943 ir_node *last_block = NULL;
944 ir_entity *entity = get_irg_entity(irg);
945 const arch_env_t *arch_env = be_get_irg_arch_env(irg);
949 isa = (arm_isa_t*) arch_env;
950 sym_or_tv = new_set(cmp_sym_or_tv, 8);
952 be_gas_elf_type_char = '%';
954 arm_register_emitters();
956 /* create the block schedule */
957 blk_sched = be_create_block_schedule(irg);
959 be_gas_emit_function_prolog(entity, 4);
961 irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
963 n = ARR_LEN(blk_sched);
964 for (i = 0; i < n;) {
965 ir_node *block, *next_bl;
967 block = blk_sched[i];
969 next_bl = i < n ? blk_sched[i] : NULL;
971 /* set here the link. the emitter expects to find the next block here */
972 set_irn_link(block, next_bl);
973 arm_gen_block(block, last_block);
977 /* emit SymConst values */
978 if (set_count(sym_or_tv) > 0) {
981 be_emit_cstring("\t.align 2\n");
983 foreach_set(sym_or_tv, sym_or_tv_t*, entry) {
984 emit_constant_name(entry);
985 be_emit_cstring(":\n");
986 be_emit_write_line();
988 if (entry->is_entity) {
989 be_emit_cstring("\t.word\t");
990 be_gas_emit_entity(entry->u.entity);
992 be_emit_write_line();
994 ir_tarval *tv = entry->u.tv;
996 int size = get_mode_size_bytes(get_tarval_mode(tv));
998 /* beware: ARM fpa uses big endian format */
999 for (vi = ((size + 3) & ~3) - 4; vi >= 0; vi -= 4) {
1002 v = get_tarval_sub_bits(tv, vi+3);
1003 v = (v << 8) | get_tarval_sub_bits(tv, vi+2);
1004 v = (v << 8) | get_tarval_sub_bits(tv, vi+1);
1005 v = (v << 8) | get_tarval_sub_bits(tv, vi+0);
1006 be_emit_irprintf("\t.word\t%u\n", v);
1007 be_emit_write_line();
1012 be_emit_write_line();
1016 be_gas_emit_function_epilog(entity);
1019 void arm_init_emitter(void)
1021 FIRM_DBG_REGISTER(dbg, "firm.be.arm.emit");