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 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);
418 be_emit_cstring("\tb ");
419 arm_emit_cfop_target(proj_false);
420 be_emit_finish_line_gas(proj_false);
424 /** Sort register in ascending order. */
425 static int reg_cmp(const void *a, const void *b)
427 const arch_register_t * const *ra = (const arch_register_t**)a;
428 const arch_register_t * const *rb = (const arch_register_t**)b;
430 return *ra < *rb ? -1 : (*ra != *rb);
434 * Create the CopyB instruction sequence.
436 static void emit_arm_CopyB(const ir_node *irn)
438 const arm_CopyB_attr_t *attr = get_arm_CopyB_attr_const(irn);
439 unsigned size = attr->size;
441 const char *tgt = arch_register_get_name(arch_get_irn_register_in(irn, 0));
442 const char *src = arch_register_get_name(arch_get_irn_register_in(irn, 1));
443 const char *t0, *t1, *t2, *t3;
445 const arch_register_t *tmpregs[4];
447 /* collect the temporary registers and sort them, we need ascending order */
448 tmpregs[0] = arch_get_irn_register_in(irn, 2);
449 tmpregs[1] = arch_get_irn_register_in(irn, 3);
450 tmpregs[2] = arch_get_irn_register_in(irn, 4);
451 tmpregs[3] = &arm_registers[REG_R12];
453 /* Note: R12 is always the last register because the RA did not assign higher ones */
454 qsort((void *)tmpregs, 3, sizeof(tmpregs[0]), reg_cmp);
456 /* need ascending order */
457 t0 = arch_register_get_name(tmpregs[0]);
458 t1 = arch_register_get_name(tmpregs[1]);
459 t2 = arch_register_get_name(tmpregs[2]);
460 t3 = arch_register_get_name(tmpregs[3]);
462 be_emit_cstring("/* MemCopy (");
464 be_emit_cstring(")->(");
465 arm_emit_source_register(irn, 0);
466 be_emit_irprintf(" [%u bytes], Uses ", size);
468 be_emit_cstring(", ");
470 be_emit_cstring(", ");
472 be_emit_cstring(", and ");
474 be_emit_cstring("*/");
475 be_emit_finish_line_gas(NULL);
477 assert(size > 0 && "CopyB needs size > 0" );
480 fprintf(stderr, "strange hack enabled: copy more bytes than needed!");
489 be_emit_cstring("\tldr ");
491 be_emit_cstring(", [");
493 be_emit_cstring(", #0]");
494 be_emit_finish_line_gas(NULL);
496 be_emit_cstring("\tstr ");
498 be_emit_cstring(", [");
500 be_emit_cstring(", #0]");
501 be_emit_finish_line_gas(irn);
504 be_emit_cstring("\tldmia ");
506 be_emit_cstring("!, {");
508 be_emit_cstring(", ");
511 be_emit_finish_line_gas(NULL);
513 be_emit_cstring("\tstmia ");
515 be_emit_cstring("!, {");
517 be_emit_cstring(", ");
520 be_emit_finish_line_gas(irn);
523 be_emit_cstring("\tldmia ");
525 be_emit_cstring("!, {");
527 be_emit_cstring(", ");
529 be_emit_cstring(", ");
532 be_emit_finish_line_gas(NULL);
534 be_emit_cstring("\tstmia ");
536 be_emit_cstring("!, {");
538 be_emit_cstring(", ");
540 be_emit_cstring(", ");
543 be_emit_finish_line_gas(irn);
548 be_emit_cstring("\tldmia ");
550 be_emit_cstring("!, {");
552 be_emit_cstring(", ");
554 be_emit_cstring(", ");
556 be_emit_cstring(", ");
559 be_emit_finish_line_gas(NULL);
561 be_emit_cstring("\tstmia ");
563 be_emit_cstring("!, {");
565 be_emit_cstring(", ");
567 be_emit_cstring(", ");
569 be_emit_cstring(", ");
572 be_emit_finish_line_gas(irn);
577 static void emit_arm_SwitchJmp(const ir_node *irn)
579 const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(irn);
580 be_emit_cstring("\tldrls pc, [pc, ");
581 arm_emit_source_register(irn, 0);
582 be_emit_cstring(", asl #2]");
583 be_emit_finish_line_gas(irn);
585 be_emit_jump_table(irn, attr->table, NULL, get_cfop_target_block);
588 /** Emit an IncSP node */
589 static void emit_be_IncSP(const ir_node *irn)
591 int offs = -be_get_IncSP_offset(irn);
595 be_emit_cstring("\tsub ");
598 be_emit_cstring("\tadd ");
600 arm_emit_dest_register(irn, 0);
601 be_emit_cstring(", ");
602 arm_emit_source_register(irn, 0);
603 be_emit_irprintf(", #0x%X", offs);
604 be_emit_finish_line_gas(irn);
606 /* omitted IncSP(0) */
611 static void emit_be_Copy(const ir_node *irn)
613 ir_mode *mode = get_irn_mode(irn);
615 if (arch_get_irn_register_in(irn, 0) == arch_get_irn_register_out(irn, 0)) {
620 if (mode_is_float(mode)) {
622 be_emit_cstring("\tmvf");
624 arm_emit_dest_register(irn, 0);
625 be_emit_cstring(", ");
626 arm_emit_source_register(irn, 0);
627 be_emit_finish_line_gas(irn);
629 panic("emit_be_Copy: move not supported for this mode");
631 } else if (mode_is_data(mode)) {
632 be_emit_cstring("\tmov ");
633 arm_emit_dest_register(irn, 0);
634 be_emit_cstring(", ");
635 arm_emit_source_register(irn, 0);
636 be_emit_finish_line_gas(irn);
638 panic("emit_be_Copy: move not supported for this mode");
642 static void emit_be_Perm(const ir_node *irn)
644 be_emit_cstring("\teor ");
645 arm_emit_source_register(irn, 0);
646 be_emit_cstring(", ");
647 arm_emit_source_register(irn, 0);
648 be_emit_cstring(", ");
649 arm_emit_source_register(irn, 1);
650 be_emit_finish_line_gas(NULL);
652 be_emit_cstring("\teor ");
653 arm_emit_source_register(irn, 1);
654 be_emit_cstring(", ");
655 arm_emit_source_register(irn, 0);
656 be_emit_cstring(", ");
657 arm_emit_source_register(irn, 1);
658 be_emit_finish_line_gas(NULL);
660 be_emit_cstring("\teor ");
661 arm_emit_source_register(irn, 0);
662 be_emit_cstring(", ");
663 arm_emit_source_register(irn, 0);
664 be_emit_cstring(", ");
665 arm_emit_source_register(irn, 1);
666 be_emit_finish_line_gas(irn);
669 static void emit_be_MemPerm(const ir_node *node)
675 /* TODO: this implementation is slower than necessary.
676 The longterm goal is however to avoid the memperm node completely */
678 memperm_arity = be_get_MemPerm_entity_arity(node);
679 if (memperm_arity > 12)
680 panic("memperm with more than 12 inputs not supported yet");
682 for (i = 0; i < memperm_arity; ++i) {
684 ir_entity *entity = be_get_MemPerm_in_entity(node, i);
687 be_emit_irprintf("\tstr r%d, [sp, #-4]!", i);
688 be_emit_finish_line_gas(node);
690 /* load from entity */
691 offset = get_entity_offset(entity) + sp_change;
692 be_emit_irprintf("\tldr r%d, [sp, #%d]", i, offset);
693 be_emit_finish_line_gas(node);
696 for (i = memperm_arity-1; i >= 0; --i) {
698 ir_entity *entity = be_get_MemPerm_out_entity(node, i);
700 /* store to new entity */
701 offset = get_entity_offset(entity) + sp_change;
702 be_emit_irprintf("\tstr r%d, [sp, #%d]", i, offset);
703 be_emit_finish_line_gas(node);
704 /* restore register */
705 be_emit_irprintf("\tldr r%d, [sp], #4", i);
707 be_emit_finish_line_gas(node);
709 assert(sp_change == 0);
712 static void emit_be_Start(const ir_node *node)
714 ir_graph *irg = get_irn_irg(node);
715 ir_type *frame_type = get_irg_frame_type(irg);
716 unsigned size = get_type_size_bytes(frame_type);
718 /* allocate stackframe */
720 be_emit_cstring("\tsub ");
721 arm_emit_register(&arm_registers[REG_SP]);
722 be_emit_cstring(", ");
723 arm_emit_register(&arm_registers[REG_SP]);
724 be_emit_irprintf(", #0x%X", size);
725 be_emit_finish_line_gas(node);
729 static void emit_be_Return(const ir_node *node)
731 ir_graph *irg = get_irn_irg(node);
732 ir_type *frame_type = get_irg_frame_type(irg);
733 unsigned size = get_type_size_bytes(frame_type);
735 /* deallocate stackframe */
737 be_emit_cstring("\tadd ");
738 arm_emit_register(&arm_registers[REG_SP]);
739 be_emit_cstring(", ");
740 arm_emit_register(&arm_registers[REG_SP]);
741 be_emit_irprintf(", #0x%X", size);
742 be_emit_finish_line_gas(node);
745 be_emit_cstring("\tmov pc, lr");
746 be_emit_finish_line_gas(node);
750 static void emit_arm_Jmp(const ir_node *node)
752 ir_node *block, *next_block;
754 /* for now, the code works for scheduled and non-schedules blocks */
755 block = get_nodes_block(node);
757 /* we have a block schedule */
758 next_block = sched_next_block(block);
759 if (get_cfop_target_block(node) != next_block) {
760 be_emit_cstring("\tb ");
761 arm_emit_cfop_target(node);
763 be_emit_cstring("\t/* fallthrough to ");
764 arm_emit_cfop_target(node);
765 be_emit_cstring(" */");
767 be_emit_finish_line_gas(node);
770 static void emit_nothing(const ir_node *irn)
776 * The type of a emitter function.
778 typedef void (emit_func)(const ir_node *irn);
781 * Set a node emitter. Make it a bit more type safe.
783 static inline void set_emitter(ir_op *op, emit_func arm_emit_node)
785 op->ops.generic = (op_func)arm_emit_node;
789 * Enters the emitter functions for handled nodes into the generic
790 * pointer of an opcode.
792 static void arm_register_emitters(void)
794 /* first clear the generic function pointer for all ops */
795 ir_clear_opcodes_generic_func();
797 /* register all emitter functions defined in spec */
798 arm_register_spec_emitters();
801 set_emitter(op_arm_B, emit_arm_B);
802 set_emitter(op_arm_CopyB, emit_arm_CopyB);
803 set_emitter(op_arm_fConst, emit_arm_fConst);
804 set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
805 set_emitter(op_arm_Jmp, emit_arm_Jmp);
806 set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
807 set_emitter(op_arm_SymConst, emit_arm_SymConst);
808 set_emitter(op_be_Copy, emit_be_Copy);
809 set_emitter(op_be_CopyKeep, emit_be_Copy);
810 set_emitter(op_be_IncSP, emit_be_IncSP);
811 set_emitter(op_be_MemPerm, emit_be_MemPerm);
812 set_emitter(op_be_Perm, emit_be_Perm);
813 set_emitter(op_be_Return, emit_be_Return);
814 set_emitter(op_be_Start, emit_be_Start);
816 /* no need to emit anything for the following nodes */
817 set_emitter(op_Phi, emit_nothing);
818 set_emitter(op_be_Keep, emit_nothing);
822 * Emits code for a node.
824 static void arm_emit_node(const ir_node *irn)
826 ir_op *op = get_irn_op(irn);
828 if (op->ops.generic) {
829 emit_func *emit = (emit_func *)op->ops.generic;
830 be_dwarf_location(get_irn_dbg_info(irn));
833 panic("Error: No emit handler for node %+F (graph %+F)\n",
834 irn, get_irn_irg(irn));
839 * emit the block label if needed.
841 static void arm_emit_block_header(ir_node *block, ir_node *prev)
846 ir_graph *irg = get_irn_irg(block);
847 ir_exec_freq *exec_freq = be_get_irg_exec_freq(irg);
850 n_cfgpreds = get_Block_n_cfgpreds(block);
851 if (n_cfgpreds == 1) {
852 ir_node *pred = get_Block_cfgpred(block, 0);
853 ir_node *pred_block = get_nodes_block(pred);
855 /* we don't need labels for fallthrough blocks, however switch-jmps
856 * are no fallthroughs */
857 if (pred_block == prev &&
858 !(is_Proj(pred) && is_arm_SwitchJmp(get_Proj_pred(pred)))) {
868 be_gas_emit_block_name(block);
871 be_emit_pad_comment();
872 be_emit_cstring(" /* preds:");
874 /* emit list of pred blocks in comment */
875 arity = get_irn_arity(block);
876 for (i = 0; i < arity; ++i) {
877 ir_node *predblock = get_Block_cfgpred_block(block, i);
878 be_emit_irprintf(" %d", get_irn_node_nr(predblock));
881 be_emit_cstring("\t/* ");
882 be_gas_emit_block_name(block);
883 be_emit_cstring(": ");
885 if (exec_freq != NULL) {
886 be_emit_irprintf(" freq: %f",
887 get_block_execfreq(exec_freq, block));
889 be_emit_cstring(" */\n");
890 be_emit_write_line();
894 * Walks over the nodes in a block connected by scheduling edges
895 * and emits code for each node.
897 static void arm_gen_block(ir_node *block, ir_node *prev_block)
901 arm_emit_block_header(block, prev_block);
902 be_dwarf_location(get_irn_dbg_info(block));
903 sched_foreach(block, irn) {
910 * Sets labels for control flow nodes (jump target)
912 static void arm_gen_labels(ir_node *block, void *env)
915 int n = get_Block_n_cfgpreds(block);
918 for (n--; n >= 0; n--) {
919 pred = get_Block_cfgpred(block, n);
920 set_irn_link(pred, block);
925 * Compare two entries of the symbol or tarval set.
927 static int cmp_sym_or_tv(const void *elt, const void *key, size_t size)
929 const sym_or_tv_t *p1 = (const sym_or_tv_t*)elt;
930 const sym_or_tv_t *p2 = (const sym_or_tv_t*)key;
933 /* as an identifier NEVER can point to a tarval, it's enough
934 to compare it this way */
935 return p1->u.generic != p2->u.generic;
938 void arm_gen_routine(ir_graph *irg)
940 ir_node *last_block = NULL;
941 ir_entity *entity = get_irg_entity(irg);
942 const arch_env_t *arch_env = be_get_irg_arch_env(irg);
946 isa = (arm_isa_t*) arch_env;
947 sym_or_tv = new_set(cmp_sym_or_tv, 8);
949 be_gas_elf_type_char = '%';
951 arm_register_emitters();
953 /* create the block schedule */
954 blk_sched = be_create_block_schedule(irg);
956 be_gas_emit_function_prolog(entity, 4, NULL);
958 irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
960 n = ARR_LEN(blk_sched);
961 for (i = 0; i < n;) {
962 ir_node *block, *next_bl;
964 block = blk_sched[i];
966 next_bl = i < n ? blk_sched[i] : NULL;
968 /* set here the link. the emitter expects to find the next block here */
969 set_irn_link(block, next_bl);
970 arm_gen_block(block, last_block);
974 /* emit SymConst values */
975 if (set_count(sym_or_tv) > 0) {
978 be_emit_cstring("\t.align 2\n");
980 foreach_set(sym_or_tv, sym_or_tv_t*, entry) {
981 emit_constant_name(entry);
982 be_emit_cstring(":\n");
983 be_emit_write_line();
985 if (entry->is_entity) {
986 be_emit_cstring("\t.word\t");
987 be_gas_emit_entity(entry->u.entity);
989 be_emit_write_line();
991 ir_tarval *tv = entry->u.tv;
993 int size = get_mode_size_bytes(get_tarval_mode(tv));
995 /* beware: ARM fpa uses big endian format */
996 for (vi = ((size + 3) & ~3) - 4; vi >= 0; vi -= 4) {
999 v = get_tarval_sub_bits(tv, vi+3);
1000 v = (v << 8) | get_tarval_sub_bits(tv, vi+2);
1001 v = (v << 8) | get_tarval_sub_bits(tv, vi+1);
1002 v = (v << 8) | get_tarval_sub_bits(tv, vi+0);
1003 be_emit_irprintf("\t.word\t%u\n", v);
1004 be_emit_write_line();
1009 be_emit_write_line();
1013 be_gas_emit_function_epilog(entity);
1016 void arm_init_emitter(void)
1018 FIRM_DBG_REGISTER(dbg, "firm.be.arm.emit");