#include "sparc_new_nodes.h"
#include "gen_sparc_regalloc_if.h"
-
-#define SNPRINTF_BUF_LEN 128
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
/**
}
}
+void sparc_emit_float_load_store_mode(const ir_node *node)
+{
+ const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
+ ir_mode *mode = attr->load_store_mode;
+ int bits = get_mode_size_bits(mode);
+
+ assert(mode_is_float(mode));
+
+ switch (bits) {
+ case 32: return;
+ case 64: be_emit_char('d'); return;
+ case 128: be_emit_char('q'); return;
+ }
+ panic("invalid flaot load/store mode %+F", mode);
+}
/**
* Emit load mode char
} else if (bits == 8) {
be_emit_string(is_signed ? "sb" : "ub");
} else if (bits == 64) {
- be_emit_string("d");
+ be_emit_char('d');
} else {
assert(bits == 32);
}
} else if (bits == 8) {
be_emit_string("b");
} else if (bits == 64) {
- be_emit_string("d");
+ be_emit_char('d');
} else {
assert(bits == 32);
}
be_emit_string(is_signed ? "s" : "u");
}
-/**
- * emit FP load mode char
- */
-void sparc_emit_fp_load_mode(const ir_node *node)
+static void emit_fp_suffix(const ir_mode *mode)
{
- const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
- ir_mode *mode = attr->load_store_mode;
- int bits = get_mode_size_bits(mode);
-
+ unsigned bits = get_mode_size_bits(mode);
assert(mode_is_float(mode));
if (bits == 32) {
- be_emit_string("f");
+ be_emit_char('s');
} else if (bits == 64) {
- be_emit_string("df");
+ be_emit_char('d');
+ } else if (bits == 128) {
+ be_emit_char('q');
} else {
- panic("FP load mode > 64bits not implemented yet");
+ panic("invalid FP mode");
}
}
-/**
- * emit FP store mode char
- */
-void sparc_emit_fp_store_mode(const ir_node *node)
+void sparc_emit_fp_conv_source(const ir_node *node)
{
- const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
- ir_mode *mode = attr->load_store_mode;
- int bits = get_mode_size_bits(mode);
-
- assert(mode_is_float(mode));
+ const sparc_fp_conv_attr_t *attr = get_sparc_fp_conv_attr_const(node);
+ emit_fp_suffix(attr->src_mode);
+}
- if (bits == 32) {
- be_emit_string("f");
- } else if (bits == 64) {
- be_emit_string("df");
- } else {
- panic("FP store mode > 64bits not implemented yet");
- }
+void sparc_emit_fp_conv_destination(const ir_node *node)
+{
+ const sparc_fp_conv_attr_t *attr = get_sparc_fp_conv_attr_const(node);
+ emit_fp_suffix(attr->dest_mode);
}
/**
*/
void sparc_emit_fp_mode_suffix(const ir_node *node)
{
- ir_mode *mode = get_irn_mode(node);
- int bits = get_mode_size_bits(mode);
-
- assert(mode_is_float(mode));
-
- if (bits == 32) {
- be_emit_string("s");
- } else if (bits == 64) {
- be_emit_string("d");
- } else {
- panic("FP mode > 64bits not implemented yet");
- }
+ const sparc_fp_attr_t *attr = get_sparc_fp_attr_const(node);
+ emit_fp_suffix(attr->fp_mode);
}
/**
}
/**
- * emit code for div with the correct sign prefix
+ * emits code for mulh
*/
-static void emit_sparc_Div(const ir_node *irn)
+static void emit_sparc_Mulh(const ir_node *irn)
{
be_emit_cstring("\t");
sparc_emit_mode_sign_prefix(irn);
- be_emit_cstring("div ");
+ be_emit_cstring("mul ");
sparc_emit_source_register(irn, 0);
be_emit_cstring(", ");
be_emit_cstring(", ");
sparc_emit_dest_register(irn, 0);
be_emit_finish_line_gas(irn);
-}
-
-/**
- * emit code for mul with the correct sign prefix
- */
-static void emit_sparc_Mul(const ir_node *irn)
-{
- be_emit_cstring("\t");
- sparc_emit_mode_sign_prefix(irn);
- be_emit_cstring("mul ");
- sparc_emit_source_register(irn, 0);
- be_emit_cstring(", ");
- sparc_emit_reg_or_imm(irn, 1);
- be_emit_cstring(", ");
+ // our result is in the y register now
+ // we just copy it to the assigned target reg
+ be_emit_cstring("\tmov %y, ");
sparc_emit_dest_register(irn, 0);
be_emit_finish_line_gas(irn);
}
-/**
- * emits code for mulh
- */
-static void emit_sparc_Mulh(const ir_node *irn)
+static void emit_sparc_Div(const ir_node *node, bool is_signed)
{
- be_emit_cstring("\t");
- sparc_emit_mode_sign_prefix(irn);
- be_emit_cstring("mul ");
+ /* can we get the delay count of the wr instruction somewhere? */
+ unsigned wry_delay_count = 3;
+ unsigned i;
- sparc_emit_source_register(irn, 0);
+ be_emit_cstring("\twr ");
+ sparc_emit_source_register(node, 0);
+ be_emit_cstring(", 0, %y");
+ be_emit_finish_line_gas(node);
+
+ for (i = 0; i < wry_delay_count; ++i) {
+ be_emit_cstring("\tnop");
+ be_emit_finish_line_gas(node);
+ }
+
+ be_emit_irprintf("\t%s ", is_signed ? "sdiv" : "udiv");
+ sparc_emit_source_register(node, 1);
be_emit_cstring(", ");
- sparc_emit_reg_or_imm(irn, 1);
+ sparc_emit_source_register(node, 2);
be_emit_cstring(", ");
- sparc_emit_dest_register(irn, 0);
- be_emit_finish_line_gas(irn);
+ sparc_emit_dest_register(node, 0);
+ be_emit_finish_line_gas(node);
+}
- // our result is in the y register now
- // we just copy it to the assigned target reg
- be_emit_cstring("\tmov ");
- be_emit_char('%');
- be_emit_string(arch_register_get_name(&sparc_flags_regs[REG_Y]));
- be_emit_cstring(", ");
- sparc_emit_dest_register(irn, 0);
- be_emit_finish_line_gas(irn);
+static void emit_sparc_SDiv(const ir_node *node)
+{
+ (void) node;
+ /* aehm we would need an aditional register for an sra instruction to
+ * compute the upper bits... Just panic for now */
+ //emit_sparc_Div(node, true);
+ panic("signed div is wrong");
+}
+
+static void emit_sparc_UDiv(const ir_node *node)
+{
+ emit_sparc_Div(node, false);
}
/**
/**
* Emits code for Call node
*/
-static void emit_be_Call(const ir_node *irn)
+static void emit_sparc_Call(const ir_node *node)
{
- ir_entity *entity = be_Call_get_entity(irn);
+ const sparc_attr_t *attr = get_sparc_attr_const(node);
+ ir_entity *entity = attr->immediate_value_entity;
+ be_emit_cstring("\tcall ");
if (entity != NULL) {
- be_emit_cstring("\tcall ");
sparc_emit_entity(entity);
be_emit_cstring(", 0");
- be_emit_finish_line_gas(irn);
- be_emit_cstring("\tnop");
- be_emit_pad_comment();
- be_emit_cstring("/* TODO: use delay slot */\n");
} else {
- be_emit_cstring("\tnop\n");
- be_emit_pad_comment();
- be_emit_cstring("/* TODO: Entity == NULL */\n");
- be_emit_finish_line_gas(irn);
+ int last = get_irn_arity(node);
+ sparc_emit_source_register(node, last-1);
}
+ be_emit_finish_line_gas(node);
+
+ /* fill delay slot */
+ be_emit_cstring("\tnop");
+ be_emit_finish_line_gas(node);
}
/**
int i;
int memperm_arity;
int sp_change = 0;
+ ir_graph *irg = get_irn_irg(node);
+ be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
+
+ /* this implementation only works with frame pointers currently */
+ assert(layout->sp_relative == false);
/* TODO: this implementation is slower than necessary.
The longterm goal is however to avoid the memperm node completely */
if (memperm_arity > 8)
panic("memperm with more than 8 inputs not supported yet");
+ be_emit_irprintf("\tsub %%sp, %d, %%sp", memperm_arity*4);
+ be_emit_finish_line_gas(node);
+
for (i = 0; i < memperm_arity; ++i) {
- int offset;
ir_entity *entity = be_get_MemPerm_in_entity(node, i);
+ int offset = be_get_stack_entity_offset(layout, entity, 0);
/* spill register */
- sp_change += 4;
- be_emit_irprintf("\tst %%l%d, [%%sp-%d]", i, sp_change);
+ be_emit_irprintf("\tst %%l%d, [%%sp%+d]", i, sp_change + SPARC_MIN_STACKSIZE);
be_emit_finish_line_gas(node);
/* load from entity */
- offset = get_entity_offset(entity) + sp_change;
- be_emit_irprintf("\tld [%%sp+%d], %%l%d", offset, i);
+ be_emit_irprintf("\tld [%%fp%+d], %%l%d", offset, i);
be_emit_finish_line_gas(node);
+ sp_change += 4;
}
for (i = memperm_arity-1; i >= 0; --i) {
- int offset;
ir_entity *entity = be_get_MemPerm_out_entity(node, i);
+ int offset = be_get_stack_entity_offset(layout, entity, 0);
+
+ sp_change -= 4;
/* store to new entity */
- offset = get_entity_offset(entity) + sp_change;
- be_emit_irprintf("\tst %%l%d, [%%sp+%d]", i, offset);
+ be_emit_irprintf("\tst %%l%d, [%%fp%+d]", i, offset);
be_emit_finish_line_gas(node);
/* restore register */
- be_emit_irprintf("\tld [%%sp-%d], %%l%d", sp_change, i);
- sp_change -= 4;
+ be_emit_irprintf("\tld [%%sp%+d], %%l%d", sp_change + SPARC_MIN_STACKSIZE, i);
be_emit_finish_line_gas(node);
}
+
+ be_emit_irprintf("\tadd %%sp, %d, %%sp", memperm_arity*4);
+ be_emit_finish_line_gas(node);
+
assert(sp_change == 0);
}
be_emit_finish_line_gas(irn);
}
+static const char *get_icc_unsigned(pn_Cmp pnc)
+{
+ switch (pnc) {
+ case pn_Cmp_False: return "bn";
+ case pn_Cmp_Eq: return "be";
+ case pn_Cmp_Lt: return "blu";
+ case pn_Cmp_Le: return "bleu";
+ case pn_Cmp_Gt: return "bgu";
+ case pn_Cmp_Ge: return "bgeu";
+ case pn_Cmp_Lg: return "bne";
+ case pn_Cmp_Leg: return "ba";
+ default: panic("Cmp has unsupported pnc");
+ }
+}
+
+static const char *get_icc_signed(pn_Cmp pnc)
+{
+ switch (pnc) {
+ case pn_Cmp_False: return "bn";
+ case pn_Cmp_Eq: return "be";
+ case pn_Cmp_Lt: return "bl";
+ case pn_Cmp_Le: return "ble";
+ case pn_Cmp_Gt: return "bg";
+ case pn_Cmp_Ge: return "bge";
+ case pn_Cmp_Lg: return "bne";
+ case pn_Cmp_Leg: return "ba";
+ default: panic("Cmp has unsupported pnc");
+ }
+}
+
+static const char *get_fcc(pn_Cmp pnc)
+{
+ switch (pnc) {
+ case pn_Cmp_False: return "fbn";
+ case pn_Cmp_Eq: return "fbe";
+ case pn_Cmp_Lt: return "fbl";
+ case pn_Cmp_Le: return "fble";
+ case pn_Cmp_Gt: return "fbg";
+ case pn_Cmp_Ge: return "fbge";
+ case pn_Cmp_Lg: return "fblg";
+ case pn_Cmp_Leg: return "fbo";
+ case pn_Cmp_Uo: return "fbu";
+ case pn_Cmp_Ue: return "fbue";
+ case pn_Cmp_Ul: return "fbul";
+ case pn_Cmp_Ule: return "fbule";
+ case pn_Cmp_Ug: return "fbug";
+ case pn_Cmp_Uge: return "fbuge";
+ case pn_Cmp_Ne: return "fbne";
+ case pn_Cmp_True: return "fba";
+ case pn_Cmp_max:
+ break;
+ }
+ panic("invalid pnc");
+}
+
+typedef const char* (*get_cc_func)(pn_Cmp pnc);
/**
* Emits code for Branch
*/
-static void emit_sparc_BXX(const ir_node *irn)
+static void emit_sparc_branch(const ir_node *node, get_cc_func get_cc)
{
+ const sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr_const(node);
+ pn_Cmp pnc = attr->pnc;
+ const ir_node *proj_true = NULL;
+ const ir_node *proj_false = NULL;
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;
- ir_node *op1 = get_irn_n(irn, 0);
- const char *suffix;
- int proj_num = get_sparc_jmp_cond_proj_num(irn);
- const sparc_cmp_attr_t *cmp_attr = get_irn_generic_attr_const(op1);
- // bool is_signed = !cmp_attr->is_unsigned;
-
- assert(is_sparc_Cmp(op1) || is_sparc_Tst(op1));
-
- foreach_out_edge(irn, edge) {
+ const ir_node *block;
+ const ir_node *next_block;
+
+ foreach_out_edge(node, edge) {
ir_node *proj = get_edge_src_irn(edge);
long nr = get_Proj_proj(proj);
if (nr == pn_Cond_true) {
}
}
- if (cmp_attr->ins_permuted) {
- proj_num = get_mirrored_pnc(proj_num);
- }
-
/* for now, the code works for scheduled and non-schedules blocks */
- block = get_nodes_block(irn);
+ block = get_nodes_block(node);
/* we have a block schedule */
next_block = get_irn_link(block);
- assert(proj_num != pn_Cmp_False);
- assert(proj_num != pn_Cmp_True);
-
if (get_irn_link(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 = "e"; break;
- case pn_Cmp_Lt: suffix = "l"; break;
- case pn_Cmp_Le: suffix = "le"; break;
- case pn_Cmp_Gt: suffix = "g"; break;
- case pn_Cmp_Ge: suffix = "ge"; break;
- case pn_Cmp_Lg: suffix = "ne"; break;
- case pn_Cmp_Leg: suffix = "a"; break;
- default: panic("Cmp has unsupported pnc");
+ if (is_sparc_fbfcc(node)) {
+ pnc = get_negated_pnc(pnc, mode_F);
+ } else {
+ pnc = get_negated_pnc(pnc, mode_Iu);
+ }
}
/* emit the true proj */
- be_emit_irprintf("\tb%s ", suffix);
+ be_emit_cstring("\t");
+ be_emit_string(get_cc(pnc));
+ be_emit_char(' ');
sparc_emit_cfop_target(proj_true);
be_emit_finish_line_gas(proj_true);
be_emit_cstring("/* TODO: use delay slot */\n");
if (get_irn_link(proj_false) == next_block) {
- be_emit_cstring("\t/* false-fallthrough to ");
+ be_emit_cstring("\t/* fallthrough to ");
sparc_emit_cfop_target(proj_false);
be_emit_cstring(" */");
be_emit_finish_line_gas(proj_false);
}
}
+static void emit_sparc_Bicc(const ir_node *node)
+{
+ const sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr_const(node);
+ bool is_unsigned = attr->is_unsigned;
+ emit_sparc_branch(node, is_unsigned ? get_icc_unsigned : get_icc_signed);
+}
+
+static void emit_sparc_fbfcc(const ir_node *node)
+{
+ emit_sparc_branch(node, get_fcc);
+}
+
/**
* emit Jmp (which actually is a branch always (ba) instruction)
*/
be_emit_finish_line_gas(node);
}
+static void emit_fmov(const ir_node *node, const arch_register_t *src_reg,
+ const arch_register_t *dst_reg)
+{
+ be_emit_cstring("\tfmov ");
+ be_emit_string(arch_register_get_name(src_reg));
+ be_emit_cstring(", ");
+ be_emit_string(arch_register_get_name(dst_reg));
+ be_emit_finish_line_gas(node);
+}
+
+static const arch_register_t *get_next_fp_reg(const arch_register_t *reg)
+{
+ unsigned index = reg->index;
+ assert(reg == &sparc_fp_regs[index]);
+ index++;
+ assert(index < N_sparc_fp_REGS);
+ return &sparc_fp_regs[index];
+}
+
/**
* emit copy node
*/
-static void emit_be_Copy(const ir_node *irn)
+static void emit_be_Copy(const ir_node *node)
{
- ir_mode *mode = get_irn_mode(irn);
+ ir_mode *mode = get_irn_mode(node);
+ const arch_register_t *src_reg = get_in_reg(node, 0);
+ const arch_register_t *dst_reg = get_out_reg(node, 0);
- if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
- /* omitted Copy */
+ if (src_reg == dst_reg)
return;
- }
if (mode_is_float(mode)) {
- panic("emit_be_Copy: move not supported for FP");
+ unsigned bits = get_mode_size_bits(mode);
+ int n = bits > 32 ? bits > 64 ? 3 : 1 : 0;
+ int i;
+ emit_fmov(node, src_reg, dst_reg);
+ for (i = 0; i < n; ++i) {
+ src_reg = get_next_fp_reg(src_reg);
+ dst_reg = get_next_fp_reg(dst_reg);
+ emit_fmov(node, src_reg, dst_reg);
+ }
} else if (mode_is_data(mode)) {
be_emit_cstring("\tmov ");
- sparc_emit_source_register(irn, 0);
+ sparc_emit_source_register(node, 0);
be_emit_cstring(", ");
- sparc_emit_dest_register(irn, 0);
- be_emit_finish_line_gas(irn);
+ sparc_emit_dest_register(node, 0);
+ be_emit_finish_line_gas(node);
} else {
- panic("emit_be_Copy: move not supported for this mode");
+ panic("emit_be_Copy: invalid mode");
}
}
(void) irn;
}
-
-
/**
* type of emitter function
*/
sparc_register_spec_emitters();
/* custom emitter */
- set_emitter(op_be_Call, emit_be_Call);
set_emitter(op_be_Copy, emit_be_Copy);
set_emitter(op_be_CopyKeep, emit_be_Copy);
set_emitter(op_be_IncSP, emit_be_IncSP);
set_emitter(op_be_MemPerm, emit_be_MemPerm);
set_emitter(op_be_Perm, emit_be_Perm);
set_emitter(op_be_Return, emit_be_Return);
- set_emitter(op_sparc_BXX, emit_sparc_BXX);
- set_emitter(op_sparc_Div, emit_sparc_Div);
+ set_emitter(op_sparc_Ba, emit_sparc_Ba);
+ set_emitter(op_sparc_Bicc, emit_sparc_Bicc);
+ set_emitter(op_sparc_Call, emit_sparc_Call);
+ set_emitter(op_sparc_fbfcc, emit_sparc_fbfcc);
set_emitter(op_sparc_FrameAddr, emit_sparc_FrameAddr);
set_emitter(op_sparc_HiImm, emit_sparc_HiImm);
- set_emitter(op_sparc_Ba, emit_sparc_Ba);
set_emitter(op_sparc_LoImm, emit_sparc_LoImm);
- set_emitter(op_sparc_Mul, emit_sparc_Mul);
set_emitter(op_sparc_Mulh, emit_sparc_Mulh);
set_emitter(op_sparc_Save, emit_sparc_Save);
+ set_emitter(op_sparc_SDiv, emit_sparc_SDiv);
set_emitter(op_sparc_SymConst, emit_sparc_SymConst);
+ set_emitter(op_sparc_UDiv, emit_sparc_UDiv);
/* no need to emit anything for the following nodes */
set_emitter(op_be_Barrier, emit_nothing);
*/
static void sparc_emit_node(const ir_node *node)
{
- ir_op *op = get_irn_op(node);
+ ir_op *op = get_irn_op(node);
if (op->ops.generic) {
emit_func func = (emit_func) op->ops.generic;
be_dbg_set_dbg_info(get_irn_dbg_info(node));
(*func) (node);
} else {
- panic("Error: No emit handler for node %+F (graph %+F)\n",
- node, current_ir_graph);
+ panic("No emit handler for node %+F (graph %+F)\n", node,
+ current_ir_graph);
}
}