Commit e50e95fb authored by Matthias Braun's avatar Matthias Braun
Browse files

sparc: preliminary SwitchJmp implementation

[r27957]
parent a24d3e41
......@@ -131,8 +131,6 @@ static const arch_irn_ops_t sparc_irn_ops = {
NULL, /* perform_memory_operand */
};
/**
* Transforms the standard firm graph into
* a SPARC firm graph
......
......@@ -322,12 +322,17 @@ void sparc_emit_fp_mode_suffix(const ir_node *node)
emit_fp_suffix(attr->fp_mode);
}
static ir_node *get_jump_target(const ir_node *jump)
{
return get_irn_link(jump);
}
/**
* Returns the target label for a control flow node.
*/
static void sparc_emit_cfop_target(const ir_node *node)
{
ir_node *block = get_irn_link(node);
ir_node *block = get_jump_target(node);
be_gas_emit_block_name(block);
}
......@@ -400,6 +405,12 @@ static void emit_sparc_Mulh(const ir_node *irn)
be_emit_finish_line_gas(irn);
}
static void fill_delay_slot(void)
{
be_emit_cstring("\tnop\n");
be_emit_write_line();
}
static void emit_sparc_Div(const ir_node *node, bool is_signed)
{
/* can we get the delay count of the wr instruction somewhere? */
......@@ -412,8 +423,7 @@ static void emit_sparc_Div(const ir_node *node, bool is_signed)
be_emit_finish_line_gas(node);
for (i = 0; i < wry_delay_count; ++i) {
be_emit_cstring("\tnop");
be_emit_finish_line_gas(node);
fill_delay_slot();
}
be_emit_irprintf("\t%s ", is_signed ? "sdiv" : "udiv");
......@@ -468,9 +478,7 @@ static void emit_sparc_Call(const ir_node *node)
}
be_emit_finish_line_gas(node);
/* fill delay slot */
be_emit_cstring("\tnop");
be_emit_finish_line_gas(node);
fill_delay_slot();
}
/**
......@@ -693,9 +701,7 @@ static void emit_sparc_branch(const ir_node *node, get_cc_func get_cc)
sparc_emit_cfop_target(proj_true);
be_emit_finish_line_gas(proj_true);
be_emit_cstring("\tnop");
be_emit_pad_comment();
be_emit_cstring("/* TODO: use delay slot */\n");
fill_delay_slot();
if (get_irn_link(proj_false) == next_block) {
be_emit_cstring("\t/* fallthrough to ");
......@@ -706,8 +712,7 @@ static void emit_sparc_branch(const ir_node *node, get_cc_func get_cc)
be_emit_cstring("\tba ");
sparc_emit_cfop_target(proj_false);
be_emit_finish_line_gas(proj_false);
be_emit_cstring("\tnop\t\t/* TODO: use delay slot */\n");
be_emit_finish_line_gas(proj_false);
fill_delay_slot();
}
}
......@@ -739,7 +744,7 @@ static void emit_sparc_Ba(const ir_node *node)
be_emit_cstring("\tba ");
sparc_emit_cfop_target(node);
be_emit_finish_line_gas(node);
be_emit_cstring("\tnop\t\t/* TODO: use delay slot */\n");
fill_delay_slot();
} else {
be_emit_cstring("\t/* fallthrough to ");
sparc_emit_cfop_target(node);
......@@ -748,6 +753,75 @@ static void emit_sparc_Ba(const ir_node *node)
be_emit_finish_line_gas(node);
}
static void emit_jump_table(const ir_node *node)
{
const sparc_switch_jmp_attr_t *attr = get_sparc_switch_jmp_attr_const(node);
long switch_min = LONG_MAX;
long switch_max = LONG_MIN;
long default_pn = attr->default_proj_num;
ir_entity *entity = attr->jump_table;
ir_node *default_block = NULL;
unsigned length;
const ir_edge_t *edge;
unsigned i;
ir_node **table;
/* go over all proj's and collect them */
foreach_out_edge(node, edge) {
ir_node *proj = get_edge_src_irn(edge);
long pn = get_Proj_proj(proj);
/* check for default proj */
if (pn == default_pn) {
assert(default_block == NULL); /* more than 1 default_pn? */
default_block = get_jump_target(proj);
} else {
switch_min = pn < switch_min ? pn : switch_min;
switch_max = pn > switch_max ? pn : switch_max;
}
}
length = (unsigned long) (switch_max - switch_min) + 1;
assert(switch_min < LONG_MAX || switch_max > LONG_MIN);
table = XMALLOCNZ(ir_node*, length);
foreach_out_edge(node, edge) {
ir_node *proj = get_edge_src_irn(edge);
long pn = get_Proj_proj(proj);
if (pn == default_pn)
continue;
table[pn - switch_min] = get_jump_target(proj);
}
/* emit table */
be_gas_emit_switch_section(GAS_SECTION_RODATA);
be_emit_cstring("\t.align 4\n");
be_gas_emit_entity(entity);
be_emit_cstring(":\n");
for (i = 0; i < length; ++i) {
ir_node *block = table[i];
if (block == NULL)
block = default_block;
be_emit_cstring("\t.long ");
be_gas_emit_block_name(block);
be_emit_char('\n');
be_emit_write_line();
}
be_gas_emit_switch_section(GAS_SECTION_TEXT);
xfree(table);
}
static void emit_sparc_SwitchJmp(const ir_node *node)
{
be_emit_cstring("\tjmp ");
sparc_emit_source_register(node, 0);
be_emit_finish_line_gas(node);
fill_delay_slot();
emit_jump_table(node);
}
static void emit_fmov(const ir_node *node, const arch_register_t *src_reg,
const arch_register_t *dst_reg)
{
......@@ -848,6 +922,7 @@ static void sparc_register_emitters(void)
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_SwitchJmp, emit_sparc_SwitchJmp);
set_emitter(op_sparc_UDiv, emit_sparc_UDiv);
/* no need to emit anything for the following nodes */
......
......@@ -55,7 +55,7 @@ static bool has_jmp_cond_attr(const ir_node *node)
return is_sparc_Bicc(node) || is_sparc_fbfcc(node);
}
static bool has_jmp_switch_attr(const ir_node *node)
static bool has_switch_jmp_attr(const ir_node *node)
{
return is_sparc_SwitchJmp(node);
}
......@@ -121,10 +121,9 @@ static void sparc_dump_node(FILE *F, ir_node *n, dump_reason_t reason)
fprintf(F, "pnc: %d (%s)\n", attr->pnc, get_pnc_string(attr->pnc));
fprintf(F, "unsigned: %s\n", attr->is_unsigned ? "true" : "false");
}
if (has_jmp_switch_attr(n)) {
const sparc_jmp_switch_attr_t *attr
= get_sparc_jmp_switch_attr_const(n);
fprintf(F, "n projs: %d\n", attr->n_projs);
if (has_switch_jmp_attr(n)) {
const sparc_switch_jmp_attr_t *attr
= get_sparc_switch_jmp_attr_const(n);
fprintf(F, "default proj: %ld\n", attr->default_proj_num);
}
if (has_fp_attr(n)) {
......@@ -158,32 +157,6 @@ static void init_sparc_jmp_cond_attr(ir_node *node, int pnc, bool is_unsigned)
attr->is_unsigned = is_unsigned;
}
void set_sparc_jmp_switch_n_projs(ir_node *node, int n_projs)
{
sparc_jmp_switch_attr_t *attr = get_sparc_jmp_switch_attr(node);
attr->n_projs = n_projs;
}
void set_sparc_jmp_switch_default_proj_num(ir_node *node, long def_proj_num)
{
sparc_jmp_switch_attr_t *attr = get_sparc_jmp_switch_attr(node);
attr->default_proj_num = def_proj_num;
}
int get_sparc_jmp_switch_n_projs(const ir_node *node)
{
const sparc_jmp_switch_attr_t *attr = get_sparc_jmp_switch_attr_const(node);
return attr->n_projs;
}
long get_sparc_jmp_switch_default_proj_num(const ir_node *node)
{
const sparc_jmp_switch_attr_t *attr = get_sparc_jmp_switch_attr_const(node);
return attr->default_proj_num;
}
sparc_attr_t *get_sparc_attr(ir_node *node)
{
assert(is_sparc_irn(node));
......@@ -220,16 +193,16 @@ const sparc_jmp_cond_attr_t *get_sparc_jmp_cond_attr_const(const ir_node *node)
return (const sparc_jmp_cond_attr_t*) get_irn_generic_attr_const(node);
}
sparc_jmp_switch_attr_t *get_sparc_jmp_switch_attr(ir_node *node)
sparc_switch_jmp_attr_t *get_sparc_switch_jmp_attr(ir_node *node)
{
assert(has_jmp_switch_attr(node));
return (sparc_jmp_switch_attr_t*) get_irn_generic_attr_const(node);
assert(has_switch_jmp_attr(node));
return (sparc_switch_jmp_attr_t*) get_irn_generic_attr_const(node);
}
const sparc_jmp_switch_attr_t *get_sparc_jmp_switch_attr_const(const ir_node *node)
const sparc_switch_jmp_attr_t *get_sparc_switch_jmp_attr_const(const ir_node *node)
{
assert(has_jmp_switch_attr(node));
return (const sparc_jmp_switch_attr_t*) get_irn_generic_attr_const(node);
assert(has_switch_jmp_attr(node));
return (const sparc_switch_jmp_attr_t*) get_irn_generic_attr_const(node);
}
sparc_save_attr_t *get_sparc_save_attr(ir_node *node)
......@@ -356,6 +329,14 @@ static void init_sparc_fp_conv_attributes(ir_node *res, ir_mode *src_mode,
attr->dest_mode = dest_mode;
}
static void init_sparc_switch_jmp_attributes(ir_node *res, long default_pn,
ir_entity *jump_table)
{
sparc_switch_jmp_attr_t *attr = get_sparc_switch_jmp_attr(res);
attr->default_proj_num = default_pn;
attr->jump_table = jump_table;
}
/**
* copies sparc attributes of node
*/
......@@ -411,16 +392,15 @@ static int cmp_attr_sparc_jmp_cond(ir_node *a, ir_node *b)
|| attr_a->is_unsigned != attr_b->is_unsigned;
}
static int cmp_attr_sparc_jmp_switch(ir_node *a, ir_node *b)
static int cmp_attr_sparc_switch_jmp(ir_node *a, ir_node *b)
{
const sparc_jmp_switch_attr_t *attr_a = get_sparc_jmp_switch_attr_const(a);
const sparc_jmp_switch_attr_t *attr_b = get_sparc_jmp_switch_attr_const(b);
const sparc_switch_jmp_attr_t *attr_a = get_sparc_switch_jmp_attr_const(a);
const sparc_switch_jmp_attr_t *attr_b = get_sparc_switch_jmp_attr_const(b);
if (cmp_attr_sparc(a, b))
return 1;
return attr_a->default_proj_num != attr_b->default_proj_num
|| attr_a->n_projs != attr_b->n_projs;
return attr_a->default_proj_num != attr_b->default_proj_num;
}
static int cmp_attr_sparc_save(ir_node *a, ir_node *b)
......
......@@ -41,8 +41,8 @@ const sparc_load_store_attr_t *get_sparc_load_store_attr_const(const ir_node *no
sparc_jmp_cond_attr_t *get_sparc_jmp_cond_attr(ir_node *node);
const sparc_jmp_cond_attr_t *get_sparc_jmp_cond_attr_const(const ir_node *node);
sparc_jmp_switch_attr_t *get_sparc_jmp_switch_attr(ir_node *node);
const sparc_jmp_switch_attr_t *get_sparc_jmp_switch_attr_const(const ir_node *node);
sparc_switch_jmp_attr_t *get_sparc_switch_jmp_attr(ir_node *node);
const sparc_switch_jmp_attr_t *get_sparc_switch_jmp_attr_const(const ir_node *node);
sparc_save_attr_t *get_sparc_save_attr(ir_node *node);
const sparc_save_attr_t *get_sparc_save_attr_const(const ir_node *node);
......@@ -70,26 +70,6 @@ const arch_register_req_t *get_sparc_in_req(const ir_node *node, int pos);
*/
void set_sparc_req_in(ir_node *node, const arch_register_req_t *req, int pos);
/**
* Returns the number of projs of a SwitchJmp.
*/
int get_sparc_jmp_switch_n_projs(const ir_node *node);
/**
* Sets the number of projs of a SwitchJmp.
*/
void set_sparc_jmp_switch_n_projs(ir_node *node, int n_projs);
/**
* Returns the default_proj_num.
*/
long get_sparc_jmp_switch_default_proj_num(const ir_node *node);
/**
* Sets the default_proj_num.
*/
void set_sparc_jmp_switch_default_proj_num(ir_node *node, long default_proj_num);
/* Include the generated headers */
#include "gen_sparc_new_nodes.h"
......
......@@ -96,11 +96,11 @@ struct sparc_jmp_cond_attr_t {
/**
* attributes for switch jumps
*/
typedef struct sparc_jmp_switch_attr_t sparc_jmp_switch_attr_t;
struct sparc_jmp_switch_attr_t {
typedef struct sparc_switch_jmp_attr_t sparc_switch_jmp_attr_t;
struct sparc_switch_jmp_attr_t {
sparc_attr_t base; /**< generic attribute */
int n_projs;
long default_proj_num;
ir_entity *jump_table;
};
#endif
......@@ -149,7 +149,8 @@ $default_copy_attr = "sparc_copy_attr";
sparc_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
sparc_load_store_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
sparc_jmp_cond_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
sparc_jmp_switch_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
sparc_switch_jmp_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n".
"\tinit_sparc_switch_jmp_attributes(res, default_pn, jump_table);\n",
sparc_save_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
sparc_fp_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n".
"\tinit_sparc_fp_attributes(res, fp_mode);\n",
......@@ -161,7 +162,7 @@ $default_copy_attr = "sparc_copy_attr";
sparc_attr_t => "cmp_attr_sparc",
sparc_load_store_attr_t => "cmp_attr_sparc_load_store",
sparc_jmp_cond_attr_t => "cmp_attr_sparc_jmp_cond",
sparc_jmp_switch_attr_t => "cmp_attr_sparc_jmp_switch",
sparc_switch_jmp_attr_t => "cmp_attr_sparc_switch_jmp",
sparc_save_attr_t => "cmp_attr_sparc_save",
sparc_fp_attr_t => "cmp_attr_sparc_fp",
sparc_fp_conv_attr_t => "cmp_attr_sparc_fp_conv",
......@@ -188,17 +189,6 @@ my %cmp_operand_constructors = (
},
);
my %unop_operand_constructors = (
imm => {
attr => "ir_entity *immediate_entity, int32_t immediate_value",
custominit => "sparc_set_attr_imm(res, immediate_entity, immediate_value);",
reg_req => { in => [], out => [ "gp" ] },
},
reg => {
reg_req => { in => [ "gp" ], out => [ "gp" ] },
},
);
my %binop_operand_constructors = (
imm => {
attr => "ir_entity *immediate_entity, int32_t immediate_value",
......@@ -429,15 +419,13 @@ Tst => {
},
SwitchJmp => {
op_flags => [ "labeled", "cfopcode", "forking" ],
irn_flags => [ "modifies_flags" ],
state => "pinned",
mode => "mode_T",
attr => "int n_projs, long def_proj_num",
init_attr => "\tset_sparc_jmp_switch_n_projs(res, n_projs);\n".
"\tset_sparc_jmp_switch_default_proj_num(res, def_proj_num);",
reg_req => { in => [ "gp" ], out => [ "none" ] },
attr_type => "sparc_jmp_switch_attr_t",
op_flags => [ "labeled", "cfopcode", "forking" ],
state => "pinned",
mode => "mode_T",
reg_req => { in => [ "gp" ], out => [ ] },
attr_type => "sparc_switch_jmp_attr_t",
attr => "long default_pn, ir_entity *jump_table",
init_attr => "info->out_infos = NULL;", # XXX ugly hack for out requirements
},
Sll => {
......
......@@ -850,9 +850,71 @@ static ir_mode *get_cmp_mode(ir_node *b_value)
return get_irn_mode(op);
}
/**
* Transform Cond nodes
*/
static ir_node *make_address(dbg_info *dbgi, ir_node *block, ir_entity *entity,
int32_t offset)
{
ir_node *hi = new_bd_sparc_SetHi(dbgi, block, entity, offset);
ir_node *low = new_bd_sparc_Or_imm(dbgi, block, hi, entity, offset);
be_dep_on_frame(hi);
return low;
}
static ir_node *gen_SwitchJmp(ir_node *node)
{
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *block = be_transform_node(get_nodes_block(node));
ir_node *selector = get_Cond_selector(node);
ir_node *new_selector = be_transform_node(selector);
long switch_min = LONG_MAX;
long switch_max = LONG_MIN;
long default_pn = get_Cond_default_proj(node);
ir_entity *entity;
ir_node *table_address;
ir_node *index;
ir_node *load;
ir_node *address;
unsigned length;
const ir_edge_t *edge;
/* switch with smaller mode not implemented yet */
assert(get_mode_size_bits(get_irn_mode(selector)) == 32);
foreach_out_edge(node, edge) {
ir_node *proj = get_edge_src_irn(edge);
long pn = get_Proj_proj(proj);
if (pn == default_pn)
continue;
switch_min = pn<switch_min ? pn : switch_min;
switch_max = pn>switch_max ? pn : switch_max;
}
length = (unsigned long) (switch_max - switch_min);
if (length > 16000) {
panic("Size of switch %+F bigger than 16000", node);
}
entity = new_entity(NULL, id_unique("TBL%u"), get_unknown_type());
set_entity_visibility(entity, ir_visibility_private);
add_entity_linkage(entity, IR_LINKAGE_CONSTANT);
/* TODO: this code does not construct code to check for access
* out-of bounds of the jumptable yet. I think we should put this stuff
* into the switch_lowering phase to get some additional optimisations
* done. */
/* construct base address */
table_address = make_address(dbgi, block, entity,
-switch_min * get_mode_size_bytes(mode_gp));
/* scale index */
index = new_bd_sparc_Sll_imm(dbgi, block, new_selector, NULL, 2);
/* load from jumptable */
load = new_bd_sparc_Ld_reg(dbgi, block, table_address, index, new_NoMem(),
mode_gp);
address = new_r_Proj(load, mode_gp, pn_sparc_Ld_res);
return new_bd_sparc_SwitchJmp(dbgi, block, address, default_pn, entity);
}
static ir_node *gen_Cond(ir_node *node)
{
ir_node *selector = get_Cond_selector(node);
......@@ -866,7 +928,7 @@ static ir_node *gen_Cond(ir_node *node)
// switch/case jumps
if (mode != mode_b) {
panic("SwitchJump not implemented yet");
return gen_SwitchJmp(node);
}
// regular if/else jumps
......@@ -929,11 +991,7 @@ static ir_node *gen_SymConst(ir_node *node)
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *block = get_nodes_block(node);
ir_node *new_block = be_transform_node(block);
ir_node *hi = new_bd_sparc_SetHi(dbgi, new_block, entity, 0);
ir_node *low = new_bd_sparc_Or_imm(dbgi, new_block, hi, entity, 0);
be_dep_on_frame(hi);
return low;
return make_address(dbgi, new_block, entity, 0);
}
static ir_node *create_fftof(dbg_info *dbgi, ir_node *block, ir_node *op,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment