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
45 #include "raw_bitset.h"
47 #include "../besched.h"
48 #include "../beblocksched.h"
49 #include "../beirg_t.h"
50 #include "../begnuas.h"
52 #include "arm_emitter.h"
53 #include "gen_arm_emitter.h"
54 #include "arm_nodes_attr.h"
55 #include "arm_new_nodes.h"
56 #include "arm_map_regs.h"
57 #include "gen_arm_regalloc_if.h"
59 #include "../benode_t.h"
61 #define SNPRINTF_BUF_LEN 128
63 static const arch_env_t *arch_env = NULL;
66 * Returns the register at in position pos.
68 static const arch_register_t *get_in_reg(const arch_env_t *arch_env, const ir_node *irn, int pos) {
70 const arch_register_t *reg = NULL;
72 assert(get_irn_arity(irn) > pos && "Invalid IN position");
74 /* The out register of the operator at position pos is the
75 in register we need. */
76 op = get_irn_n(irn, pos);
78 reg = arch_get_irn_register(arch_env, op);
80 assert(reg && "no in register found");
82 /* in case of a joker register: just return a valid register */
83 if (arch_register_type_is(reg, joker)) {
84 const arch_register_req_t *req;
86 /* ask for the requirements */
87 req = arch_get_register_req(arch_env, irn, pos);
89 if (arch_register_req_is(req, limited)) {
90 /* in case of limited requirements: get the first allowed register */
91 unsigned idx = rbitset_next(req->limited, 0, 1);
92 reg = arch_register_for_index(req->cls, idx);
94 /* otherwise get first register in class */
95 reg = arch_register_for_index(req->cls, 0);
103 * Returns the register at out position pos.
105 static const arch_register_t *get_out_reg(const arch_env_t *arch_env,
106 const ir_node *node, int pos)
109 const arch_register_t *reg = NULL;
111 /* 1st case: irn is not of mode_T, so it has only */
112 /* one OUT register -> good */
113 /* 2nd case: irn is of mode_T -> collect all Projs and ask the */
114 /* Proj with the corresponding projnum for the register */
116 if (get_irn_mode(node) != mode_T) {
117 reg = arch_get_irn_register(arch_env, node);
118 } else if (is_arm_irn(node)) {
119 reg = get_arm_out_reg(node, pos);
121 const ir_edge_t *edge;
123 foreach_out_edge(node, edge) {
124 proj = get_edge_src_irn(edge);
125 assert(is_Proj(proj) && "non-Proj from mode_T node");
126 if (get_Proj_proj(proj) == pos) {
127 reg = arch_get_irn_register(arch_env, proj);
133 assert(reg && "no out register found");
137 /*************************************************************
139 * (_) | | / _| | | | |
140 * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __
141 * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__|
142 * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ |
143 * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_|
146 *************************************************************/
149 * Emits a block label from the given block.
151 static void arm_emit_block_label(arm_emit_env_t *env, const ir_node *block) {
152 be_emit_irprintf(env->emit, "BLOCK_%u", get_irn_node_nr(block));
156 * Emit the name of the source register at given input position.
158 void arm_emit_source_register(arm_emit_env_t *env, const ir_node *node, int pos) {
159 const arch_register_t *reg = get_in_reg(env->arch_env, node, pos);
160 be_emit_string(env->emit, arch_register_get_name(reg));
164 * Emit the name of the destination register at given output position.
166 void arm_emit_dest_register(arm_emit_env_t *env, const ir_node *node, int pos) {
167 const arch_register_t *reg = get_out_reg(env->arch_env, node, pos);
168 be_emit_string(env->emit, arch_register_get_name(reg));
172 * Emit a node's offset.
174 void arm_emit_offset(arm_emit_env_t *env, const ir_node *node) {
176 ir_op *irn_op = get_irn_op(node);
178 if (irn_op == op_be_StackParam) {
179 ir_entity *ent = be_get_frame_entity(node);
180 offset = get_entity_offset(ent);
181 } else if (irn_op == op_be_Reload || irn_op == op_be_Spill) {
182 ir_entity *ent = be_get_frame_entity(node);
183 offset = get_entity_offset(ent);
184 } else if (irn_op == op_be_IncSP) {
185 offset = - be_get_IncSP_offset(node);
187 assert(!"unimplemented arm_emit_offset for this node type");
188 panic("unimplemented arm_emit_offset for this node type");
190 be_emit_irprintf(env->emit, "%d", offset);
194 * Emit the arm fpa instruction suffix depending on the mode.
196 static void arm_emit_fpa_postfix(arm_emit_env_t *env, ir_mode *mode) {
197 int bits = get_mode_size_bits(mode);
199 be_emit_char(env->emit, 's');
201 be_emit_char(env->emit, 'd');
203 be_emit_char(env->emit, 'e');
207 * Emit the instruction suffix depending on the mode.
209 void arm_emit_mode(arm_emit_env_t *env, const ir_node *node) {
212 if (is_arm_irn(node)) {
213 const arm_attr_t *attr = get_arm_attr_const(node);
214 mode = attr->op_mode ? attr->op_mode : get_irn_mode(node);
216 mode = get_irn_mode(node);
218 arm_emit_fpa_postfix(env, mode);
223 * Returns non-zero if a mode has a Immediate attribute.
225 int is_immediate_node(const ir_node *irn) {
226 const arm_attr_t *attr = get_arm_attr_const(irn);
227 return ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM;
231 * Emit a const or SymConst value.
233 void arm_emit_immediate(arm_emit_env_t *env, const ir_node *node) {
234 if (is_immediate_node(node)) {
235 be_emit_irprintf(env->emit, "#0x%X", arm_decode_imm_w_shift(get_arm_value(node)));
236 } else if (is_arm_SymConst(node))
237 be_emit_ident(env->emit, get_arm_symconst_id(node));
239 assert(!"not a Constant");
244 * Returns the tarval or offset of an arm node as a string.
246 void arm_emit_shift(arm_emit_env_t *env, const ir_node *node) {
247 arm_shift_modifier mod;
249 mod = get_arm_shift_modifier(node);
250 if (ARM_HAS_SHIFT(mod)) {
251 long v = get_tarval_long(get_arm_value(node));
253 be_emit_irprintf(env->emit, ", %s #%l", arm_shf_mod_name(mod), v);
257 /** An entry in the sym_or_tv set. */
258 typedef struct sym_or_tv {
260 ident *id; /**< An ident. */
261 tarval *tv; /**< A tarval. */
262 const void *generic; /**< For generic compare. */
264 unsigned label; /**< the associated label. */
265 char is_ident; /**< Non-zero if an ident is stored. */
269 * Returns a unique label. This number will not be used a second time.
271 static unsigned get_unique_label(void) {
272 static unsigned id = 0;
279 static void emit_arm_SymConst(arm_emit_env_t *env, const ir_node *irn) {
280 sym_or_tv key, *entry;
283 key.u.id = get_arm_symconst_id(irn);
286 entry = (sym_or_tv *)set_insert(env->sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
287 if (entry->label == 0) {
288 /* allocate a label */
289 entry->label = get_unique_label();
291 label = entry->label;
293 /* load the symbol indirect */
294 be_emit_cstring(env->emit, "\tldr ");
295 arm_emit_dest_register(env, irn, 0);
296 be_emit_irprintf(env->emit, ", .L%u", label);
297 be_emit_finish_line_gas(env->emit, irn);
301 * Emit a floating point fpa constant.
303 static void emit_arm_fpaConst(arm_emit_env_t *env, const ir_node *irn) {
304 sym_or_tv key, *entry;
308 key.u.tv = get_arm_value(irn);
311 entry = (sym_or_tv *)set_insert(env->sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
312 if (entry->label == 0) {
313 /* allocate a label */
314 entry->label = get_unique_label();
316 label = entry->label;
318 /* load the tarval indirect */
319 mode = get_irn_mode(irn);
320 be_emit_cstring(env->emit, "\tldf");
321 arm_emit_fpa_postfix(env, mode);
322 be_emit_char(env->emit, ' ');
324 arm_emit_dest_register(env, irn, 0);
325 be_emit_irprintf(env->emit, ", .L%u", label);
326 be_emit_finish_line_gas(env->emit, irn);
330 * Returns the next block in a block schedule.
332 static ir_node *sched_next_block(ir_node *block) {
333 return get_irn_link(block);
337 * Emit a conditional jump.
339 static void emit_arm_CondJmp(arm_emit_env_t *env, const ir_node *irn) {
340 const ir_edge_t *edge;
341 ir_node *true_block = NULL;
342 ir_node *false_block = NULL;
343 ir_node *op1 = get_irn_n(irn, 0);
344 ir_mode *opmode = get_irn_mode(op1);
346 int proj_num = get_arm_CondJmp_proj_num(irn);
348 foreach_out_edge(irn, edge) {
349 ir_node *proj = get_edge_src_irn(edge);
350 long nr = get_Proj_proj(proj);
351 ir_node *block = get_irn_link(proj);
352 if (nr == pn_Cond_true) {
359 if (proj_num == pn_Cmp_False) {
360 /* always false: should not happen */
361 be_emit_cstring(env->emit, "\tb ");
362 arm_emit_block_label(env, false_block);
363 be_emit_finish_line_gas(env->emit, irn);
364 } else if (proj_num == pn_Cmp_True) {
365 /* always true: should not happen */
366 be_emit_cstring(env->emit, "\tb ");
367 arm_emit_block_label(env, true_block);
368 be_emit_finish_line_gas(env->emit, irn);
370 ir_node *block = get_nodes_block(irn);
372 if (mode_is_float(opmode)) {
373 suffix = "ICHWILLIMPLEMENTIERTWERDEN";
375 be_emit_cstring(env->emit, "\tfcmp ");
376 arm_emit_source_register(env, irn, 0);
377 be_emit_cstring(env->emit, ", ");
378 arm_emit_source_register(env, irn, 1);
379 be_emit_finish_line_gas(env->emit, irn);
381 be_emit_cstring(env->emit, "\tfmstat");
382 be_emit_pad_comment(env->emit);
383 be_emit_cstring(env->emit, "/* FCSPR -> CPSR */");
384 be_emit_finish_line_gas(env->emit, NULL);
386 if (true_block == sched_next_block(block)) {
388 proj_num = get_negated_pnc(proj_num, opmode);
391 case pn_Cmp_Eq: suffix = "eq"; break;
392 case pn_Cmp_Lt: suffix = "lt"; break;
393 case pn_Cmp_Le: suffix = "le"; break;
394 case pn_Cmp_Gt: suffix = "gt"; break;
395 case pn_Cmp_Ge: suffix = "ge"; break;
396 case pn_Cmp_Lg: suffix = "ne"; break;
397 case pn_Cmp_Leg: suffix = "al"; break;
398 default: assert(!"Cmp unsupported"); suffix = "al";
400 be_emit_cstring(env->emit, "\tcmp ");
401 arm_emit_source_register(env, irn, 0);
402 be_emit_cstring(env->emit, ", ");
403 arm_emit_source_register(env, irn, 1);
404 be_emit_finish_line_gas(env->emit, irn);
407 if (true_block == sched_next_block(block)) {
408 be_emit_irprintf(env->emit, "\tb%s ", suffix);
409 arm_emit_block_label(env, true_block);
410 be_emit_pad_comment(env->emit);
411 be_emit_cstring(env->emit, "/* false case */");
412 be_emit_finish_line_gas(env->emit, NULL);
414 be_emit_pad_comment(env->emit);
415 be_emit_cstring(env->emit, "/* fallthrough ");
416 arm_emit_block_label(env, false_block);
417 be_emit_cstring(env->emit, " */");
418 be_emit_finish_line_gas(env->emit, NULL);
420 be_emit_irprintf(env->emit, "\tb%s ", suffix);
421 arm_emit_block_label(env, true_block);
422 be_emit_pad_comment(env->emit);
423 be_emit_cstring(env->emit, "/* true case */");
424 be_emit_finish_line_gas(env->emit, NULL);
426 if (false_block == sched_next_block(block)) {
427 be_emit_pad_comment(env->emit);
428 be_emit_cstring(env->emit, "/* fallthrough ");
429 arm_emit_block_label(env, false_block);
430 be_emit_cstring(env->emit, " */");
431 be_emit_finish_line_gas(env->emit, NULL);
433 be_emit_cstring(env->emit, "b ");
434 arm_emit_block_label(env, false_block);
435 be_emit_pad_comment(env->emit);
436 be_emit_cstring(env->emit, "/* false case */");
437 be_emit_finish_line_gas(env->emit, NULL);
444 * Create the CopyB instruction sequence.
446 static void emit_arm_CopyB(arm_emit_env_t *env, const ir_node *irn) {
447 unsigned int size = get_tarval_long(get_arm_value(irn));
449 be_emit_cstring(env->emit, "/* MemCopy (");
450 arm_emit_source_register(env, irn, 1);
451 be_emit_cstring(env->emit, ")->(");
452 arm_emit_source_register(env, irn, 0);
453 be_emit_irprintf(env->emit, " [%d bytes], Uses ", size);
454 arm_emit_source_register(env, irn, 2);
455 be_emit_cstring(env->emit, ", ");
456 arm_emit_source_register(env, irn, 3);
457 be_emit_cstring(env->emit, ", ");
458 arm_emit_source_register(env, irn, 4);
459 be_emit_cstring(env->emit, ", and %r12 */");
460 be_emit_finish_line_gas(env->emit, NULL);
462 assert ( size > 0 && "CopyB needs size > 0" );
470 be_emit_cstring(env->emit, "\tldr %%r12, [");
471 arm_emit_source_register(env, irn, 1);
472 be_emit_cstring(env->emit, ", #0]!");
473 be_emit_finish_line_gas(env->emit, NULL);
475 be_emit_cstring(env->emit, "\tstr %%r12, [");
476 arm_emit_source_register(env, irn, 0);
477 be_emit_cstring(env->emit, ", #0]!");
478 be_emit_finish_line_gas(env->emit, irn);
481 be_emit_cstring(env->emit, "\tldmia ");
482 arm_emit_source_register(env, irn, 1);
483 be_emit_cstring(env->emit, "!, {%r12, ");
484 arm_emit_source_register(env, irn, 2);
485 be_emit_char(env->emit, '}');
486 be_emit_finish_line_gas(env->emit, NULL);
488 be_emit_cstring(env->emit, "\tstmia ");
489 arm_emit_source_register(env, irn, 0);
490 be_emit_cstring(env->emit, "!, {%r12, ");
491 arm_emit_source_register(env, irn, 2);
492 be_emit_char(env->emit, '}');
493 be_emit_finish_line_gas(env->emit, irn);
496 be_emit_cstring(env->emit, "\tldmia ");
497 arm_emit_source_register(env, irn, 1);
498 be_emit_cstring(env->emit, "!, {%r12, ");
499 arm_emit_source_register(env, irn, 2);
500 be_emit_cstring(env->emit, ", ");
501 arm_emit_source_register(env, irn, 3);
502 be_emit_char(env->emit, '}');
503 be_emit_finish_line_gas(env->emit, NULL);
505 be_emit_cstring(env->emit, "\tstmia ");
506 arm_emit_source_register(env, irn, 0);
507 be_emit_cstring(env->emit, "!, {%r12, ");
508 arm_emit_source_register(env, irn, 2);
509 be_emit_cstring(env->emit, ", ");
510 arm_emit_source_register(env, irn, 3);
511 be_emit_char(env->emit, '}');
512 be_emit_finish_line_gas(env->emit, irn);
517 be_emit_cstring(env->emit, "\tldmia ");
518 arm_emit_source_register(env, irn, 1);
519 be_emit_cstring(env->emit, "!, {%r12, ");
520 arm_emit_source_register(env, irn, 2);
521 be_emit_cstring(env->emit, ", ");
522 arm_emit_source_register(env, irn, 3);
523 be_emit_cstring(env->emit, ", ");
524 arm_emit_source_register(env, irn, 4);
525 be_emit_char(env->emit, '}');
526 be_emit_finish_line_gas(env->emit, NULL);
528 be_emit_cstring(env->emit, "\tstmia ");
529 arm_emit_source_register(env, irn, 0);
530 be_emit_cstring(env->emit, "!, {%r12, ");
531 arm_emit_source_register(env, irn, 2);
532 be_emit_cstring(env->emit, ", ");
533 arm_emit_source_register(env, irn, 3);
534 be_emit_cstring(env->emit, ", ");
535 arm_emit_source_register(env, irn, 4);
536 be_emit_char(env->emit, '}');
537 be_emit_finish_line_gas(env->emit, irn);
542 static void emit_arm_SwitchJmp(arm_emit_env_t *env, const ir_node *irn) {
543 const ir_edge_t *edge;
549 ir_node *default_block = NULL;
551 block_nr = get_irn_node_nr(irn);
552 n_projs = get_arm_SwitchJmp_n_projs(irn);
554 projs = xcalloc(n_projs , sizeof(ir_node*));
556 foreach_out_edge(irn, edge) {
557 proj = get_edge_src_irn(edge);
558 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
560 if (get_Proj_proj(proj) == get_arm_SwitchJmp_default_proj_num(irn))
561 default_block = get_irn_link(proj);
563 projs[get_Proj_proj(proj)] = proj;
565 assert(default_block != NULL);
572 be_emit_cstring(env->emit, "\tcmp ");
573 arm_emit_source_register(env, irn, 0);
574 be_emit_irprintf(env->emit, ", #%u", n_projs - 1);
575 be_emit_finish_line_gas(env->emit, irn);
577 be_emit_cstring(env->emit, "\tbhi ");
578 arm_emit_block_label(env, default_block);
579 be_emit_finish_line_gas(env->emit, NULL);
582 LDR %r12, .TABLE_X_START
583 ADD %r12, %r12, [%1S, LSL #2]
587 be_emit_irprintf(env->emit, "\tldr %%r12, TABLE_%d_START", block_nr);
588 be_emit_finish_line_gas(env->emit, NULL);
590 be_emit_irprintf(env->emit, "\tadd %%r12, %%r12, ");
591 arm_emit_source_register(env, irn, 0);
592 be_emit_cstring(env->emit, ", LSL #2");
593 be_emit_finish_line_gas(env->emit, NULL);
595 be_emit_cstring(env->emit, "\tldr %r15, [%r12, #0]");
596 be_emit_finish_line_gas(env->emit, NULL);
598 be_emit_irprintf(env->emit, "TABLE_%d_START:\n\t.word\tTABLE_%d", block_nr, block_nr);
599 be_emit_finish_line_gas(env->emit, NULL);
600 be_emit_irprintf(env->emit, "\t.align 2");
601 be_emit_finish_line_gas(env->emit, NULL);
602 be_emit_irprintf(env->emit, "TABLE_%d:", block_nr);
603 be_emit_finish_line_gas(env->emit, NULL);
605 for (i = 0; i < n_projs; ++i) {
609 block = get_irn_link(proj);
611 block = get_irn_link(projs[get_arm_SwitchJmp_default_proj_num(irn)]);
613 be_emit_cstring(env->emit, "\t.word\t");
614 arm_emit_block_label(env, block);
615 be_emit_finish_line_gas(env->emit, NULL);
617 be_emit_irprintf(env->emit, "\t.align 2\n");
618 be_emit_finish_line_gas(env->emit, NULL);
622 /************************************************************************/
624 /************************************************************************/
626 static void emit_be_Call(arm_emit_env_t *env, const ir_node *irn) {
627 ir_entity *ent = be_Call_get_entity(irn);
629 be_emit_cstring(env->emit, "\tbl ");
631 set_entity_backend_marked(ent, 1);
632 be_emit_ident(env->emit, get_entity_ld_ident(ent));
634 arm_emit_source_register(env, irn, be_pos_Call_ptr);
636 be_emit_finish_line_gas(env->emit, irn);
639 /** Emit an IncSP node */
640 static void emit_be_IncSP(arm_emit_env_t *env, const ir_node *irn) {
641 int offs = be_get_IncSP_offset(irn);
644 be_emit_cstring(env->emit, "\tadd ");
645 arm_emit_dest_register(env, irn, 0);
646 be_emit_cstring(env->emit, ", ");
647 arm_emit_source_register(env, irn, 0);
648 be_emit_cstring(env->emit, ", #");
649 arm_emit_offset(env, irn);
651 be_emit_cstring(env->emit, "\t/* omitted IncSP(");
652 arm_emit_offset(env, irn);
653 be_emit_cstring(env->emit,") */");
655 be_emit_finish_line_gas(env->emit, irn);
658 static void emit_be_Copy(arm_emit_env_t *env, const ir_node *irn) {
659 ir_mode *mode = get_irn_mode(irn);
661 if (get_in_reg(env->arch_env, irn, 0) == get_out_reg(env->arch_env, irn, 0)) {
662 be_emit_cstring(env->emit, "\t/* omitted Copy: ");
663 arm_emit_source_register(env, irn, 0);
664 be_emit_cstring(env->emit, " -> ");
665 arm_emit_dest_register(env, irn, 0);
666 be_emit_finish_line_gas(env->emit, irn);
670 if (mode_is_float(mode)) {
671 if (USE_FPA(env->cg->isa)) {
672 be_emit_cstring(env->emit, "\tmvf");
673 arm_emit_mode(env, irn);
674 be_emit_char(env->emit, ' ');
675 arm_emit_dest_register(env, irn, 0);
676 be_emit_cstring(env->emit, ", ");
677 arm_emit_source_register(env, irn, 0);
678 be_emit_finish_line_gas(env->emit, irn);
680 assert(0 && "move not supported for this mode");
681 panic("emit_be_Copy: move not supported for this mode");
683 } else if (mode_is_numP(mode)) {
684 be_emit_cstring(env->emit, "\tmov ");
685 arm_emit_dest_register(env, irn, 0);
686 be_emit_cstring(env->emit, ", ");
687 arm_emit_source_register(env, irn, 0);
688 be_emit_finish_line_gas(env->emit, irn);
690 assert(0 && "move not supported for this mode");
691 panic("emit_be_Copy: move not supported for this mode");
696 * Emit code for a Spill.
698 static void emit_be_Spill(arm_emit_env_t *env, const ir_node *irn) {
699 ir_mode *mode = get_irn_mode(be_get_Spill_val(irn));
701 if (mode_is_float(mode)) {
702 if (USE_FPA(env->cg->isa)) {
703 be_emit_cstring(env->emit, "\tstf");
704 arm_emit_fpa_postfix(env, mode);
705 be_emit_char(env->emit, ' ');
707 assert(0 && "spill not supported for this mode");
708 panic("emit_be_Spill: spill not supported for this mode");
710 } else if (mode_is_dataM(mode)) {
711 be_emit_cstring(env->emit, "\tstr ");
713 assert(0 && "spill not supported for this mode");
714 panic("emit_be_Spill: spill not supported for this mode");
716 arm_emit_source_register(env, irn, 1);
717 be_emit_cstring(env->emit, ", [");
718 arm_emit_source_register(env, irn, 0);
719 be_emit_cstring(env->emit, ", #");
720 arm_emit_offset(env, irn);
721 be_emit_char(env->emit, ']');
722 be_emit_finish_line_gas(env->emit, irn);
726 * Emit code for a Reload.
728 static void emit_be_Reload(arm_emit_env_t *env, const ir_node *irn) {
729 ir_mode *mode = get_irn_mode(irn);
731 if (mode_is_float(mode)) {
732 if (USE_FPA(env->cg->isa)) {
733 be_emit_cstring(env->emit, "\tldf");
734 arm_emit_fpa_postfix(env, mode);
735 be_emit_char(env->emit, ' ');
737 assert(0 && "reload not supported for this mode");
738 panic("emit_be_Reload: reload not supported for this mode");
740 } else if (mode_is_dataM(mode)) {
741 be_emit_cstring(env->emit, "\tldr ");
743 assert(0 && "reload not supported for this mode");
744 panic("emit_be_Reload: reload not supported for this mode");
746 arm_emit_dest_register(env, irn, 0);
747 be_emit_cstring(env->emit, ", [");
748 arm_emit_source_register(env, irn, 0);
749 be_emit_cstring(env->emit, ", #");
750 arm_emit_offset(env, irn);
751 be_emit_char(env->emit, ']');
752 be_emit_finish_line_gas(env->emit, irn);
755 static void emit_be_Perm(arm_emit_env_t *env, const ir_node *irn) {
756 be_emit_cstring(env->emit, "\teor ");
757 arm_emit_source_register(env, irn, 0);
758 be_emit_cstring(env->emit, ", ");
759 arm_emit_source_register(env, irn, 0);
760 be_emit_cstring(env->emit, ", ");
761 arm_emit_source_register(env, irn, 1);
762 be_emit_finish_line_gas(env->emit, NULL);
764 be_emit_cstring(env->emit, "\teor ");
765 arm_emit_source_register(env, irn, 1);
766 be_emit_cstring(env->emit, ", ");
767 arm_emit_source_register(env, irn, 0);
768 be_emit_cstring(env->emit, ", ");
769 arm_emit_source_register(env, irn, 1);
770 be_emit_finish_line_gas(env->emit, NULL);
772 be_emit_cstring(env->emit, "\teor ");
773 arm_emit_source_register(env, irn, 0);
774 be_emit_cstring(env->emit, ", ");
775 arm_emit_source_register(env, irn, 0);
776 be_emit_cstring(env->emit, ", ");
777 arm_emit_source_register(env, irn, 1);
778 be_emit_finish_line_gas(env->emit, irn);
781 static void emit_be_StackParam(arm_emit_env_t *env, const ir_node *irn) {
782 ir_mode *mode = get_irn_mode(irn);
784 if (mode_is_float(mode)) {
785 if (USE_FPA(env->cg->isa)) {
786 be_emit_cstring(env->emit,"\tldf");
787 arm_emit_fpa_postfix(env, mode);
788 be_emit_char(env->emit, ' ');
790 assert(0 && "stackparam not supported for this mode");
791 panic("emit_be_StackParam: stackparam not supported for this mode");
794 be_emit_cstring(env->emit,"\tldr ");
796 arm_emit_dest_register(env, irn, 0);
797 be_emit_cstring(env->emit, ", [");
798 arm_emit_source_register(env, irn, 0);
799 be_emit_cstring(env->emit,", #");
800 arm_emit_offset(env, irn);
801 be_emit_finish_line_gas(env->emit, irn);
804 /************************************************************************/
806 /************************************************************************/
808 static void emit_Jmp(arm_emit_env_t *env, const ir_node *irn) {
809 const ir_edge_t *edge = get_irn_out_edge_first(irn);
810 ir_node *target_block = get_edge_src_irn(edge);
811 ir_node *block = get_nodes_block(irn);
813 if (target_block == sched_next_block(block)) {
814 be_emit_pad_comment(env->emit);
815 be_emit_cstring(env->emit, "/* fallthrough ");
816 arm_emit_block_label(env, target_block);
817 be_emit_cstring(env->emit, " */");
818 be_emit_finish_line_gas(env->emit, NULL);
820 be_emit_cstring(env->emit, "\tb ");
821 arm_emit_block_label(env, target_block);
822 be_emit_finish_line_gas(env->emit, irn);
826 static void emit_arm_fpaDbl2GP(arm_emit_env_t *env, const ir_node *irn) {
827 be_emit_cstring(env->emit, "\tstfd ");
828 arm_emit_source_register(env, irn, 0);
829 be_emit_cstring(env->emit, ", [sp, #-8]!");
830 be_emit_pad_comment(env->emit);
831 be_emit_cstring(env->emit, "/* Push fp to stack */");
832 be_emit_finish_line_gas(env->emit, NULL);
834 be_emit_cstring(env->emit, "\tldmfd sp!, {");
835 arm_emit_dest_register(env, irn, 1);
836 be_emit_cstring(env->emit, ", ");
837 arm_emit_dest_register(env, irn, 0);
838 be_emit_char(env->emit, '}');
839 be_emit_pad_comment(env->emit);
840 be_emit_cstring(env->emit, "/* Pop destination */");
841 be_emit_finish_line_gas(env->emit, irn);
844 static void emit_arm_LdTls(arm_emit_env_t *env, const ir_node *irn) {
845 panic("TLS not supported for this target\n");
846 /* Er... our gcc does not support it... Install a newer toolchain. */
849 /***********************************************************************************
852 * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
853 * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
854 * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
855 * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
857 ***********************************************************************************/
859 static void emit_silence(arm_emit_env_t *env, const ir_node *irn) {
864 * The type of a emitter function.
866 typedef void (emit_func)(arm_emit_env_t *env, const ir_node *irn);
869 * Set a node emitter. Make it a bit more type safe.
871 static INLINE void set_emitter(ir_op *op, emit_func arm_emit_node) {
872 op->ops.generic = (op_func)arm_emit_node;
876 * Enters the emitter functions for handled nodes into the generic
877 * pointer of an opcode.
879 static void arm_register_emitters(void) {
881 #define ARM_EMIT(a) set_emitter(op_arm_##a, emit_arm_##a)
882 #define EMIT(a) set_emitter(op_##a, emit_##a)
883 #define BE_EMIT(a) set_emitter(op_be_##a, emit_be_##a)
884 #define SILENCE(a) set_emitter(op_##a, emit_silence)
886 /* first clear the generic function pointer for all ops */
887 clear_irp_opcodes_generic_func();
889 /* register all emitter functions defined in spec */
890 arm_register_spec_emitters();
892 /* other emitter functions */
895 // ARM_EMIT(CopyB_i);
921 SILENCE(be_CopyKeep);
922 SILENCE(be_RegParams);
934 * Emits code for a node.
936 static void arm_emit_node(arm_emit_env_t *env, const ir_node *irn) {
937 ir_op *op = get_irn_op(irn);
939 if (op->ops.generic) {
940 emit_func *emit = (emit_func *)op->ops.generic;
943 be_emit_cstring(env->emit, "\t/* TODO */");
944 be_emit_finish_line_gas(env->emit, irn);
949 * Walks over the nodes in a block connected by scheduling edges
950 * and emits code for each node.
952 void arm_gen_block(ir_node *block, void *ctx) {
953 arm_emit_env_t *env = ctx;
956 arm_emit_block_label(env, block);
957 be_emit_cstring(env->emit, ":\n");
958 be_emit_write_line(env->emit);
960 sched_foreach(block, irn) {
961 arm_emit_node(env, irn);
967 * Emits code for function start.
969 void arm_func_prolog(arm_emit_env_t *env, ir_graph *irg) {
970 be_emit_env_t *eenv = env->emit;
971 ir_entity *ent = get_irg_entity(irg);
972 const char *irg_name = get_entity_ld_name(ent);
974 be_emit_write_line(eenv);
975 be_gas_emit_switch_section(eenv, GAS_SECTION_TEXT);
976 be_emit_cstring(eenv, "\t.align 2\n");
978 if (get_entity_visibility(ent) == visibility_external_visible)
979 be_emit_irprintf(eenv, "\t.global %s\n", irg_name);
980 be_emit_irprintf(eenv, "%s:\n", irg_name);
984 * Emits code for function end
986 void arm_emit_end(FILE *F, ir_graph *irg) {
987 fprintf(F, "\t.ident \"firmcc\"\n");
991 * Sets labels for control flow nodes (jump target)
992 * TODO: Jump optimization
994 void arm_gen_labels(ir_node *block, void *env) {
996 int n = get_Block_n_cfgpreds(block);
998 for (n--; n >= 0; n--) {
999 pred = get_Block_cfgpred(block, n);
1000 set_irn_link(pred, block);
1005 * Compare two entries of the symbol or tarval set.
1007 static int cmp_sym_or_tv(const void *elt, const void *key, size_t size) {
1008 const sym_or_tv *p1 = elt;
1009 const sym_or_tv *p2 = key;
1011 /* as an identifier NEVER can point to a tarval, it's enough
1012 to compare it this way */
1013 return p1->u.generic != p2->u.generic;
1017 * Main driver. Emits the code for one routine.
1019 void arm_gen_routine(const arm_code_gen_t *cg, ir_graph *irg)
1021 arm_emit_env_t emit_env;
1022 ir_node **blk_sched;
1025 emit_env.emit = &cg->isa->emit;
1026 emit_env.arch_env = cg->arch_env;
1028 emit_env.sym_or_tv = new_set(cmp_sym_or_tv, 8);
1029 FIRM_DBG_REGISTER(emit_env.mod, "firm.be.arm.emit");
1031 /* set the global arch_env (needed by print hooks) */
1032 arch_env = cg->arch_env;
1034 arm_register_emitters();
1036 /* create the block schedule. For now, we don't need it earlier. */
1037 blk_sched = be_create_block_schedule(cg->irg, cg->birg->exec_freq);
1039 arm_func_prolog(&emit_env, irg);
1040 irg_block_walk_graph(irg, arm_gen_labels, NULL, &emit_env);
1042 n = ARR_LEN(blk_sched);
1043 for (i = 0; i < n;) {
1044 ir_node *block, *next_bl;
1046 block = blk_sched[i];
1048 next_bl = i < n ? blk_sched[i] : NULL;
1050 /* set here the link. the emitter expects to find the next block here */
1051 set_irn_link(block, next_bl);
1052 arm_gen_block(block, &emit_env);
1055 /* emit SymConst values */
1056 if (set_count(emit_env.sym_or_tv) > 0) {
1059 be_emit_cstring(emit_env.emit, "\t.align 2\n");
1061 foreach_set(emit_env.sym_or_tv, entry) {
1062 be_emit_irprintf(emit_env.emit, ".L%u:\n", entry->label);
1064 if (entry->is_ident) {
1065 be_emit_cstring(emit_env.emit, "\t.word\t");
1066 be_emit_ident(emit_env.emit, entry->u.id);
1067 be_emit_char(emit_env.emit, '\n');
1068 be_emit_write_line(emit_env.emit);
1070 tarval *tv = entry->u.tv;
1071 int i, size = get_mode_size_bytes(get_tarval_mode(tv));
1074 /* beware: ARM fpa uses bigendian format */
1075 for (i = ((size + 3) & ~3) - 4; i >= 0; i -= 4) {
1077 v = get_tarval_sub_bits(tv, i+3);
1078 v = (v << 8) | get_tarval_sub_bits(tv, i+2);
1079 v = (v << 8) | get_tarval_sub_bits(tv, i+1);
1080 v = (v << 8) | get_tarval_sub_bits(tv, i+0);
1081 be_emit_irprintf(emit_env.emit, "\t.word\t%u\n", v);
1082 be_emit_write_line(emit_env.emit);
1086 be_emit_char(emit_env.emit, '\n');
1087 be_emit_write_line(emit_env.emit);
1089 del_set(emit_env.sym_or_tv);