2 * Copyright (C) 1995-2007 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
46 #include "../besched.h"
47 #include "../beblocksched.h"
48 #include "../beirg_t.h"
49 #include "../begnuas.h"
51 #include "arm_emitter.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"
58 #include "../benode_t.h"
60 #define SNPRINTF_BUF_LEN 128
62 static const arch_env_t *arch_env = NULL;
65 * Returns the register at in position pos.
67 static const arch_register_t *get_in_reg(const arch_env_t *arch_env, const ir_node *irn, int pos) {
69 const arch_register_t *reg = NULL;
71 assert(get_irn_arity(irn) > pos && "Invalid IN position");
73 /* The out register of the operator at position pos is the
74 in register we need. */
75 op = get_irn_n(irn, pos);
77 reg = arch_get_irn_register(arch_env, op);
79 assert(reg && "no in register found");
85 * Returns the register at out position pos.
87 static const arch_register_t *get_out_reg(const arch_env_t *arch_env,
88 const ir_node *node, int pos)
91 const arch_register_t *reg = NULL;
93 /* 1st case: irn is not of mode_T, so it has only */
94 /* one OUT register -> good */
95 /* 2nd case: irn is of mode_T -> collect all Projs and ask the */
96 /* Proj with the corresponding projnum for the register */
98 if (get_irn_mode(node) != mode_T) {
99 reg = arch_get_irn_register(arch_env, node);
100 } else if (is_arm_irn(node)) {
101 reg = get_arm_out_reg(node, pos);
103 const ir_edge_t *edge;
105 foreach_out_edge(node, edge) {
106 proj = get_edge_src_irn(edge);
107 assert(is_Proj(proj) && "non-Proj from mode_T node");
108 if (get_Proj_proj(proj) == pos) {
109 reg = arch_get_irn_register(arch_env, proj);
115 assert(reg && "no out register found");
119 /*************************************************************
121 * (_) | | / _| | | | |
122 * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __
123 * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__|
124 * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ |
125 * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_|
128 *************************************************************/
131 * Emits a block label from the given block.
133 static void arm_emit_block_label(arm_emit_env_t *env, const ir_node *block) {
134 be_emit_irprintf(env->emit, "BLOCK_%u", get_irn_node_nr(block));
138 * Emit the name of the source register at given input position.
140 void arm_emit_source_register(arm_emit_env_t *env, const ir_node *node, int pos) {
141 const arch_register_t *reg = get_in_reg(env->arch_env, node, pos);
142 be_emit_string(env->emit, arch_register_get_name(reg));
146 * Emit the name of the destination register at given output position.
148 void arm_emit_dest_register(arm_emit_env_t *env, const ir_node *node, int pos) {
149 const arch_register_t *reg = get_out_reg(env->arch_env, node, pos);
150 be_emit_string(env->emit, arch_register_get_name(reg));
154 * Emit a node's offset.
156 void arm_emit_offset(arm_emit_env_t *env, const ir_node *node) {
158 ir_op *irn_op = get_irn_op(node);
160 if (irn_op == op_be_StackParam) {
161 ir_entity *ent = be_get_frame_entity(node);
162 offset = get_entity_offset(ent);
163 } else if (irn_op == op_be_Reload || irn_op == op_be_Spill) {
164 ir_entity *ent = be_get_frame_entity(node);
165 offset = get_entity_offset(ent);
166 } else if (irn_op == op_be_IncSP) {
167 offset = - be_get_IncSP_offset(node);
169 assert(!"unimplemented arm_emit_offset for this node type");
170 panic("unimplemented arm_emit_offset for this node type");
172 be_emit_irprintf(env->emit, "%d", offset);
176 * Emit the instruction suffix depending on the mode.
178 void arm_emit_mode(arm_emit_env_t *env, const ir_node *node) {
179 const arm_attr_t *attr = get_arm_attr_const(node);
180 ir_mode *mode = attr->op_mode ? attr->op_mode : get_irn_mode(node);
181 int bits = get_mode_size_bits(mode);
184 be_emit_char(env->emit, 's');
186 be_emit_char(env->emit, 'd');
188 be_emit_char(env->emit, 'e');
193 * Returns non-zero if a mode has a Immediate attribute.
195 int is_immediate_node(const ir_node *irn) {
196 const arm_attr_t *attr = get_arm_attr_const(irn);
197 return ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM;
201 * Emit a const or SymConst value.
203 void arm_emit_immediate(arm_emit_env_t *env, const ir_node *node) {
204 if (is_immediate_node(node)) {
205 be_emit_irprintf(env->emit, "#0x%X", arm_decode_imm_w_shift(get_arm_value(node)));
206 } else if (is_arm_SymConst(node))
207 be_emit_ident(env->emit, get_arm_symconst_id(node));
209 assert(!"not a Constant");
214 * Returns the tarval or offset of an arm node as a string.
216 void arm_emit_shift(arm_emit_env_t *env, const ir_node *node) {
217 arm_shift_modifier mod;
219 mod = get_arm_shift_modifier(node);
220 if (ARM_HAS_SHIFT(mod)) {
221 long v = get_tarval_long(get_arm_value(node));
223 be_emit_irprintf(env->emit, ", %s #%ld", arm_shf_mod_name(mod), v);
228 * Returns a unique label. This number will not be used a second time.
230 static unsigned get_unique_label(void) {
231 static unsigned id = 0;
238 static void emit_arm_SymConst(arm_emit_env_t *env, const ir_node *irn) {
239 ident *id = get_arm_symconst_id(irn);
240 pmap_entry *entry = pmap_find(env->symbols, id);
244 /* allocate a label */
245 label = get_unique_label();
246 pmap_insert(env->symbols, id, INT_TO_PTR(label));
248 label = PTR_TO_INT(entry->value);
251 /* load the symbol indirect */
252 be_emit_cstring(env->emit, "\tldr ");
253 arm_emit_dest_register(env, irn, 0);
254 be_emit_irprintf(env->emit, ", .L%u", label);
255 be_emit_finish_line_gas(env->emit, irn);
259 * Returns the next block in a block schedule.
261 static ir_node *sched_next_block(ir_node *block) {
262 return get_irn_link(block);
266 * Emit a conditional jump.
268 static void emit_arm_CondJmp(arm_emit_env_t *env, const ir_node *irn) {
269 const ir_edge_t *edge;
270 ir_node *true_block = NULL;
271 ir_node *false_block = NULL;
272 ir_node *op1 = get_irn_n(irn, 0);
273 ir_mode *opmode = get_irn_mode(op1);
275 int proj_num = get_arm_CondJmp_proj_num(irn);
277 foreach_out_edge(irn, edge) {
278 ir_node *proj = get_edge_src_irn(edge);
279 long nr = get_Proj_proj(proj);
280 ir_node *block = get_irn_link(proj);
281 if (nr == pn_Cond_true) {
288 if (proj_num == pn_Cmp_False) {
289 /* always false: should not happen */
290 be_emit_cstring(env->emit, "\tb ");
291 arm_emit_block_label(env, false_block);
292 be_emit_finish_line_gas(env->emit, irn);
293 } else if (proj_num == pn_Cmp_True) {
294 /* always true: should not happen */
295 be_emit_cstring(env->emit, "\tb ");
296 arm_emit_block_label(env, true_block);
297 be_emit_finish_line_gas(env->emit, irn);
299 ir_node *block = get_nodes_block(irn);
301 if (mode_is_float(opmode)) {
302 suffix = "ICHWILLIMPLEMENTIERTWERDEN";
304 be_emit_cstring(env->emit, "\tfcmp ");
305 arm_emit_source_register(env, irn, 0);
306 be_emit_cstring(env->emit, ", ");
307 arm_emit_source_register(env, irn, 1);
308 be_emit_finish_line_gas(env->emit, irn);
310 be_emit_cstring(env->emit, "\tfmstat");
311 be_emit_pad_comment(env->emit);
312 be_emit_cstring(env->emit, "/* FCSPR -> CPSR */");
313 be_emit_finish_line_gas(env->emit, NULL);
315 if (true_block == sched_next_block(block)) {
317 proj_num = get_negated_pnc(proj_num, opmode);
320 case pn_Cmp_Eq: suffix = "eq"; break;
321 case pn_Cmp_Lt: suffix = "lt"; break;
322 case pn_Cmp_Le: suffix = "le"; break;
323 case pn_Cmp_Gt: suffix = "gt"; break;
324 case pn_Cmp_Ge: suffix = "ge"; break;
325 case pn_Cmp_Lg: suffix = "ne"; break;
326 case pn_Cmp_Leg: suffix = "al"; break;
327 default: assert(!"Cmp unsupported"); suffix = "al";
329 be_emit_cstring(env->emit, "\tcmp ");
330 arm_emit_source_register(env, irn, 0);
331 be_emit_cstring(env->emit, ", ");
332 arm_emit_source_register(env, irn, 1);
333 be_emit_finish_line_gas(env->emit, irn);
336 if (true_block == sched_next_block(block)) {
337 be_emit_irprintf(env->emit, "\tb%s ", suffix);
338 arm_emit_block_label(env, true_block);
339 be_emit_pad_comment(env->emit);
340 be_emit_cstring(env->emit, "/* false case */");
341 be_emit_finish_line_gas(env->emit, NULL);
343 be_emit_pad_comment(env->emit);
344 be_emit_cstring(env->emit, "/* fallthrough ");
345 arm_emit_block_label(env, false_block);
346 be_emit_cstring(env->emit, " */");
347 be_emit_finish_line_gas(env->emit, NULL);
349 be_emit_irprintf(env->emit, "\tb%s ", suffix);
350 arm_emit_block_label(env, true_block);
351 be_emit_pad_comment(env->emit);
352 be_emit_cstring(env->emit, "/* true case */");
353 be_emit_finish_line_gas(env->emit, NULL);
355 if (false_block == sched_next_block(block)) {
356 be_emit_pad_comment(env->emit);
357 be_emit_cstring(env->emit, "/* fallthrough ");
358 arm_emit_block_label(env, false_block);
359 be_emit_cstring(env->emit, " */");
360 be_emit_finish_line_gas(env->emit, NULL);
362 be_emit_cstring(env->emit, "b ");
363 arm_emit_block_label(env, false_block);
364 be_emit_pad_comment(env->emit);
365 be_emit_cstring(env->emit, "/* false case */");
366 be_emit_finish_line_gas(env->emit, NULL);
373 * Create the CopyB instruction sequence.
375 static void emit_arm_CopyB(arm_emit_env_t *env, const ir_node *irn) {
376 unsigned int size = get_tarval_long(get_arm_value(irn));
378 be_emit_cstring(env->emit, "/* MemCopy (");
379 arm_emit_source_register(env, irn, 1);
380 be_emit_cstring(env->emit, ")->(");
381 arm_emit_source_register(env, irn, 0);
382 be_emit_irprintf(env->emit, " [%d bytes], Uses ", size);
383 arm_emit_source_register(env, irn, 2);
384 be_emit_cstring(env->emit, ", ");
385 arm_emit_source_register(env, irn, 3);
386 be_emit_cstring(env->emit, ", ");
387 arm_emit_source_register(env, irn, 4);
388 be_emit_cstring(env->emit, ", and %r12 */");
389 be_emit_finish_line_gas(env->emit, NULL);
391 assert ( size > 0 && "CopyB needs size > 0" );
399 be_emit_cstring(env->emit, "\tldr %%r12, [");
400 arm_emit_source_register(env, irn, 1);
401 be_emit_cstring(env->emit, ", #0]!");
402 be_emit_finish_line_gas(env->emit, NULL);
404 be_emit_cstring(env->emit, "\tstr %%r12, [");
405 arm_emit_source_register(env, irn, 0);
406 be_emit_cstring(env->emit, ", #0]!");
407 be_emit_finish_line_gas(env->emit, irn);
410 be_emit_cstring(env->emit, "\tldmia ");
411 arm_emit_source_register(env, irn, 1);
412 be_emit_cstring(env->emit, "!, {%r12, ");
413 arm_emit_source_register(env, irn, 2);
414 be_emit_char(env->emit, '}');
415 be_emit_finish_line_gas(env->emit, NULL);
417 be_emit_cstring(env->emit, "\tstmia ");
418 arm_emit_source_register(env, irn, 0);
419 be_emit_cstring(env->emit, "!, {%r12, ");
420 arm_emit_source_register(env, irn, 2);
421 be_emit_char(env->emit, '}');
422 be_emit_finish_line_gas(env->emit, irn);
425 be_emit_cstring(env->emit, "\tldmia ");
426 arm_emit_source_register(env, irn, 1);
427 be_emit_cstring(env->emit, "!, {%r12, ");
428 arm_emit_source_register(env, irn, 2);
429 be_emit_cstring(env->emit, ", ");
430 arm_emit_source_register(env, irn, 3);
431 be_emit_char(env->emit, '}');
432 be_emit_finish_line_gas(env->emit, NULL);
434 be_emit_cstring(env->emit, "\tstmia ");
435 arm_emit_source_register(env, irn, 0);
436 be_emit_cstring(env->emit, "!, {%r12, ");
437 arm_emit_source_register(env, irn, 2);
438 be_emit_cstring(env->emit, ", ");
439 arm_emit_source_register(env, irn, 3);
440 be_emit_char(env->emit, '}');
441 be_emit_finish_line_gas(env->emit, irn);
446 be_emit_cstring(env->emit, "\tldmia ");
447 arm_emit_source_register(env, irn, 1);
448 be_emit_cstring(env->emit, "!, {%r12, ");
449 arm_emit_source_register(env, irn, 2);
450 be_emit_cstring(env->emit, ", ");
451 arm_emit_source_register(env, irn, 3);
452 be_emit_cstring(env->emit, ", ");
453 arm_emit_source_register(env, irn, 4);
454 be_emit_char(env->emit, '}');
455 be_emit_finish_line_gas(env->emit, NULL);
457 be_emit_cstring(env->emit, "\tstmia ");
458 arm_emit_source_register(env, irn, 0);
459 be_emit_cstring(env->emit, "!, {%r12, ");
460 arm_emit_source_register(env, irn, 2);
461 be_emit_cstring(env->emit, ", ");
462 arm_emit_source_register(env, irn, 3);
463 be_emit_cstring(env->emit, ", ");
464 arm_emit_source_register(env, irn, 4);
465 be_emit_char(env->emit, '}');
466 be_emit_finish_line_gas(env->emit, irn);
471 static void emit_arm_SwitchJmp(arm_emit_env_t *env, const ir_node *irn) {
472 const ir_edge_t *edge;
478 ir_node *default_block = NULL;
480 block_nr = get_irn_node_nr(irn);
481 n_projs = get_arm_SwitchJmp_n_projs(irn);
483 projs = xcalloc(n_projs , sizeof(ir_node*));
485 foreach_out_edge(irn, edge) {
486 proj = get_edge_src_irn(edge);
487 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
489 if (get_Proj_proj(proj) == get_arm_SwitchJmp_default_proj_num(irn))
490 default_block = get_irn_link(proj);
492 projs[get_Proj_proj(proj)] = proj;
494 assert(default_block != NULL);
501 be_emit_cstring(env->emit, "\tcmp ");
502 arm_emit_source_register(env, irn, 0);
503 be_emit_irprintf(env->emit, ", #%u", n_projs - 1);
504 be_emit_finish_line_gas(env->emit, irn);
506 be_emit_cstring(env->emit, "\tbhi ");
507 arm_emit_block_label(env, default_block);
508 be_emit_finish_line_gas(env->emit, NULL);
511 LDR %r12, .TABLE_X_START
512 ADD %r12, %r12, [%1S, LSL #2]
516 be_emit_irprintf(env->emit, "\tldr %%r12, TABLE_%d_START", block_nr);
517 be_emit_finish_line_gas(env->emit, NULL);
519 be_emit_irprintf(env->emit, "\tadd %%r12, %%r12, ");
520 arm_emit_source_register(env, irn, 0);
521 be_emit_cstring(env->emit, ", LSL #2");
522 be_emit_finish_line_gas(env->emit, NULL);
524 be_emit_cstring(env->emit, "\tldr %r15, [%r12, #0]");
525 be_emit_finish_line_gas(env->emit, NULL);
527 be_emit_irprintf(env->emit, "TABLE_%d_START:\n\t.word\tTABLE_%d", block_nr, block_nr);
528 be_emit_finish_line_gas(env->emit, NULL);
529 be_emit_irprintf(env->emit, "\t.align 2");
530 be_emit_finish_line_gas(env->emit, NULL);
531 be_emit_irprintf(env->emit, "TABLE_%d:", block_nr);
532 be_emit_finish_line_gas(env->emit, NULL);
534 for (i = 0; i < n_projs; ++i) {
538 block = get_irn_link(proj);
540 block = get_irn_link(projs[get_arm_SwitchJmp_default_proj_num(irn)]);
542 be_emit_cstring(env->emit, "\t.word\t");
543 arm_emit_block_label(env, block);
544 be_emit_finish_line_gas(env->emit, NULL);
546 be_emit_irprintf(env->emit, "\t.align 2\n");
547 be_emit_finish_line_gas(env->emit, NULL);
551 /************************************************************************/
553 /************************************************************************/
555 static void emit_be_Call(arm_emit_env_t *env, const ir_node *irn) {
556 ir_entity *ent = be_Call_get_entity(irn);
558 be_emit_cstring(env->emit, "\tbl ");
560 mark_entity_visited(ent);
561 be_emit_ident(env->emit, get_entity_ld_ident(ent));
563 arm_emit_source_register(env, irn, be_pos_Call_ptr);
565 be_emit_finish_line_gas(env->emit, irn);
568 /** Emit an IncSP node */
569 static void emit_be_IncSP(arm_emit_env_t *env, const ir_node *irn) {
570 int offs = be_get_IncSP_offset(irn);
573 be_emit_cstring(env->emit, "\tadd ");
574 arm_emit_dest_register(env, irn, 0);
575 be_emit_cstring(env->emit, ", ");
576 arm_emit_source_register(env, irn, 0);
577 be_emit_cstring(env->emit, ", #");
578 arm_emit_offset(env, irn);
580 be_emit_cstring(env->emit, "\t/* omitted IncSP(");
581 arm_emit_offset(env, irn);
582 be_emit_cstring(env->emit,") */");
584 be_emit_finish_line_gas(env->emit, irn);
587 static void emit_be_Copy(arm_emit_env_t *env, const ir_node *irn) {
588 ir_mode *mode = get_irn_mode(irn);
590 if (get_in_reg(env->arch_env, irn, 0) == get_out_reg(env->arch_env, irn, 0)) {
591 be_emit_cstring(env->emit, "\t/* omitted Copy: ");
592 arm_emit_source_register(env, irn, 0);
593 be_emit_cstring(env->emit, " -> ");
594 arm_emit_dest_register(env, irn, 0);
595 be_emit_finish_line_gas(env->emit, irn);
599 if (mode_is_float(mode)) {
600 if (USE_FPA(env->cg->isa)) {
601 be_emit_cstring(env->emit, "\tmvf");
602 arm_emit_mode(env, irn);
603 be_emit_char(env->emit, ' ');
604 arm_emit_dest_register(env, irn, 0);
605 be_emit_cstring(env->emit, ", ");
606 arm_emit_source_register(env, irn, 0);
607 be_emit_finish_line_gas(env->emit, irn);
609 assert(0 && "move not supported for this mode");
610 panic("emit_be_Copy: move not supported for this mode");
612 } else if (mode_is_numP(mode)) {
613 be_emit_cstring(env->emit, "\tmov ");
614 arm_emit_dest_register(env, irn, 0);
615 be_emit_cstring(env->emit, ", ");
616 arm_emit_source_register(env, irn, 0);
617 be_emit_finish_line_gas(env->emit, irn);
619 assert(0 && "move not supported for this mode");
620 panic("emit_be_Copy: move not supported for this mode");
625 * Emit code for a Spill.
627 static void emit_be_Spill(arm_emit_env_t *env, const ir_node *irn) {
628 ir_mode *mode = get_irn_mode(irn);
630 if (mode_is_float(mode)) {
631 if (USE_FPA(env->cg->isa)) {
632 be_emit_cstring(env->emit, "\tstf ");
634 assert(0 && "spill not supported for this mode");
635 panic("emit_be_Spill: spill not supported for this mode");
637 } else if (mode_is_dataM(mode)) {
638 be_emit_cstring(env->emit, "\tstr ");
640 assert(0 && "spill not supported for this mode");
641 panic("emit_be_Spill: spill not supported for this mode");
643 arm_emit_source_register(env, irn, 1);
644 be_emit_cstring(env->emit, ", [");
645 arm_emit_source_register(env, irn, 0);
646 be_emit_cstring(env->emit, ", #");
647 arm_emit_offset(env, irn);
648 be_emit_char(env->emit, ']');
649 be_emit_finish_line_gas(env->emit, irn);
653 * Emit code for a Reload.
655 static void emit_be_Reload(arm_emit_env_t *env, const ir_node *irn) {
656 ir_mode *mode = get_irn_mode(irn);
658 if (mode_is_float(mode)) {
659 if (USE_FPA(env->cg->isa)) {
660 be_emit_cstring(env->emit, "\tldf ");
662 assert(0 && "reload not supported for this mode");
663 panic("emit_be_Reload: reload not supported for this mode");
665 } else if (mode_is_dataM(mode)) {
666 be_emit_cstring(env->emit, "\tldr ");
668 assert(0 && "reload not supported for this mode");
669 panic("emit_be_Reload: reload not supported for this mode");
671 arm_emit_dest_register(env, irn, 0);
672 be_emit_cstring(env->emit, ", [");
673 arm_emit_source_register(env, irn, 0);
674 be_emit_cstring(env->emit, ", #");
675 arm_emit_offset(env, irn);
676 be_emit_char(env->emit, ']');
677 be_emit_finish_line_gas(env->emit, irn);
680 static void emit_be_Perm(arm_emit_env_t *env, const ir_node *irn) {
681 be_emit_cstring(env->emit, "\teor ");
682 arm_emit_source_register(env, irn, 0);
683 be_emit_cstring(env->emit, ", ");
684 arm_emit_source_register(env, irn, 0);
685 be_emit_cstring(env->emit, ", ");
686 arm_emit_source_register(env, irn, 1);
687 be_emit_finish_line_gas(env->emit, NULL);
689 be_emit_cstring(env->emit, "\teor ");
690 arm_emit_source_register(env, irn, 1);
691 be_emit_cstring(env->emit, ", ");
692 arm_emit_source_register(env, irn, 0);
693 be_emit_cstring(env->emit, ", ");
694 arm_emit_source_register(env, irn, 1);
695 be_emit_finish_line_gas(env->emit, NULL);
697 be_emit_cstring(env->emit, "\teor ");
698 arm_emit_source_register(env, irn, 0);
699 be_emit_cstring(env->emit, ", ");
700 arm_emit_source_register(env, irn, 0);
701 be_emit_cstring(env->emit, ", ");
702 arm_emit_source_register(env, irn, 1);
703 be_emit_finish_line_gas(env->emit, irn);
706 static void emit_be_StackParam(arm_emit_env_t *env, const ir_node *irn) {
707 ir_mode *mode = get_irn_mode(irn);
709 if (mode_is_float(mode)) {
710 if (USE_FPA(env->cg->isa)) {
711 be_emit_cstring(env->emit,"\tldf ");
713 assert(0 && "stackparam not supported for this mode");
714 panic("emit_be_StackParam: stackparam not supported for this mode");
717 be_emit_cstring(env->emit,"\tldr ");
719 arm_emit_dest_register(env, irn, 0);
720 be_emit_cstring(env->emit, ", [");
721 arm_emit_source_register(env, irn, 0);
722 be_emit_cstring(env->emit,", #");
723 arm_emit_offset(env, irn);
724 be_emit_finish_line_gas(env->emit, irn);
727 /************************************************************************/
729 /************************************************************************/
731 static void emit_Jmp(arm_emit_env_t *env, const ir_node *irn) {
732 const ir_edge_t *edge = get_irn_out_edge_first(irn);
733 ir_node *target_block = get_edge_src_irn(edge);
734 ir_node *block = get_nodes_block(irn);
736 if (target_block == sched_next_block(block)) {
737 be_emit_pad_comment(env->emit);
738 be_emit_cstring(env->emit, "/* fallthrough ");
739 arm_emit_block_label(env, target_block);
740 be_emit_cstring(env->emit, " */");
741 be_emit_finish_line_gas(env->emit, NULL);
743 be_emit_cstring(env->emit, "\tb ");
744 arm_emit_block_label(env, target_block);
745 be_emit_finish_line_gas(env->emit, irn);
749 static void emit_arm_fpaDbl2GP(arm_emit_env_t *env, const ir_node *irn) {
750 be_emit_cstring(env->emit, "\tstfd ");
751 arm_emit_source_register(env, irn, 0);
752 be_emit_cstring(env->emit, ", [sp, #-8]!");
753 be_emit_pad_comment(env->emit);
754 be_emit_cstring(env->emit, "/* Push fp to stack */");
755 be_emit_finish_line_gas(env->emit, NULL);
757 be_emit_cstring(env->emit, "\tldmfd sp!, {");
758 arm_emit_dest_register(env, irn, 1);
759 be_emit_cstring(env->emit, ", ");
760 arm_emit_dest_register(env, irn, 0);
761 be_emit_char(env->emit, '}');
762 be_emit_pad_comment(env->emit);
763 be_emit_cstring(env->emit, "/* Pop destination */");
764 be_emit_finish_line_gas(env->emit, irn);
767 /***********************************************************************************
770 * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
771 * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
772 * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
773 * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
775 ***********************************************************************************/
777 static void emit_silence(arm_emit_env_t *env, const ir_node *irn) {
782 * The type of a emitter function.
784 typedef void (emit_func)(arm_emit_env_t *env, 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) {
790 op->ops.generic = (op_func)arm_emit_node;
794 * Enters the emitter functions for handled nodes into the generic
795 * pointer of an opcode.
797 static void arm_register_emitters(void) {
799 #define ARM_EMIT(a) set_emitter(op_arm_##a, emit_arm_##a)
800 #define EMIT(a) set_emitter(op_##a, emit_##a)
801 #define BE_EMIT(a) set_emitter(op_be_##a, emit_be_##a)
802 #define SILENCE(a) set_emitter(op_##a, emit_silence)
804 /* first clear the generic function pointer for all ops */
805 clear_irp_opcodes_generic_func();
807 /* register all emitter functions defined in spec */
808 arm_register_spec_emitters();
810 /* other emitter functions */
813 // ARM_EMIT(CopyB_i);
838 SILENCE(be_CopyKeep);
839 SILENCE(be_RegParams);
851 * Emits code for a node.
853 static void arm_emit_node(arm_emit_env_t *env, const ir_node *irn) {
854 ir_op *op = get_irn_op(irn);
856 if (op->ops.generic) {
857 emit_func *emit = (emit_func *)op->ops.generic;
860 be_emit_cstring(env->emit, "\t/* TODO */");
861 be_emit_finish_line_gas(env->emit, irn);
866 * Walks over the nodes in a block connected by scheduling edges
867 * and emits code for each node.
869 void arm_gen_block(ir_node *block, void *ctx) {
870 arm_emit_env_t *env = ctx;
873 arm_emit_block_label(env, block);
874 be_emit_cstring(env->emit, ":\n");
875 be_emit_write_line(env->emit);
877 sched_foreach(block, irn) {
878 arm_emit_node(env, irn);
884 * Emits code for function start.
886 void arm_func_prolog(arm_emit_env_t *env, ir_graph *irg) {
887 be_emit_env_t *eenv = env->emit;
888 ir_entity *ent = get_irg_entity(irg);
889 const char *irg_name = get_entity_ld_name(ent);
891 be_emit_write_line(eenv);
892 be_gas_emit_switch_section(eenv, GAS_SECTION_TEXT);
893 be_emit_cstring(eenv, "\t.align 2\n");
895 if (get_entity_visibility(ent) == visibility_external_visible)
896 be_emit_irprintf(eenv, "\t.global %s\n", irg_name);
897 be_emit_irprintf(eenv, "%s:\n", irg_name);
901 * Emits code for function end
903 void arm_emit_end(FILE *F, ir_graph *irg) {
904 fprintf(F, "\t.ident \"firmcc\"\n");
908 * Sets labels for control flow nodes (jump target)
909 * TODO: Jump optimization
911 void arm_gen_labels(ir_node *block, void *env) {
913 int n = get_Block_n_cfgpreds(block);
915 for (n--; n >= 0; n--) {
916 pred = get_Block_cfgpred(block, n);
917 set_irn_link(pred, block);
923 * Main driver. Emits the code for one routine.
925 void arm_gen_routine(const arm_code_gen_t *cg, ir_graph *irg)
927 arm_emit_env_t emit_env;
932 emit_env.emit = &cg->isa->emit;
933 emit_env.arch_env = cg->arch_env;
935 emit_env.symbols = pmap_create();
936 FIRM_DBG_REGISTER(emit_env.mod, "firm.be.arm.emit");
938 /* set the global arch_env (needed by print hooks) */
939 arch_env = cg->arch_env;
941 arm_register_emitters();
943 /* create the block schedule. For now, we don't need it earlier. */
944 blk_sched = be_create_block_schedule(cg->irg, cg->birg->exec_freq);
946 arm_func_prolog(&emit_env, irg);
947 irg_block_walk_graph(irg, arm_gen_labels, NULL, &emit_env);
949 n = ARR_LEN(blk_sched);
950 for (i = 0; i < n;) {
951 ir_node *block, *next_bl;
953 block = blk_sched[i];
955 next_bl = i < n ? blk_sched[i] : NULL;
957 /* set here the link. the emitter expects to find the next block here */
958 set_irn_link(block, next_bl);
959 arm_gen_block(block, &emit_env);
962 /* emit SymConst values */
963 if (pmap_count(emit_env.symbols) > 0) {
964 be_emit_cstring(emit_env.emit, "\t.align 2\n");
966 pmap_foreach(emit_env.symbols, entry) {
967 ident *id = entry->key;
969 be_emit_irprintf(emit_env.emit, ".L%u:\n", PTR_TO_INT(entry->value));
970 be_emit_cstring(emit_env.emit, "\t.word\t");
971 be_emit_ident(emit_env.emit, id);
972 be_emit_char(emit_env.emit, '\n');
973 be_emit_write_line(emit_env.emit);
975 be_emit_char(emit_env.emit, '\n');
976 be_emit_write_line(emit_env.emit);
978 pmap_destroy(emit_env.symbols);