*/
#define SILENCER
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <limits.h>
#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"
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
-static const arch_env_t *arch_env = NULL;
static const arm_code_gen_t *cg;
-static const arm_isa_t *isa;
static set *sym_or_tv;
/**
in register we need. */
op = get_irn_n(irn, pos);
- reg = arch_get_irn_register(arch_env, op);
+ reg = arch_get_irn_register(op);
assert(reg && "no in register found");
/* in case of a joker register: just return a valid register */
if (arch_register_type_is(reg, joker)) {
- const arch_register_req_t *req;
-
- /* ask for the requirements */
- req = arch_get_register_req(arch_env, irn, pos);
+ const arch_register_req_t *req = arch_get_register_req(irn, pos);
if (arch_register_req_is(req, limited)) {
/* in case of limited requirements: get the first allowed register */
/* Proj with the corresponding projnum for the register */
if (get_irn_mode(node) != mode_T) {
- reg = arch_get_irn_register(arch_env, node);
+ reg = arch_get_irn_register(node);
} else if (is_arm_irn(node)) {
reg = get_arm_out_reg(node, pos);
} else {
proj = get_edge_src_irn(edge);
assert(is_Proj(proj) && "non-Proj from mode_T node");
if (get_Proj_proj(proj) == pos) {
- reg = arch_get_irn_register(arch_env, proj);
+ reg = arch_get_irn_register(proj);
break;
}
}
*/
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);
}
/**
mod = get_arm_shift_modifier(node);
if (ARM_HAS_SHIFT(mod)) {
- long v = get_arm_imm_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);
}
}
*/
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.
*/
block_nr = get_irn_node_nr(irn);
n_projs = get_arm_SwitchJmp_n_projs(irn);
- projs = xcalloc(n_projs , sizeof(ir_node*));
+ projs = XMALLOCNZ(ir_node*, n_projs);
foreach_out_edge(irn, edge) {
proj = get_edge_src_irn(edge);
/** 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;
}
if (mode_is_float(mode)) {
- if (USE_FPA(isa)) {
+ if (USE_FPA(cg->isa)) {
be_emit_cstring("\tmvf");
arm_emit_mode(irn);
be_emit_char(' ');
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. */
}
/**
* Set a node emitter. Make it a bit more type safe.
*/
-static INLINE void set_emitter(ir_op *op, emit_func arm_emit_node) {
+static inline void set_emitter(ir_op *op, emit_func arm_emit_node) {
op->ops.generic = (op_func)arm_emit_node;
}
/* 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;
- 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;