#include "../beblocksched.h"
#include "../beirg_t.h"
#include "../begnuas.h"
+#include "../be_dbgout.h"
#include "arm_emitter.h"
+#include "arm_optimize.h"
#include "gen_arm_emitter.h"
#include "arm_nodes_attr.h"
#include "arm_new_nodes.h"
*/
void arm_emit_offset(const ir_node *node) {
int offset = 0;
- ir_op *irn_op = get_irn_op(node);
+ ir_opcode opc = get_irn_opcode(node);
- if (irn_op == op_be_Reload || irn_op == op_be_Spill) {
+ if (opc == beo_Reload || opc == beo_Spill) {
ir_entity *ent = be_get_frame_entity(node);
offset = get_entity_offset(ent);
- } else if (irn_op == op_be_IncSP) {
- offset = - be_get_IncSP_offset(node);
} else {
assert(!"unimplemented arm_emit_offset for this node type");
panic("unimplemented arm_emit_offset for this node type");
*/
static void arm_emit_fpa_postfix(const ir_mode *mode) {
int bits = get_mode_size_bits(mode);
+ char c = 'e';
+
if (bits == 32)
- be_emit_char('s');
+ c = 's';
else if (bits == 64)
- be_emit_char('d');
- else
- be_emit_char('e');
+ c = 'd';
+ be_emit_char(c);
}
/**
const arm_attr_t *attr = get_arm_attr_const(node);
if (ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM) {
- be_emit_irprintf("#0x%X", arm_decode_imm_w_shift(get_arm_value(node)));
+ be_emit_irprintf("#0x%X", arm_decode_imm_w_shift(get_arm_imm_value(node)));
} else if (ARM_GET_FPA_IMM(attr)) {
- be_emit_irprintf("#0x%F", get_arm_value(node));
+ be_emit_irprintf("#%s", arm_get_fpa_imm_name(get_arm_imm_value(node)));
} else if (is_arm_SymConst(node))
be_emit_ident(get_arm_symconst_id(node));
else {
mod = get_arm_shift_modifier(node);
if (ARM_HAS_SHIFT(mod)) {
- long v = get_tarval_long(get_arm_value(node));
+ int v = get_arm_imm_value(node);
- be_emit_irprintf(", %s #%l", arm_shf_mod_name(mod), v);
+ be_emit_irprintf(", %s #%d", arm_shf_mod_name(mod), v);
}
}
unsigned label;
ir_mode *mode;
- key.u.tv = get_arm_value(irn);
+ key.u.tv = get_fpaConst_value(irn);
key.is_ident = 0;
key.label = 0;
entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
*/
static void arm_emit_block_name(const ir_node *block) {
if (has_Block_label(block)) {
- be_emit_string(be_gas_label_prefix());
+ be_emit_string(be_gas_block_label_prefix());
be_emit_irprintf("%lu", get_Block_label(block));
} else {
be_emit_cstring(BLOCK_PREFIX);
}
}
+
+/**
+ * Emit a Tst with conditional branch.
+ */
+static void emit_arm_TstBra(const ir_node *irn)
+{
+ const ir_edge_t *edge;
+ const ir_node *proj_true = NULL;
+ const ir_node *proj_false = NULL;
+ const ir_node *block;
+ const ir_node *next_block;
+ const char *suffix;
+ int proj_num = get_arm_CondJmp_proj_num(irn);
+
+ foreach_out_edge(irn, edge) {
+ ir_node *proj = get_edge_src_irn(edge);
+ long nr = get_Proj_proj(proj);
+ if (nr == pn_Cond_true) {
+ proj_true = proj;
+ } else {
+ proj_false = proj;
+ }
+ }
+
+ /* for now, the code works for scheduled and non-schedules blocks */
+ block = get_nodes_block(irn);
+
+ /* we have a block schedule */
+ next_block = sched_next_block(block);
+
+ assert(proj_num != pn_Cmp_False);
+ assert(proj_num != pn_Cmp_True);
+
+ if (get_cfop_target_block(proj_true) == next_block) {
+ /* exchange both proj's so the second one can be omitted */
+ const ir_node *t = proj_true;
+
+ proj_true = proj_false;
+ proj_false = t;
+ proj_num = get_negated_pnc(proj_num, mode_Iu);
+ }
+ switch (proj_num) {
+ case pn_Cmp_Eq: suffix = "eq"; break;
+ case pn_Cmp_Lt: suffix = "lt"; break;
+ case pn_Cmp_Le: suffix = "le"; break;
+ case pn_Cmp_Gt: suffix = "gt"; break;
+ case pn_Cmp_Ge: suffix = "ge"; break;
+ case pn_Cmp_Lg: suffix = "ne"; break;
+ case pn_Cmp_Leg: suffix = "al"; break;
+ default: assert(!"Cmp unsupported"); suffix = "al";
+ }
+ be_emit_cstring("\ttst ");
+ arm_emit_source_register(irn, 0);
+ be_emit_cstring(", ");
+ arm_emit_source_register(irn, 1);
+ be_emit_finish_line_gas(irn);
+
+ /* emit the true proj */
+ be_emit_irprintf("\tb%s ", suffix);
+ arm_emit_cfop_target(proj_true);
+ be_emit_finish_line_gas(proj_true);
+
+ if (get_cfop_target_block(proj_false) == next_block) {
+ be_emit_cstring("\t/* fallthrough to ");
+ arm_emit_cfop_target(proj_false);
+ be_emit_cstring(" */");
+ be_emit_finish_line_gas(proj_false);
+ } else {
+ be_emit_cstring("b ");
+ arm_emit_cfop_target(proj_false);
+ be_emit_finish_line_gas(proj_false);
+ }
+}
+
/**
* Emit a Compare with conditional branch.
*/
* Create the CopyB instruction sequence.
*/
static void emit_arm_CopyB(const ir_node *irn) {
- unsigned int size = get_tarval_long(get_arm_value(irn));
+ unsigned size = (unsigned)get_arm_imm_value(irn);
const char *tgt = arch_register_get_name(get_in_reg(irn, 0));
const char *src = arch_register_get_name(get_in_reg(irn, 1));
be_emit_string(src);
be_emit_cstring(")->(");
arm_emit_source_register(irn, 0);
- be_emit_irprintf(" [%d bytes], Uses ", size);
+ be_emit_irprintf(" [%u bytes], Uses ", size);
be_emit_string(t0);
be_emit_cstring(", ");
be_emit_string(t1);
/** Emit an IncSP node */
static void emit_be_IncSP(const ir_node *irn) {
- int offs = be_get_IncSP_offset(irn);
+ int offs = -be_get_IncSP_offset(irn);
if (offs != 0) {
- be_emit_cstring("\tadd ");
+ if (offs < 0) {
+ be_emit_cstring("\tsub ");
+ offs = -offs;
+ } else {
+ be_emit_cstring("\tadd ");
+ }
arm_emit_dest_register(irn, 0);
be_emit_cstring(", ");
arm_emit_source_register(irn, 0);
- be_emit_cstring(", #");
- arm_emit_offset(irn);
+ be_emit_irprintf(", #0x%X", offs);
} else {
- be_emit_cstring("\t/* omitted IncSP(");
- arm_emit_offset(irn);
- be_emit_cstring(") */");
+ /* omitted IncSP(0) */
+ return;
}
be_emit_finish_line_gas(irn);
}
ir_mode *mode = get_irn_mode(irn);
if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
- be_emit_cstring("\t/* omitted Copy: ");
- arm_emit_source_register(irn, 0);
- be_emit_cstring(" -> ");
- arm_emit_dest_register(irn, 0);
- be_emit_finish_line_gas(irn);
+ /* omitted Copy */
return;
}
static void emit_arm_LdTls(const ir_node *irn) {
(void) irn;
- panic("TLS not supported for this target\n");
+ panic("TLS not supported for this target");
/* Er... our gcc does not support it... Install a newer toolchain. */
}
/* other emitter functions */
ARM_EMIT(CmpBra);
+ ARM_EMIT(TstBra);
ARM_EMIT(fpaCmfBra);
ARM_EMIT(fpaCmfeBra);
ARM_EMIT(CopyB);
#undef SILENCE
}
-static const char *last_name = NULL;
-static unsigned last_line = -1;
-static unsigned num = -1;
-
-/**
- * Emit the debug support for node node.
- */
-static void arm_emit_dbg(const ir_node *irn) {
- dbg_info *db = get_irn_dbg_info(irn);
- unsigned lineno;
- const char *fname = ir_retrieve_dbg_info(db, &lineno);
-
- if (! cg->birg->main_env->options->stabs_debug_support)
- return;
-
- if (fname) {
- if (last_name != fname) {
- last_line = -1;
- be_dbg_include_begin(cg->birg->main_env->db_handle, fname);
- last_name = fname;
- }
- if (last_line != lineno) {
- char name[64];
-
- snprintf(name, sizeof(name), ".LM%u", ++num);
- last_line = lineno;
- be_dbg_line(cg->birg->main_env->db_handle, lineno, name);
- be_emit_string(name);
- be_emit_cstring(":\n");
- be_emit_write_line();
- }
- }
-}
-
/**
* Emits code for a node.
*/
if (op->ops.generic) {
emit_func *emit = (emit_func *)op->ops.generic;
- arm_emit_dbg(irn);
+ be_dbg_set_dbg_info(get_irn_dbg_info(irn));
(*emit)(irn);
} else {
be_emit_cstring("\t/* TODO */");
ir_node *irn;
arm_emit_block_header(block, prev_block);
- arm_emit_dbg(block);
+ be_dbg_set_dbg_info(get_irn_dbg_info(block));
sched_foreach(block, irn) {
arm_emit_node(irn);
}
* Main driver. Emits the code for one routine.
*/
void arm_gen_routine(const arm_code_gen_t *arm_cg, ir_graph *irg) {
- ir_node **blk_sched;
- int i, n;
- ir_node *last_block = NULL;
+ ir_node **blk_sched;
+ int i, n;
+ ir_node *last_block = NULL;
+ ir_entity *entity = get_irg_entity(irg);
cg = arm_cg;
+ isa = (const arm_isa_t *)cg->arch_env;
arch_env = cg->arch_env;
sym_or_tv = new_set(cmp_sym_or_tv, 8);
-
arm_register_emitters();
+ be_dbg_method_begin(entity, be_abi_get_stack_layout(cg->birg->abi));
+
/* create the block schedule. For now, we don't need it earlier. */
blk_sched = be_create_block_schedule(cg->irg, cg->birg->exec_freq);
last_block = block;
}
+ be_dbg_method_end();
+
/* emit SymConst values */
if (set_count(sym_or_tv) > 0) {
sym_or_tv_t *entry;