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, Michael Beck
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 arm fpa instruction suffix depending on the mode.
178 static void arm_emit_fpa_postfix(arm_emit_env_t *env, ir_mode *mode) {
179 int bits = get_mode_size_bits(mode);
181 be_emit_char(env->emit, 's');
183 be_emit_char(env->emit, 'd');
185 be_emit_char(env->emit, 'e');
189 * Emit the instruction suffix depending on the mode.
191 void arm_emit_mode(arm_emit_env_t *env, const ir_node *node) {
194 if (is_arm_irn(node)) {
195 const arm_attr_t *attr = get_arm_attr_const(node);
196 mode = attr->op_mode ? attr->op_mode : get_irn_mode(node);
198 mode = get_irn_mode(node);
200 arm_emit_fpa_postfix(env, mode);
205 * Returns non-zero if a mode has a Immediate attribute.
207 int is_immediate_node(const ir_node *irn) {
208 const arm_attr_t *attr = get_arm_attr_const(irn);
209 return ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM;
213 * Emit a const or SymConst value.
215 void arm_emit_immediate(arm_emit_env_t *env, const ir_node *node) {
216 if (is_immediate_node(node)) {
217 be_emit_irprintf(env->emit, "#0x%X", arm_decode_imm_w_shift(get_arm_value(node)));
218 } else if (is_arm_SymConst(node))
219 be_emit_ident(env->emit, get_arm_symconst_id(node));
221 assert(!"not a Constant");
226 * Returns the tarval or offset of an arm node as a string.
228 void arm_emit_shift(arm_emit_env_t *env, const ir_node *node) {
229 arm_shift_modifier mod;
231 mod = get_arm_shift_modifier(node);
232 if (ARM_HAS_SHIFT(mod)) {
233 long v = get_tarval_long(get_arm_value(node));
235 be_emit_irprintf(env->emit, ", %s #%l", arm_shf_mod_name(mod), v);
239 /** An entry in the sym_or_tv set. */
240 typedef struct sym_or_tv {
242 ident *id; /**< An ident. */
243 tarval *tv; /**< A tarval. */
244 const void *generic; /**< For generic compare. */
246 unsigned label; /**< the associated label. */
247 char is_ident; /**< Non-zero if an ident is stored. */
251 * Returns a unique label. This number will not be used a second time.
253 static unsigned get_unique_label(void) {
254 static unsigned id = 0;
261 static void emit_arm_SymConst(arm_emit_env_t *env, const ir_node *irn) {
262 sym_or_tv key, *entry;
265 key.u.id = get_arm_symconst_id(irn);
268 entry = (sym_or_tv *)set_insert(env->sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
269 if (entry->label == 0) {
270 /* allocate a label */
271 entry->label = get_unique_label();
273 label = entry->label;
275 /* load the symbol indirect */
276 be_emit_cstring(env->emit, "\tldr ");
277 arm_emit_dest_register(env, irn, 0);
278 be_emit_irprintf(env->emit, ", .L%u", label);
279 be_emit_finish_line_gas(env->emit, irn);
283 * Emit a floating point fpa constant.
285 static void emit_arm_fpaConst(arm_emit_env_t *env, const ir_node *irn) {
286 sym_or_tv key, *entry;
290 key.u.tv = get_arm_value(irn);
293 entry = (sym_or_tv *)set_insert(env->sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
294 if (entry->label == 0) {
295 /* allocate a label */
296 entry->label = get_unique_label();
298 label = entry->label;
300 /* load the tarval indirect */
301 mode = get_irn_mode(irn);
302 be_emit_cstring(env->emit, "\tldf");
303 arm_emit_fpa_postfix(env, mode);
304 be_emit_char(env->emit, ' ');
306 arm_emit_dest_register(env, irn, 0);
307 be_emit_irprintf(env->emit, ", .L%u", label);
308 be_emit_finish_line_gas(env->emit, irn);
312 * Returns the next block in a block schedule.
314 static ir_node *sched_next_block(ir_node *block) {
315 return get_irn_link(block);
319 * Emit a conditional jump.
321 static void emit_arm_CondJmp(arm_emit_env_t *env, const ir_node *irn) {
322 const ir_edge_t *edge;
323 ir_node *true_block = NULL;
324 ir_node *false_block = NULL;
325 ir_node *op1 = get_irn_n(irn, 0);
326 ir_mode *opmode = get_irn_mode(op1);
328 int proj_num = get_arm_CondJmp_proj_num(irn);
330 foreach_out_edge(irn, edge) {
331 ir_node *proj = get_edge_src_irn(edge);
332 long nr = get_Proj_proj(proj);
333 ir_node *block = get_irn_link(proj);
334 if (nr == pn_Cond_true) {
341 if (proj_num == pn_Cmp_False) {
342 /* always false: should not happen */
343 be_emit_cstring(env->emit, "\tb ");
344 arm_emit_block_label(env, false_block);
345 be_emit_finish_line_gas(env->emit, irn);
346 } else if (proj_num == pn_Cmp_True) {
347 /* always true: should not happen */
348 be_emit_cstring(env->emit, "\tb ");
349 arm_emit_block_label(env, true_block);
350 be_emit_finish_line_gas(env->emit, irn);
352 ir_node *block = get_nodes_block(irn);
354 if (mode_is_float(opmode)) {
355 suffix = "ICHWILLIMPLEMENTIERTWERDEN";
357 be_emit_cstring(env->emit, "\tfcmp ");
358 arm_emit_source_register(env, irn, 0);
359 be_emit_cstring(env->emit, ", ");
360 arm_emit_source_register(env, irn, 1);
361 be_emit_finish_line_gas(env->emit, irn);
363 be_emit_cstring(env->emit, "\tfmstat");
364 be_emit_pad_comment(env->emit);
365 be_emit_cstring(env->emit, "/* FCSPR -> CPSR */");
366 be_emit_finish_line_gas(env->emit, NULL);
368 if (true_block == sched_next_block(block)) {
370 proj_num = get_negated_pnc(proj_num, opmode);
373 case pn_Cmp_Eq: suffix = "eq"; break;
374 case pn_Cmp_Lt: suffix = "lt"; break;
375 case pn_Cmp_Le: suffix = "le"; break;
376 case pn_Cmp_Gt: suffix = "gt"; break;
377 case pn_Cmp_Ge: suffix = "ge"; break;
378 case pn_Cmp_Lg: suffix = "ne"; break;
379 case pn_Cmp_Leg: suffix = "al"; break;
380 default: assert(!"Cmp unsupported"); suffix = "al";
382 be_emit_cstring(env->emit, "\tcmp ");
383 arm_emit_source_register(env, irn, 0);
384 be_emit_cstring(env->emit, ", ");
385 arm_emit_source_register(env, irn, 1);
386 be_emit_finish_line_gas(env->emit, irn);
389 if (true_block == sched_next_block(block)) {
390 be_emit_irprintf(env->emit, "\tb%s ", suffix);
391 arm_emit_block_label(env, true_block);
392 be_emit_pad_comment(env->emit);
393 be_emit_cstring(env->emit, "/* false case */");
394 be_emit_finish_line_gas(env->emit, NULL);
396 be_emit_pad_comment(env->emit);
397 be_emit_cstring(env->emit, "/* fallthrough ");
398 arm_emit_block_label(env, false_block);
399 be_emit_cstring(env->emit, " */");
400 be_emit_finish_line_gas(env->emit, NULL);
402 be_emit_irprintf(env->emit, "\tb%s ", suffix);
403 arm_emit_block_label(env, true_block);
404 be_emit_pad_comment(env->emit);
405 be_emit_cstring(env->emit, "/* true case */");
406 be_emit_finish_line_gas(env->emit, NULL);
408 if (false_block == sched_next_block(block)) {
409 be_emit_pad_comment(env->emit);
410 be_emit_cstring(env->emit, "/* fallthrough ");
411 arm_emit_block_label(env, false_block);
412 be_emit_cstring(env->emit, " */");
413 be_emit_finish_line_gas(env->emit, NULL);
415 be_emit_cstring(env->emit, "b ");
416 arm_emit_block_label(env, false_block);
417 be_emit_pad_comment(env->emit);
418 be_emit_cstring(env->emit, "/* false case */");
419 be_emit_finish_line_gas(env->emit, NULL);
426 * Create the CopyB instruction sequence.
428 static void emit_arm_CopyB(arm_emit_env_t *env, const ir_node *irn) {
429 unsigned int size = get_tarval_long(get_arm_value(irn));
431 be_emit_cstring(env->emit, "/* MemCopy (");
432 arm_emit_source_register(env, irn, 1);
433 be_emit_cstring(env->emit, ")->(");
434 arm_emit_source_register(env, irn, 0);
435 be_emit_irprintf(env->emit, " [%d bytes], Uses ", size);
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_cstring(env->emit, ", ");
440 arm_emit_source_register(env, irn, 4);
441 be_emit_cstring(env->emit, ", and %r12 */");
442 be_emit_finish_line_gas(env->emit, NULL);
444 assert ( size > 0 && "CopyB needs size > 0" );
452 be_emit_cstring(env->emit, "\tldr %%r12, [");
453 arm_emit_source_register(env, irn, 1);
454 be_emit_cstring(env->emit, ", #0]!");
455 be_emit_finish_line_gas(env->emit, NULL);
457 be_emit_cstring(env->emit, "\tstr %%r12, [");
458 arm_emit_source_register(env, irn, 0);
459 be_emit_cstring(env->emit, ", #0]!");
460 be_emit_finish_line_gas(env->emit, irn);
463 be_emit_cstring(env->emit, "\tldmia ");
464 arm_emit_source_register(env, irn, 1);
465 be_emit_cstring(env->emit, "!, {%r12, ");
466 arm_emit_source_register(env, irn, 2);
467 be_emit_char(env->emit, '}');
468 be_emit_finish_line_gas(env->emit, NULL);
470 be_emit_cstring(env->emit, "\tstmia ");
471 arm_emit_source_register(env, irn, 0);
472 be_emit_cstring(env->emit, "!, {%r12, ");
473 arm_emit_source_register(env, irn, 2);
474 be_emit_char(env->emit, '}');
475 be_emit_finish_line_gas(env->emit, irn);
478 be_emit_cstring(env->emit, "\tldmia ");
479 arm_emit_source_register(env, irn, 1);
480 be_emit_cstring(env->emit, "!, {%r12, ");
481 arm_emit_source_register(env, irn, 2);
482 be_emit_cstring(env->emit, ", ");
483 arm_emit_source_register(env, irn, 3);
484 be_emit_char(env->emit, '}');
485 be_emit_finish_line_gas(env->emit, NULL);
487 be_emit_cstring(env->emit, "\tstmia ");
488 arm_emit_source_register(env, irn, 0);
489 be_emit_cstring(env->emit, "!, {%r12, ");
490 arm_emit_source_register(env, irn, 2);
491 be_emit_cstring(env->emit, ", ");
492 arm_emit_source_register(env, irn, 3);
493 be_emit_char(env->emit, '}');
494 be_emit_finish_line_gas(env->emit, irn);
499 be_emit_cstring(env->emit, "\tldmia ");
500 arm_emit_source_register(env, irn, 1);
501 be_emit_cstring(env->emit, "!, {%r12, ");
502 arm_emit_source_register(env, irn, 2);
503 be_emit_cstring(env->emit, ", ");
504 arm_emit_source_register(env, irn, 3);
505 be_emit_cstring(env->emit, ", ");
506 arm_emit_source_register(env, irn, 4);
507 be_emit_char(env->emit, '}');
508 be_emit_finish_line_gas(env->emit, NULL);
510 be_emit_cstring(env->emit, "\tstmia ");
511 arm_emit_source_register(env, irn, 0);
512 be_emit_cstring(env->emit, "!, {%r12, ");
513 arm_emit_source_register(env, irn, 2);
514 be_emit_cstring(env->emit, ", ");
515 arm_emit_source_register(env, irn, 3);
516 be_emit_cstring(env->emit, ", ");
517 arm_emit_source_register(env, irn, 4);
518 be_emit_char(env->emit, '}');
519 be_emit_finish_line_gas(env->emit, irn);
524 static void emit_arm_SwitchJmp(arm_emit_env_t *env, const ir_node *irn) {
525 const ir_edge_t *edge;
531 ir_node *default_block = NULL;
533 block_nr = get_irn_node_nr(irn);
534 n_projs = get_arm_SwitchJmp_n_projs(irn);
536 projs = xcalloc(n_projs , sizeof(ir_node*));
538 foreach_out_edge(irn, edge) {
539 proj = get_edge_src_irn(edge);
540 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
542 if (get_Proj_proj(proj) == get_arm_SwitchJmp_default_proj_num(irn))
543 default_block = get_irn_link(proj);
545 projs[get_Proj_proj(proj)] = proj;
547 assert(default_block != NULL);
554 be_emit_cstring(env->emit, "\tcmp ");
555 arm_emit_source_register(env, irn, 0);
556 be_emit_irprintf(env->emit, ", #%u", n_projs - 1);
557 be_emit_finish_line_gas(env->emit, irn);
559 be_emit_cstring(env->emit, "\tbhi ");
560 arm_emit_block_label(env, default_block);
561 be_emit_finish_line_gas(env->emit, NULL);
564 LDR %r12, .TABLE_X_START
565 ADD %r12, %r12, [%1S, LSL #2]
569 be_emit_irprintf(env->emit, "\tldr %%r12, TABLE_%d_START", block_nr);
570 be_emit_finish_line_gas(env->emit, NULL);
572 be_emit_irprintf(env->emit, "\tadd %%r12, %%r12, ");
573 arm_emit_source_register(env, irn, 0);
574 be_emit_cstring(env->emit, ", LSL #2");
575 be_emit_finish_line_gas(env->emit, NULL);
577 be_emit_cstring(env->emit, "\tldr %r15, [%r12, #0]");
578 be_emit_finish_line_gas(env->emit, NULL);
580 be_emit_irprintf(env->emit, "TABLE_%d_START:\n\t.word\tTABLE_%d", block_nr, block_nr);
581 be_emit_finish_line_gas(env->emit, NULL);
582 be_emit_irprintf(env->emit, "\t.align 2");
583 be_emit_finish_line_gas(env->emit, NULL);
584 be_emit_irprintf(env->emit, "TABLE_%d:", block_nr);
585 be_emit_finish_line_gas(env->emit, NULL);
587 for (i = 0; i < n_projs; ++i) {
591 block = get_irn_link(proj);
593 block = get_irn_link(projs[get_arm_SwitchJmp_default_proj_num(irn)]);
595 be_emit_cstring(env->emit, "\t.word\t");
596 arm_emit_block_label(env, block);
597 be_emit_finish_line_gas(env->emit, NULL);
599 be_emit_irprintf(env->emit, "\t.align 2\n");
600 be_emit_finish_line_gas(env->emit, NULL);
604 /************************************************************************/
606 /************************************************************************/
608 static void emit_be_Call(arm_emit_env_t *env, const ir_node *irn) {
609 ir_entity *ent = be_Call_get_entity(irn);
611 be_emit_cstring(env->emit, "\tbl ");
613 mark_entity_visited(ent);
614 be_emit_ident(env->emit, get_entity_ld_ident(ent));
616 arm_emit_source_register(env, irn, be_pos_Call_ptr);
618 be_emit_finish_line_gas(env->emit, irn);
621 /** Emit an IncSP node */
622 static void emit_be_IncSP(arm_emit_env_t *env, const ir_node *irn) {
623 int offs = be_get_IncSP_offset(irn);
626 be_emit_cstring(env->emit, "\tadd ");
627 arm_emit_dest_register(env, irn, 0);
628 be_emit_cstring(env->emit, ", ");
629 arm_emit_source_register(env, irn, 0);
630 be_emit_cstring(env->emit, ", #");
631 arm_emit_offset(env, irn);
633 be_emit_cstring(env->emit, "\t/* omitted IncSP(");
634 arm_emit_offset(env, irn);
635 be_emit_cstring(env->emit,") */");
637 be_emit_finish_line_gas(env->emit, irn);
640 static void emit_be_Copy(arm_emit_env_t *env, const ir_node *irn) {
641 ir_mode *mode = get_irn_mode(irn);
643 if (get_in_reg(env->arch_env, irn, 0) == get_out_reg(env->arch_env, irn, 0)) {
644 be_emit_cstring(env->emit, "\t/* omitted Copy: ");
645 arm_emit_source_register(env, irn, 0);
646 be_emit_cstring(env->emit, " -> ");
647 arm_emit_dest_register(env, irn, 0);
648 be_emit_finish_line_gas(env->emit, irn);
652 if (mode_is_float(mode)) {
653 if (USE_FPA(env->cg->isa)) {
654 be_emit_cstring(env->emit, "\tmvf");
655 arm_emit_mode(env, irn);
656 be_emit_char(env->emit, ' ');
657 arm_emit_dest_register(env, irn, 0);
658 be_emit_cstring(env->emit, ", ");
659 arm_emit_source_register(env, irn, 0);
660 be_emit_finish_line_gas(env->emit, irn);
662 assert(0 && "move not supported for this mode");
663 panic("emit_be_Copy: move not supported for this mode");
665 } else if (mode_is_numP(mode)) {
666 be_emit_cstring(env->emit, "\tmov ");
667 arm_emit_dest_register(env, irn, 0);
668 be_emit_cstring(env->emit, ", ");
669 arm_emit_source_register(env, irn, 0);
670 be_emit_finish_line_gas(env->emit, irn);
672 assert(0 && "move not supported for this mode");
673 panic("emit_be_Copy: move not supported for this mode");
678 * Emit code for a Spill.
680 static void emit_be_Spill(arm_emit_env_t *env, const ir_node *irn) {
681 ir_mode *mode = get_irn_mode(be_get_Spill_val(irn));
683 if (mode_is_float(mode)) {
684 if (USE_FPA(env->cg->isa)) {
685 be_emit_cstring(env->emit, "\tstf");
686 arm_emit_fpa_postfix(env, mode);
687 be_emit_char(env->emit, ' ');
689 assert(0 && "spill not supported for this mode");
690 panic("emit_be_Spill: spill not supported for this mode");
692 } else if (mode_is_dataM(mode)) {
693 be_emit_cstring(env->emit, "\tstr ");
695 assert(0 && "spill not supported for this mode");
696 panic("emit_be_Spill: spill not supported for this mode");
698 arm_emit_source_register(env, irn, 1);
699 be_emit_cstring(env->emit, ", [");
700 arm_emit_source_register(env, irn, 0);
701 be_emit_cstring(env->emit, ", #");
702 arm_emit_offset(env, irn);
703 be_emit_char(env->emit, ']');
704 be_emit_finish_line_gas(env->emit, irn);
708 * Emit code for a Reload.
710 static void emit_be_Reload(arm_emit_env_t *env, const ir_node *irn) {
711 ir_mode *mode = get_irn_mode(irn);
713 if (mode_is_float(mode)) {
714 if (USE_FPA(env->cg->isa)) {
715 be_emit_cstring(env->emit, "\tldf");
716 arm_emit_fpa_postfix(env, mode);
717 be_emit_char(env->emit, ' ');
719 assert(0 && "reload not supported for this mode");
720 panic("emit_be_Reload: reload not supported for this mode");
722 } else if (mode_is_dataM(mode)) {
723 be_emit_cstring(env->emit, "\tldr ");
725 assert(0 && "reload not supported for this mode");
726 panic("emit_be_Reload: reload not supported for this mode");
728 arm_emit_dest_register(env, irn, 0);
729 be_emit_cstring(env->emit, ", [");
730 arm_emit_source_register(env, irn, 0);
731 be_emit_cstring(env->emit, ", #");
732 arm_emit_offset(env, irn);
733 be_emit_char(env->emit, ']');
734 be_emit_finish_line_gas(env->emit, irn);
737 static void emit_be_Perm(arm_emit_env_t *env, const ir_node *irn) {
738 be_emit_cstring(env->emit, "\teor ");
739 arm_emit_source_register(env, irn, 0);
740 be_emit_cstring(env->emit, ", ");
741 arm_emit_source_register(env, irn, 0);
742 be_emit_cstring(env->emit, ", ");
743 arm_emit_source_register(env, irn, 1);
744 be_emit_finish_line_gas(env->emit, NULL);
746 be_emit_cstring(env->emit, "\teor ");
747 arm_emit_source_register(env, irn, 1);
748 be_emit_cstring(env->emit, ", ");
749 arm_emit_source_register(env, irn, 0);
750 be_emit_cstring(env->emit, ", ");
751 arm_emit_source_register(env, irn, 1);
752 be_emit_finish_line_gas(env->emit, NULL);
754 be_emit_cstring(env->emit, "\teor ");
755 arm_emit_source_register(env, irn, 0);
756 be_emit_cstring(env->emit, ", ");
757 arm_emit_source_register(env, irn, 0);
758 be_emit_cstring(env->emit, ", ");
759 arm_emit_source_register(env, irn, 1);
760 be_emit_finish_line_gas(env->emit, irn);
763 static void emit_be_StackParam(arm_emit_env_t *env, const ir_node *irn) {
764 ir_mode *mode = get_irn_mode(irn);
766 if (mode_is_float(mode)) {
767 if (USE_FPA(env->cg->isa)) {
768 be_emit_cstring(env->emit,"\tldf");
769 arm_emit_fpa_postfix(env, mode);
770 be_emit_char(env->emit, ' ');
772 assert(0 && "stackparam not supported for this mode");
773 panic("emit_be_StackParam: stackparam not supported for this mode");
776 be_emit_cstring(env->emit,"\tldr ");
778 arm_emit_dest_register(env, irn, 0);
779 be_emit_cstring(env->emit, ", [");
780 arm_emit_source_register(env, irn, 0);
781 be_emit_cstring(env->emit,", #");
782 arm_emit_offset(env, irn);
783 be_emit_finish_line_gas(env->emit, irn);
786 /************************************************************************/
788 /************************************************************************/
790 static void emit_Jmp(arm_emit_env_t *env, const ir_node *irn) {
791 const ir_edge_t *edge = get_irn_out_edge_first(irn);
792 ir_node *target_block = get_edge_src_irn(edge);
793 ir_node *block = get_nodes_block(irn);
795 if (target_block == sched_next_block(block)) {
796 be_emit_pad_comment(env->emit);
797 be_emit_cstring(env->emit, "/* fallthrough ");
798 arm_emit_block_label(env, target_block);
799 be_emit_cstring(env->emit, " */");
800 be_emit_finish_line_gas(env->emit, NULL);
802 be_emit_cstring(env->emit, "\tb ");
803 arm_emit_block_label(env, target_block);
804 be_emit_finish_line_gas(env->emit, irn);
808 static void emit_arm_fpaDbl2GP(arm_emit_env_t *env, const ir_node *irn) {
809 be_emit_cstring(env->emit, "\tstfd ");
810 arm_emit_source_register(env, irn, 0);
811 be_emit_cstring(env->emit, ", [sp, #-8]!");
812 be_emit_pad_comment(env->emit);
813 be_emit_cstring(env->emit, "/* Push fp to stack */");
814 be_emit_finish_line_gas(env->emit, NULL);
816 be_emit_cstring(env->emit, "\tldmfd sp!, {");
817 arm_emit_dest_register(env, irn, 1);
818 be_emit_cstring(env->emit, ", ");
819 arm_emit_dest_register(env, irn, 0);
820 be_emit_char(env->emit, '}');
821 be_emit_pad_comment(env->emit);
822 be_emit_cstring(env->emit, "/* Pop destination */");
823 be_emit_finish_line_gas(env->emit, irn);
826 static void emit_arm_LdTls(arm_emit_env_t *env, const ir_node *irn) {
827 panic("TLS not supported for this target\n");
828 /* Er... our gcc does not support it... Install a newer toolchain. */
831 /***********************************************************************************
834 * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
835 * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
836 * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
837 * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
839 ***********************************************************************************/
841 static void emit_silence(arm_emit_env_t *env, const ir_node *irn) {
846 * The type of a emitter function.
848 typedef void (emit_func)(arm_emit_env_t *env, const ir_node *irn);
851 * Set a node emitter. Make it a bit more type safe.
853 static INLINE void set_emitter(ir_op *op, emit_func arm_emit_node) {
854 op->ops.generic = (op_func)arm_emit_node;
858 * Enters the emitter functions for handled nodes into the generic
859 * pointer of an opcode.
861 static void arm_register_emitters(void) {
863 #define ARM_EMIT(a) set_emitter(op_arm_##a, emit_arm_##a)
864 #define EMIT(a) set_emitter(op_##a, emit_##a)
865 #define BE_EMIT(a) set_emitter(op_be_##a, emit_be_##a)
866 #define SILENCE(a) set_emitter(op_##a, emit_silence)
868 /* first clear the generic function pointer for all ops */
869 clear_irp_opcodes_generic_func();
871 /* register all emitter functions defined in spec */
872 arm_register_spec_emitters();
874 /* other emitter functions */
877 // ARM_EMIT(CopyB_i);
903 SILENCE(be_CopyKeep);
904 SILENCE(be_RegParams);
916 * Emits code for a node.
918 static void arm_emit_node(arm_emit_env_t *env, const ir_node *irn) {
919 ir_op *op = get_irn_op(irn);
921 if (op->ops.generic) {
922 emit_func *emit = (emit_func *)op->ops.generic;
925 be_emit_cstring(env->emit, "\t/* TODO */");
926 be_emit_finish_line_gas(env->emit, irn);
931 * Walks over the nodes in a block connected by scheduling edges
932 * and emits code for each node.
934 void arm_gen_block(ir_node *block, void *ctx) {
935 arm_emit_env_t *env = ctx;
938 arm_emit_block_label(env, block);
939 be_emit_cstring(env->emit, ":\n");
940 be_emit_write_line(env->emit);
942 sched_foreach(block, irn) {
943 arm_emit_node(env, irn);
949 * Emits code for function start.
951 void arm_func_prolog(arm_emit_env_t *env, ir_graph *irg) {
952 be_emit_env_t *eenv = env->emit;
953 ir_entity *ent = get_irg_entity(irg);
954 const char *irg_name = get_entity_ld_name(ent);
956 be_emit_write_line(eenv);
957 be_gas_emit_switch_section(eenv, GAS_SECTION_TEXT);
958 be_emit_cstring(eenv, "\t.align 2\n");
960 if (get_entity_visibility(ent) == visibility_external_visible)
961 be_emit_irprintf(eenv, "\t.global %s\n", irg_name);
962 be_emit_irprintf(eenv, "%s:\n", irg_name);
966 * Emits code for function end
968 void arm_emit_end(FILE *F, ir_graph *irg) {
969 fprintf(F, "\t.ident \"firmcc\"\n");
973 * Sets labels for control flow nodes (jump target)
974 * TODO: Jump optimization
976 void arm_gen_labels(ir_node *block, void *env) {
978 int n = get_Block_n_cfgpreds(block);
980 for (n--; n >= 0; n--) {
981 pred = get_Block_cfgpred(block, n);
982 set_irn_link(pred, block);
987 * Compare two entries of the symbol or tarval set.
989 static int cmp_sym_or_tv(const void *elt, const void *key, size_t size) {
990 const sym_or_tv *p1 = elt;
991 const sym_or_tv *p2 = key;
993 /* as an identifier NEVER can point to a tarval, it's enough
994 to compare it this way */
995 return p1->u.generic != p2->u.generic;
999 * Main driver. Emits the code for one routine.
1001 void arm_gen_routine(const arm_code_gen_t *cg, ir_graph *irg)
1003 arm_emit_env_t emit_env;
1004 ir_node **blk_sched;
1007 emit_env.emit = &cg->isa->emit;
1008 emit_env.arch_env = cg->arch_env;
1010 emit_env.sym_or_tv = new_set(cmp_sym_or_tv, 8);
1011 FIRM_DBG_REGISTER(emit_env.mod, "firm.be.arm.emit");
1013 /* set the global arch_env (needed by print hooks) */
1014 arch_env = cg->arch_env;
1016 arm_register_emitters();
1018 /* create the block schedule. For now, we don't need it earlier. */
1019 blk_sched = be_create_block_schedule(cg->irg, cg->birg->exec_freq);
1021 arm_func_prolog(&emit_env, irg);
1022 irg_block_walk_graph(irg, arm_gen_labels, NULL, &emit_env);
1024 n = ARR_LEN(blk_sched);
1025 for (i = 0; i < n;) {
1026 ir_node *block, *next_bl;
1028 block = blk_sched[i];
1030 next_bl = i < n ? blk_sched[i] : NULL;
1032 /* set here the link. the emitter expects to find the next block here */
1033 set_irn_link(block, next_bl);
1034 arm_gen_block(block, &emit_env);
1037 /* emit SymConst values */
1038 if (set_count(emit_env.sym_or_tv) > 0) {
1041 be_emit_cstring(emit_env.emit, "\t.align 2\n");
1043 foreach_set(emit_env.sym_or_tv, entry) {
1044 be_emit_irprintf(emit_env.emit, ".L%u:\n", entry->label);
1046 if (entry->is_ident) {
1047 be_emit_cstring(emit_env.emit, "\t.word\t");
1048 be_emit_ident(emit_env.emit, entry->u.id);
1049 be_emit_char(emit_env.emit, '\n');
1050 be_emit_write_line(emit_env.emit);
1052 tarval *tv = entry->u.tv;
1053 int i, size = get_mode_size_bytes(get_tarval_mode(tv));
1056 /* beware: ARM fpa uses bigendian format */
1057 for (i = ((size + 3) & ~3) - 4; i >= 0; i -= 4) {
1059 v = get_tarval_sub_bits(tv, i+3);
1060 v = (v << 8) | get_tarval_sub_bits(tv, i+2);
1061 v = (v << 8) | get_tarval_sub_bits(tv, i+1);
1062 v = (v << 8) | get_tarval_sub_bits(tv, i+0);
1063 be_emit_irprintf(emit_env.emit, "\t.word\t%u\n", v);
1064 be_emit_write_line(emit_env.emit);
1068 be_emit_char(emit_env.emit, '\n');
1069 be_emit_write_line(emit_env.emit);
1071 del_set(emit_env.sym_or_tv);