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
45 #include "../besched.h"
46 #include "../beblocksched.h"
47 #include "../beirg_t.h"
48 #include "../begnuas.h"
50 #include "arm_emitter.h"
51 #include "gen_arm_emitter.h"
52 #include "arm_nodes_attr.h"
53 #include "arm_new_nodes.h"
54 #include "arm_map_regs.h"
55 #include "gen_arm_regalloc_if.h"
57 #include "../benode_t.h"
59 #define SNPRINTF_BUF_LEN 128
61 static const arch_env_t *arch_env = NULL;
64 * Returns the register at in position pos.
66 static const arch_register_t *get_in_reg(const arch_env_t *arch_env, const ir_node *irn, int pos) {
68 const arch_register_t *reg = NULL;
70 assert(get_irn_arity(irn) > pos && "Invalid IN position");
72 /* The out register of the operator at position pos is the
73 in register we need. */
74 op = get_irn_n(irn, pos);
76 reg = arch_get_irn_register(arch_env, op);
78 assert(reg && "no in register found");
84 * Returns the register at out position pos.
86 static const arch_register_t *get_out_reg(const arch_env_t *arch_env,
87 const ir_node *node, int pos)
90 const arch_register_t *reg = NULL;
92 /* 1st case: irn is not of mode_T, so it has only */
93 /* one OUT register -> good */
94 /* 2nd case: irn is of mode_T -> collect all Projs and ask the */
95 /* Proj with the corresponding projnum for the register */
97 if (get_irn_mode(node) != mode_T) {
98 reg = arch_get_irn_register(arch_env, node);
99 } else if (is_arm_irn(node)) {
100 reg = get_arm_out_reg(node, pos);
102 const ir_edge_t *edge;
104 foreach_out_edge(node, edge) {
105 proj = get_edge_src_irn(edge);
106 assert(is_Proj(proj) && "non-Proj from mode_T node");
107 if (get_Proj_proj(proj) == pos) {
108 reg = arch_get_irn_register(arch_env, proj);
114 assert(reg && "no out register found");
118 /*************************************************************
120 * (_) | | / _| | | | |
121 * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __
122 * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__|
123 * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ |
124 * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_|
127 *************************************************************/
130 * Emits a block label from the given block.
132 static void arm_emit_block_label(arm_emit_env_t *env, const ir_node *block) {
133 be_emit_irprintf(env->emit, "BLOCK_%ld", get_irn_node_nr(block));
137 * Emit the name of the source register at given input position.
139 void arm_emit_source_register(arm_emit_env_t *env, const ir_node *node, int pos) {
140 const arch_register_t *reg = get_in_reg(env->arch_env, node, pos);
141 be_emit_string(env->emit, arch_register_get_name(reg));
145 * Emit the name of the destination register at given output position.
147 void arm_emit_dest_register(arm_emit_env_t *env, const ir_node *node, int pos) {
148 const arch_register_t *reg = get_out_reg(env->arch_env, node, pos);
149 be_emit_string(env->emit, arch_register_get_name(reg));
153 * Emit a node's offset.
155 void arm_emit_offset(arm_emit_env_t *env, const ir_node *node) {
157 ir_op *irn_op = get_irn_op(node);
159 if (irn_op == op_be_StackParam) {
160 ir_entity *ent = be_get_frame_entity(node);
161 offset = get_entity_offset(ent);
162 } else if (irn_op == op_be_Reload || irn_op == op_be_Spill) {
163 ir_entity *ent = be_get_frame_entity(node);
164 offset = get_entity_offset(ent);
165 } else if (irn_op == op_be_IncSP) {
166 offset = - be_get_IncSP_offset(node);
168 assert(!"unimplemented arm_emit_offset for this node type");
169 panic("unimplemented arm_emit_offset for this node type");
171 be_emit_irprintf(env->emit, "%d", offset);
175 * Emit the instruction suffix depending on the mode.
177 void arm_emit_mode(arm_emit_env_t *env, const ir_node *node) {
182 attr = get_arm_attr(node);
183 mode = attr->op_mode ? attr->op_mode : get_irn_mode(node);
184 bits = get_mode_size_bits(mode);
187 be_emit_char(env->emit, 's');
189 be_emit_char(env->emit, 'd');
191 be_emit_char(env->emit, 'e');
196 * Returns non-zero if a mode has a Immediate attribute.
198 int is_immediate_node(const ir_node *irn) {
199 arm_attr_t *attr = get_arm_attr(irn);
200 return ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM;
204 * Emit a const or SymConst value.
206 void arm_emit_immediate(arm_emit_env_t *env, const ir_node *node) {
207 if (is_immediate_node(node)) {
208 be_emit_irprintf(env->emit, "#0x%X", arm_decode_imm_w_shift(get_arm_value(node)));
209 } else if (is_arm_SymConst(node))
210 be_emit_string(env->emit, get_arm_symconst_label(node));
212 assert(!"not a Constant");
217 * Returns the tarval or offset of an arm node as a string.
219 void arm_emit_shift(arm_emit_env_t *env, const ir_node *node) {
220 arm_shift_modifier mod;
222 mod = get_arm_shift_modifier(node);
223 if (ARM_HAS_SHIFT(mod)) {
224 long v = get_tarval_long(get_arm_value(node));
226 be_emit_irprintf(env->emit, ", %s #%ld", arm_shf_mod_name(mod), v);
231 * Returns a unique label. This number will not be used a second time.
233 static unsigned get_unique_label(void) {
234 static unsigned id = 0;
241 static void emit_arm_SymConst(arm_emit_env_t *env, const ir_node *irn) {
242 SymConstEntry *entry = obstack_alloc(&env->obst, sizeof(*entry));
244 /* allocate a new symbol entry */
245 entry->label = get_unique_label();
246 entry->symconst = irn;
247 entry->next = env->symbols;
248 env->symbols = entry;
250 /* load the symbol indirect */
251 be_emit_cstring(env->emit, "\tldr ");
252 arm_emit_dest_register(env, irn, 0);
253 be_emit_irprintf(env->emit, ", .L%u", entry->label);
254 be_emit_finish_line_gas(env->emit, irn);
258 * Returns the next block in a block schedule.
260 static ir_node *sched_next_block(ir_node *block) {
261 return get_irn_link(block);
265 * Emit a conditional jump.
267 static void emit_arm_CondJmp(arm_emit_env_t *env, const ir_node *irn) {
268 const ir_edge_t *edge;
269 ir_node *true_block = NULL;
270 ir_node *false_block = NULL;
271 ir_node *op1 = get_irn_n(irn, 0);
272 ir_mode *opmode = get_irn_mode(op1);
274 int proj_num = get_arm_proj_num(irn);
276 foreach_out_edge(irn, edge) {
277 ir_node *proj = get_edge_src_irn(edge);
278 long nr = get_Proj_proj(proj);
279 ir_node *block = get_irn_link(proj);
280 if (nr == pn_Cond_true) {
287 if (proj_num == pn_Cmp_False) {
288 /* always false: should not happen */
289 be_emit_cstring(env->emit, "\tb ");
290 arm_emit_block_label(env, false_block);
291 be_emit_finish_line_gas(env->emit, irn);
292 } else if (proj_num == pn_Cmp_True) {
293 /* always true: should not happen */
294 be_emit_cstring(env->emit, "\tb ");
295 arm_emit_block_label(env, true_block);
296 be_emit_finish_line_gas(env->emit, irn);
298 ir_node *block = get_nodes_block(irn);
300 if (mode_is_float(opmode)) {
301 suffix = "ICHWILLIMPLEMENTIERTWERDEN";
303 be_emit_cstring(env->emit, "\tfcmp ");
304 arm_emit_source_register(env, irn, 0);
305 be_emit_cstring(env->emit, ", ");
306 arm_emit_source_register(env, irn, 1);
307 be_emit_finish_line_gas(env->emit, irn);
309 be_emit_cstring(env->emit, "\tfmstat");
310 be_emit_pad_comment(env->emit);
311 be_emit_cstring(env->emit, "/* FCSPR -> CPSR */");
312 be_emit_finish_line_gas(env->emit, NULL);
314 if (true_block == sched_next_block(block)) {
316 proj_num = get_negated_pnc(proj_num, opmode);
319 case pn_Cmp_Eq: suffix = "eq"; break;
320 case pn_Cmp_Lt: suffix = "lt"; break;
321 case pn_Cmp_Le: suffix = "le"; break;
322 case pn_Cmp_Gt: suffix = "gt"; break;
323 case pn_Cmp_Ge: suffix = "ge"; break;
324 case pn_Cmp_Lg: suffix = "ne"; break;
325 case pn_Cmp_Leg: suffix = "al"; break;
326 default: assert(!"Cmp unsupported"); suffix = "al";
328 be_emit_cstring(env->emit, "\tcmp ");
329 arm_emit_source_register(env, irn, 0);
330 be_emit_cstring(env->emit, ", ");
331 arm_emit_source_register(env, irn, 1);
332 be_emit_finish_line_gas(env->emit, irn);
335 if (true_block == sched_next_block(block)) {
336 be_emit_irprintf(env->emit, "\tb%s", suffix);
337 arm_emit_block_label(env, true_block);
338 be_emit_pad_comment(env->emit);
339 be_emit_cstring(env->emit, "/* false case */");
340 be_emit_finish_line_gas(env->emit, NULL);
342 be_emit_pad_comment(env->emit);
343 be_emit_cstring(env->emit, "/* fallthrough ");
344 arm_emit_block_label(env, false_block);
345 be_emit_cstring(env->emit, " */");
346 be_emit_finish_line_gas(env->emit, NULL);
348 be_emit_irprintf(env->emit, "\tb%s", suffix);
349 arm_emit_block_label(env, true_block);
350 be_emit_pad_comment(env->emit);
351 be_emit_cstring(env->emit, "/* true case */");
352 be_emit_finish_line_gas(env->emit, NULL);
354 if (false_block == sched_next_block(block)) {
355 be_emit_pad_comment(env->emit);
356 be_emit_cstring(env->emit, "/* fallthrough ");
357 arm_emit_block_label(env, false_block);
358 be_emit_cstring(env->emit, " */");
359 be_emit_finish_line_gas(env->emit, NULL);
361 be_emit_cstring(env->emit, "b ");
362 arm_emit_block_label(env, false_block);
363 be_emit_pad_comment(env->emit);
364 be_emit_cstring(env->emit, "/* false case */");
365 be_emit_finish_line_gas(env->emit, NULL);
372 * Create the CopyB instruction sequence.
374 static void emit_arm_CopyB(arm_emit_env_t *env, const ir_node *irn) {
375 unsigned int size = get_tarval_long(get_arm_value(irn));
377 be_emit_cstring(env->emit, "/* MemCopy (");
378 arm_emit_source_register(env, irn, 1);
379 be_emit_cstring(env->emit, ")->(");
380 arm_emit_source_register(env, irn, 0);
381 be_emit_irprintf(env->emit, " [%d bytes], Uses ", size);
382 arm_emit_source_register(env, irn, 2);
383 be_emit_cstring(env->emit, ", ");
384 arm_emit_source_register(env, irn, 3);
385 be_emit_cstring(env->emit, ", ");
386 arm_emit_source_register(env, irn, 4);
387 be_emit_cstring(env->emit, ", and %r12 */");
388 be_emit_finish_line_gas(env->emit, NULL);
390 assert ( size > 0 && "CopyB needs size > 0" );
398 be_emit_cstring(env->emit, "\tldr %%r12, [");
399 arm_emit_source_register(env, irn, 1);
400 be_emit_cstring(env->emit, ", #0]!");
401 be_emit_finish_line_gas(env->emit, NULL);
403 be_emit_cstring(env->emit, "\tstr %%r12, [");
404 arm_emit_source_register(env, irn, 0);
405 be_emit_cstring(env->emit, ", #0]!");
406 be_emit_finish_line_gas(env->emit, irn);
409 be_emit_cstring(env->emit, "\tldmia ");
410 arm_emit_source_register(env, irn, 1);
411 be_emit_cstring(env->emit, "!, {%r12, ");
412 arm_emit_source_register(env, irn, 2);
413 be_emit_char(env->emit, '}');
414 be_emit_finish_line_gas(env->emit, NULL);
416 be_emit_cstring(env->emit, "\tstmia ");
417 arm_emit_source_register(env, irn, 0);
418 be_emit_cstring(env->emit, "!, {%r12, ");
419 arm_emit_source_register(env, irn, 2);
420 be_emit_char(env->emit, '}');
421 be_emit_finish_line_gas(env->emit, irn);
424 be_emit_cstring(env->emit, "\tldmia ");
425 arm_emit_source_register(env, irn, 1);
426 be_emit_cstring(env->emit, "!, {%r12, ");
427 arm_emit_source_register(env, irn, 2);
428 be_emit_cstring(env->emit, ", ");
429 arm_emit_source_register(env, irn, 3);
430 be_emit_char(env->emit, '}');
431 be_emit_finish_line_gas(env->emit, NULL);
433 be_emit_cstring(env->emit, "\tstmia ");
434 arm_emit_source_register(env, irn, 0);
435 be_emit_cstring(env->emit, "!, {%r12, ");
436 arm_emit_source_register(env, irn, 2);
437 be_emit_cstring(env->emit, ", ");
438 arm_emit_source_register(env, irn, 3);
439 be_emit_char(env->emit, '}');
440 be_emit_finish_line_gas(env->emit, irn);
445 be_emit_cstring(env->emit, "\tldmia ");
446 arm_emit_source_register(env, irn, 1);
447 be_emit_cstring(env->emit, "!, {%r12, ");
448 arm_emit_source_register(env, irn, 2);
449 be_emit_cstring(env->emit, ", ");
450 arm_emit_source_register(env, irn, 3);
451 be_emit_cstring(env->emit, ", ");
452 arm_emit_source_register(env, irn, 4);
453 be_emit_char(env->emit, '}');
454 be_emit_finish_line_gas(env->emit, NULL);
456 be_emit_cstring(env->emit, "\tstmia ");
457 arm_emit_source_register(env, irn, 0);
458 be_emit_cstring(env->emit, "!, {%r12, ");
459 arm_emit_source_register(env, irn, 2);
460 be_emit_cstring(env->emit, ", ");
461 arm_emit_source_register(env, irn, 3);
462 be_emit_cstring(env->emit, ", ");
463 arm_emit_source_register(env, irn, 4);
464 be_emit_char(env->emit, '}');
465 be_emit_finish_line_gas(env->emit, irn);
470 static void emit_arm_SwitchJmp(arm_emit_env_t *env, const ir_node *irn) {
471 const ir_edge_t *edge;
477 ir_node *default_block = NULL;
479 block_nr = get_irn_node_nr(irn);
480 n_projs = get_arm_n_projs(irn);
482 projs = xcalloc(n_projs , sizeof(ir_node*));
484 foreach_out_edge(irn, edge) {
485 proj = get_edge_src_irn(edge);
486 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
488 if (get_Proj_proj(proj) == get_arm_default_proj_num(irn))
489 default_block = get_irn_link(proj);
491 projs[get_Proj_proj(proj)] = proj;
493 assert(default_block != NULL);
500 be_emit_cstring(env->emit, "\tcmp ");
501 arm_emit_source_register(env, irn, 0);
502 be_emit_irprintf(env->emit, ", #%u", n_projs - 1);
503 be_emit_finish_line_gas(env->emit, irn);
505 be_emit_cstring(env->emit, "\tbhi ");
506 arm_emit_block_label(env, default_block);
507 be_emit_finish_line_gas(env->emit, NULL);
510 LDR %r12, .TABLE_X_START
511 ADD %r12, %r12, [%1S, LSL #2]
515 be_emit_irprintf(env->emit, "\tldr %%r12, TABLE_%d_START", block_nr);
516 be_emit_finish_line_gas(env->emit, NULL);
518 be_emit_irprintf(env->emit, "\tadd %%r12, %%r12, ");
519 arm_emit_source_register(env, irn, 0);
520 be_emit_cstring(env->emit, ", LSL #2");
521 be_emit_finish_line_gas(env->emit, NULL);
523 be_emit_cstring(env->emit, "\tldr %r15, [%r12, #0]");
524 be_emit_finish_line_gas(env->emit, NULL);
526 be_emit_irprintf(env->emit, "TABLE_%d_START:\n\t.word\tTABLE_%d", block_nr, block_nr);
527 be_emit_finish_line_gas(env->emit, NULL);
528 be_emit_irprintf(env->emit, "\t.align 2");
529 be_emit_finish_line_gas(env->emit, NULL);
530 be_emit_irprintf(env->emit, "TABLE_%d:", block_nr);
531 be_emit_finish_line_gas(env->emit, NULL);
533 for (i = 0; i < n_projs; ++i) {
537 block = get_irn_link(proj);
539 block = get_irn_link(projs[get_arm_default_proj_num(irn)]);
541 be_emit_cstring(env->emit, "\t.word\t");
542 arm_emit_block_label(env, block);
543 be_emit_finish_line_gas(env->emit, NULL);
545 be_emit_irprintf(env->emit, "\t.align 2\n");
546 be_emit_finish_line_gas(env->emit, NULL);
550 /************************************************************************/
552 /************************************************************************/
554 static void emit_be_Call(arm_emit_env_t *env, const ir_node *irn) {
555 ir_entity *ent = be_Call_get_entity(irn);
557 be_emit_cstring(env->emit, "\tbl ");
559 mark_entity_visited(ent);
560 be_emit_ident(env->emit, get_entity_ld_ident(ent));
562 arm_emit_source_register(env, irn, be_pos_Call_ptr);
564 be_emit_finish_line_gas(env->emit, irn);
567 /** Emit an IncSP node */
568 static void emit_be_IncSP(arm_emit_env_t *env, const ir_node *irn) {
569 int offs = be_get_IncSP_offset(irn);
572 be_emit_cstring(env->emit, "\tadd ");
573 arm_emit_dest_register(env, irn, 0);
574 be_emit_cstring(env->emit, ", ");
575 arm_emit_source_register(env, irn, 0);
576 be_emit_cstring(env->emit, ", #");
577 arm_emit_offset(env, irn);
579 be_emit_cstring(env->emit, "\t/* omitted IncSP(");
580 arm_emit_offset(env, irn);
581 be_emit_cstring(env->emit,") */");
583 be_emit_finish_line_gas(env->emit, irn);
586 static void emit_be_Copy(arm_emit_env_t *env, const ir_node *irn) {
587 ir_mode *mode = get_irn_mode(irn);
589 if (get_in_reg(env->arch_env, irn, 0) == get_out_reg(env->arch_env, irn, 0)) {
590 be_emit_cstring(env->emit, "\t/* omitted Copy: ");
591 arm_emit_source_register(env, irn, 0);
592 be_emit_cstring(env->emit, " -> ");
593 arm_emit_dest_register(env, irn, 0);
594 be_emit_finish_line_gas(env->emit, irn);
598 if (mode_is_float(mode)) {
599 if (USE_FPA(env->cg->isa)) {
600 be_emit_cstring(env->emit, "\tmvf");
601 arm_emit_mode(env, irn);
602 be_emit_char(env->emit, ' ');
603 arm_emit_dest_register(env, irn, 0);
604 be_emit_cstring(env->emit, ", ");
605 arm_emit_source_register(env, irn, 0);
606 be_emit_finish_line_gas(env->emit, irn);
608 assert(0 && "move not supported for this mode");
609 panic("emit_be_Copy: move not supported for this mode");
611 } else if (mode_is_numP(mode)) {
612 be_emit_cstring(env->emit, "\tmov ");
613 arm_emit_dest_register(env, irn, 0);
614 be_emit_cstring(env->emit, ", ");
615 arm_emit_source_register(env, irn, 0);
616 be_emit_finish_line_gas(env->emit, irn);
618 assert(0 && "move not supported for this mode");
619 panic("emit_be_Copy: move not supported for this mode");
624 * Emit code for a Spill.
626 static void emit_be_Spill(arm_emit_env_t *env, const ir_node *irn) {
627 ir_mode *mode = get_irn_mode(irn);
629 if (mode_is_float(mode)) {
630 if (USE_FPA(env->cg->isa)) {
631 be_emit_cstring(env->emit, "\tstf ");
633 assert(0 && "spill not supported for this mode");
634 panic("emit_be_Spill: spill not supported for this mode");
636 } else if (mode_is_dataM(mode)) {
637 be_emit_cstring(env->emit, "\tstr ");
639 assert(0 && "spill not supported for this mode");
640 panic("emit_be_Spill: spill not supported for this mode");
642 arm_emit_source_register(env, irn, 1);
643 be_emit_cstring(env->emit, ", [");
644 arm_emit_source_register(env, irn, 0);
645 be_emit_cstring(env->emit, ", #");
646 arm_emit_offset(env, irn);
647 be_emit_char(env->emit, ']');
648 be_emit_finish_line_gas(env->emit, irn);
652 * Emit code for a Reload.
654 static void emit_be_Reload(arm_emit_env_t *env, const ir_node *irn) {
655 ir_mode *mode = get_irn_mode(irn);
657 if (mode_is_float(mode)) {
658 if (USE_FPA(env->cg->isa)) {
659 be_emit_cstring(env->emit, "\tldf ");
661 assert(0 && "reload not supported for this mode");
662 panic("emit_be_Reload: reload not supported for this mode");
664 } else if (mode_is_dataM(mode)) {
665 be_emit_cstring(env->emit, "\tldr ");
667 assert(0 && "reload not supported for this mode");
668 panic("emit_be_Reload: reload not supported for this mode");
670 arm_emit_dest_register(env, irn, 0);
671 be_emit_cstring(env->emit, ", [");
672 arm_emit_source_register(env, irn, 0);
673 be_emit_cstring(env->emit, ", #");
674 arm_emit_offset(env, irn);
675 be_emit_char(env->emit, ']');
676 be_emit_finish_line_gas(env->emit, irn);
679 static void emit_be_Perm(arm_emit_env_t *env, const ir_node *irn) {
680 be_emit_cstring(env->emit, "\teor ");
681 arm_emit_source_register(env, irn, 0);
682 be_emit_cstring(env->emit, ", ");
683 arm_emit_source_register(env, irn, 0);
684 be_emit_cstring(env->emit, ", ");
685 arm_emit_source_register(env, irn, 1);
686 be_emit_finish_line_gas(env->emit, NULL);
688 be_emit_cstring(env->emit, "\teor ");
689 arm_emit_source_register(env, irn, 1);
690 be_emit_cstring(env->emit, ", ");
691 arm_emit_source_register(env, irn, 0);
692 be_emit_cstring(env->emit, ", ");
693 arm_emit_source_register(env, irn, 1);
694 be_emit_finish_line_gas(env->emit, NULL);
696 arm_emit_source_register(env, irn, 0);
697 be_emit_cstring(env->emit, ", ");
698 arm_emit_source_register(env, irn, 0);
699 be_emit_cstring(env->emit, ", ");
700 arm_emit_source_register(env, irn, 1);
701 be_emit_finish_line_gas(env->emit, irn);
704 static void emit_be_StackParam(arm_emit_env_t *env, const ir_node *irn) {
705 ir_mode *mode = get_irn_mode(irn);
707 if (mode_is_float(mode)) {
708 if (USE_FPA(env->cg->isa)) {
709 be_emit_cstring(env->emit,"\tldf ");
711 assert(0 && "stackparam not supported for this mode");
712 panic("emit_be_StackParam: stackparam not supported for this mode");
715 be_emit_cstring(env->emit,"\tldr ");
717 arm_emit_dest_register(env, irn, 0);
718 be_emit_cstring(env->emit, ", [");
719 arm_emit_source_register(env, irn, 0);
720 be_emit_cstring(env->emit,", #");
721 arm_emit_offset(env, irn);
722 be_emit_finish_line_gas(env->emit, irn);
725 /************************************************************************/
727 /************************************************************************/
729 static void emit_Jmp(arm_emit_env_t *env, const ir_node *irn) {
730 const ir_edge_t *edge = get_irn_out_edge_first(irn);
731 ir_node *target_block = get_edge_src_irn(edge);
733 be_emit_cstring(env->emit, "\tb ");
734 arm_emit_block_label(env, target_block);
735 be_emit_finish_line_gas(env->emit, irn);
738 static void emit_arm_fpaDbl2GP(arm_emit_env_t *env, const ir_node *irn) {
739 be_emit_cstring(env->emit, "\tstfd ");
740 arm_emit_source_register(env, irn, 0);
741 be_emit_cstring(env->emit, ", [sp, #-8]!");
742 be_emit_pad_comment(env->emit);
743 be_emit_cstring(env->emit, "/* Push fp to stack */");
744 be_emit_finish_line_gas(env->emit, NULL);
746 be_emit_cstring(env->emit, "\tldmfd sp!, {");
747 arm_emit_dest_register(env, irn, 1);
748 be_emit_cstring(env->emit, ", ");
749 arm_emit_dest_register(env, irn, 0);
750 be_emit_char(env->emit, '}');
751 be_emit_pad_comment(env->emit);
752 be_emit_cstring(env->emit, "/* Pop destination */");
753 be_emit_finish_line_gas(env->emit, irn);
756 /***********************************************************************************
759 * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
760 * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
761 * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
762 * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
764 ***********************************************************************************/
766 static void emit_silence(arm_emit_env_t *env, const ir_node *irn) {
771 * The type of a emitter function.
773 typedef void (emit_func)(arm_emit_env_t *env, const ir_node *irn);
776 * Set a node emitter. Make it a bit more type safe.
778 static INLINE void set_emitter(ir_op *op, emit_func arm_emit_node) {
779 op->ops.generic = (op_func)arm_emit_node;
783 * Enters the emitter functions for handled nodes into the generic
784 * pointer of an opcode.
786 static void arm_register_emitters(void) {
788 #define ARM_EMIT(a) set_emitter(op_arm_##a, emit_arm_##a)
789 #define EMIT(a) set_emitter(op_##a, emit_##a)
790 #define BE_EMIT(a) set_emitter(op_be_##a, emit_be_##a)
791 #define SILENCE(a) set_emitter(op_##a, emit_silence)
793 /* first clear the generic function pointer for all ops */
794 clear_irp_opcodes_generic_func();
796 /* register all emitter functions defined in spec */
797 arm_register_spec_emitters();
799 /* other emitter functions */
802 // ARM_EMIT(CopyB_i);
826 SILENCE(be_CopyKeep);
836 * Emits code for a node.
838 static void arm_emit_node(arm_emit_env_t *env, const ir_node *irn) {
839 ir_op *op = get_irn_op(irn);
841 if (op->ops.generic) {
842 emit_func *emit = (emit_func *)op->ops.generic;
845 be_emit_cstring(env->emit, "\t/* TODO */");
846 be_emit_finish_line_gas(env->emit, irn);
851 * Walks over the nodes in a block connected by scheduling edges
852 * and emits code for each node.
854 void arm_gen_block(ir_node *block, void *ctx) {
855 arm_emit_env_t *env = ctx;
858 arm_emit_block_label(env, block);
859 be_emit_cstring(env->emit, ":\n");
860 be_emit_write_line(env->emit);
862 sched_foreach(block, irn) {
863 arm_emit_node(env, irn);
869 * Emits code for function start.
871 void arm_func_prolog(arm_emit_env_t *env, ir_graph *irg) {
872 be_emit_env_t *eenv = env->emit;
873 ir_entity *ent = get_irg_entity(irg);
874 const char *irg_name = get_entity_ld_name(ent);
876 be_emit_write_line(eenv);
877 be_gas_emit_switch_section(eenv, GAS_SECTION_TEXT);
878 be_emit_cstring(eenv, "\t.align 2\n");
880 if (get_entity_visibility(ent) == visibility_external_visible)
881 be_emit_irprintf(eenv, "\t.global %s\n", irg_name);
882 be_emit_irprintf(eenv, "%s:\n", irg_name);
886 * Emits code for function end
888 void arm_emit_end(FILE *F, ir_graph *irg) {
889 fprintf(F, "\t.ident \"firmcc\"\n");
893 * Sets labels for control flow nodes (jump target)
894 * TODO: Jump optimization
896 void arm_gen_labels(ir_node *block, void *env) {
898 int n = get_Block_n_cfgpreds(block);
900 for (n--; n >= 0; n--) {
901 pred = get_Block_cfgpred(block, n);
902 set_irn_link(pred, block);
908 * Main driver. Emits the code for one routine.
910 void arm_gen_routine(const arm_code_gen_t *cg, ir_graph *irg)
912 SymConstEntry *entry;
913 arm_emit_env_t emit_env;
917 emit_env.emit = &cg->isa->emit;
918 emit_env.arch_env = cg->arch_env;
920 emit_env.symbols = NULL;
921 obstack_init(&emit_env.obst);
922 FIRM_DBG_REGISTER(emit_env.mod, "firm.be.arm.emit");
924 /* set the global arch_env (needed by print hooks) */
925 arch_env = cg->arch_env;
927 arm_register_emitters();
929 /* create the block schedule. For now, we don't need it earlier. */
930 blk_sched = be_create_block_schedule(cg->irg, cg->birg->exec_freq);
932 arm_func_prolog(&emit_env, irg);
933 irg_block_walk_graph(irg, arm_gen_labels, NULL, &emit_env);
935 n = ARR_LEN(blk_sched);
936 for (i = 0; i < n;) {
937 ir_node *block, *next_bl;
939 block = blk_sched[i];
941 next_bl = i < n ? blk_sched[i] : NULL;
943 /* set here the link. the emitter expects to find the next block here */
944 set_irn_link(block, next_bl);
945 arm_gen_block(block, &emit_env);
948 /* emit SymConst values */
949 if (emit_env.symbols)
950 be_emit_cstring(emit_env.emit, "\t.align 2\n");
952 for (entry = emit_env.symbols; entry; entry = entry->next) {
953 be_emit_irprintf(emit_env.emit, ".L%u:\n", entry->label);
954 be_emit_cstring(emit_env.emit, "\t.word\t");
955 arm_emit_immediate(&emit_env, entry->symconst);
956 be_emit_char(emit_env.emit, '\n');
957 be_emit_write_line(emit_env.emit);
960 obstack_free(&emit_env.obst, NULL);