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

begnuas/i32: properly emit jump tables in PIC mode

parent aba0611e
......@@ -712,13 +712,24 @@ static void emit_amd64_jmp(const ir_node *node)
}
}
static void emit_jumptable_target(ir_entity const *const table,
ir_node const *const proj_x)
{
ir_node const *const block = get_cfop_target_block(proj_x);
be_gas_emit_block_name(block);
if (be_options.pic) {
be_emit_char('-');
be_gas_emit_entity(table);
}
}
static void emit_amd64_jmp_switch(const ir_node *node)
{
const amd64_switch_jmp_attr_t *attr = get_amd64_switch_jmp_attr_const(node);
amd64_emitf(node, "jmp *%E(,%^S0,8)", attr->table_entity);
be_emit_jump_table(node, attr->table, attr->table_entity,
get_cfop_target_block);
emit_jumptable_target);
}
/**
......
......@@ -489,12 +489,19 @@ static void emit_arm_B(const ir_node *irn)
}
}
static void emit_jumptable_target(ir_entity const *const table,
ir_node const *const proj_x)
{
(void)table;
arm_emit_cfop_target(proj_x);
}
static void emit_arm_SwitchJmp(const ir_node *irn)
{
const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(irn);
arm_emitf(irn, "ldrls pc, [pc, %S0, asl #2]");
be_emit_jump_table(irn, attr->table, NULL, get_cfop_target_block);
be_emit_jump_table(irn, attr->table, NULL, emit_jumptable_target);
}
/** Emit an IncSP node */
......
......@@ -1504,17 +1504,16 @@ static void emit_global_decls(const be_main_env_t *main_env)
}
void be_emit_jump_table(const ir_node *node, const ir_switch_table *table,
ir_entity *entity, get_cfop_target_func get_cfop_target)
ir_entity const *const entity,
emit_target_func emit_target)
{
/* go over all proj's and collect their jump targets */
unsigned n_outs = arch_get_irn_n_outs(node);
const ir_node **targets = XMALLOCNZ(const ir_node*, n_outs);
foreach_out_edge(node, edge) {
ir_node *proj = get_edge_src_irn(edge);
unsigned pn = get_Proj_num(proj);
ir_node *target = get_cfop_target(proj);
assert(targets[pn] == NULL);
targets[pn] = target;
ir_node *proj = get_edge_src_irn(edge);
unsigned pn = get_Proj_num(proj);
targets[pn] = proj;
}
/* go over table to determine max value (note that we normalized the
......@@ -1580,11 +1579,11 @@ void be_emit_jump_table(const ir_node *node, const ir_switch_table *table,
}
for (unsigned long i = 0; i < length; ++i) {
const ir_node *block = labels[i];
if (block == NULL)
block = targets[0];
const ir_node *target = labels[i];
if (target == NULL)
target = targets[0];
emit_size_type(pointer_size);
be_gas_emit_block_name(block);
emit_target(entity, target);
be_emit_char('\n');
be_emit_write_line();
}
......
......@@ -123,14 +123,14 @@ void be_gas_end_compilation_unit(const be_main_env_t *env);
*/
const char *be_gas_insn_label_prefix(void);
typedef ir_node* (*get_cfop_target_func)(const ir_node *cfop);
typedef void (*emit_target_func)(ir_entity const *table, ir_node const *proj_x);
/**
* Emits a jump table for switch operations
*/
void be_emit_jump_table(const ir_node *node, const ir_switch_table *table,
ir_entity *entity,
get_cfop_target_func get_cfop_target);
ir_entity const *entity,
emit_target_func get_cfop_target);
bool be_gas_produces_dwarf_line_info(void);
......
......@@ -874,16 +874,30 @@ static void emit_ia32_Setcc(const ir_node *node)
}
}
static void emit_jumptable_target(ir_entity const *const table,
ir_node const *const proj_x)
{
(void)table;
ir_node const *const block = get_cfop_target_block(proj_x);
be_gas_emit_block_name(block);
if (ia32_pic_style == IA32_PIC_ELF_PLT
|| ia32_pic_style == IA32_PIC_ELF_NO_PLT) {
be_emit_cstring("@GOTOFF");
} else if (ia32_pic_style == IA32_PIC_MACH_O) {
be_emit_char('-');
be_emit_string(pic_base_label);
}
}
/**
* Emits code for a SwitchJmp
*/
static void emit_ia32_SwitchJmp(const ir_node *node)
{
ir_entity *jump_table = get_ia32_am_ent(node);
const ir_switch_table *table = get_ia32_switch_table(node);
ia32_emitf(node, "jmp %*AM");
be_emit_jump_table(node, table, jump_table, get_cfop_target_block);
ia32_switch_attr_t const *const attr = get_ia32_switch_attr_const(node);
ia32_emitf(node, "jmp %*AS0");
be_emit_jump_table(node, attr->table, attr->table_entity,
emit_jumptable_target);
}
/**
......@@ -2702,7 +2716,7 @@ static void bemit_switchjmp(const ir_node *node)
bemit8(0xFF); // jmp *tbl.label(,%in,4)
bemit_mod_am(0x05, node);
be_emit_jump_table(node, table, jump_table, get_cfop_target_block);
be_emit_jump_table(node, table, jump_table, emit_jumptable_target);
}
static void bemit_return(const ir_node *node)
......
......@@ -735,13 +735,15 @@ static void init_ia32_climbframe_attributes(ir_node *res, unsigned count)
}
static void init_ia32_switch_attributes(ir_node *node,
const ir_switch_table *table)
ir_switch_table const *const table,
ir_entity const *const table_entity)
{
ia32_switch_attr_t *attr = (ia32_switch_attr_t*) get_irn_generic_attr(node);
#ifndef NDEBUG
attr->attr.attr_type |= IA32_ATTR_ia32_switch_attr_t;
#endif
attr->table = table;
attr->table = table;
attr->table_entity = table_entity;
be_foreach_out(node, o) {
arch_set_irn_register_req_out(node, o, arch_exec_req);
......@@ -849,7 +851,7 @@ static int ia32_switch_attrs_equal(const ir_node *a, const ir_node *b)
const ia32_switch_attr_t *attr_b = get_ia32_switch_attr_const(b);
return ia32_attrs_equal_(&attr_a->attr, &attr_b->attr)
&& attr_a->table == attr_b->table
&& attr_a->jump_table == attr_b->jump_table;
&& attr_a->table_entity == attr_b->table_entity;
}
static int ia32_return_attrs_equal(const ir_node *a, const ir_node *b)
......
......@@ -147,7 +147,7 @@ typedef struct ia32_switch_attr_t ia32_switch_attr_t;
struct ia32_switch_attr_t {
ia32_attr_t attr; /**< generic attribute */
const ir_switch_table *table;
ir_entity *jump_table;
const ir_entity *table_entity;
};
/**
......
......@@ -100,7 +100,7 @@ $custom_init_attr_func = \&ia32_custom_init_attr;
"\tinit_ia32_condcode_attributes(res, condition_code);",
ia32_switch_attr_t =>
"init_ia32_attributes(res, irn_flags, in_reqs, n_res);\n".
"\tinit_ia32_switch_attributes(res, switch_table);",
"\tinit_ia32_switch_attributes(res, switch_table, table_entity);",
ia32_copyb_attr_t =>
"init_ia32_attributes(res, irn_flags, in_reqs, n_res);\n".
"\tinit_ia32_copyb_attributes(res, size);",
......@@ -821,7 +821,7 @@ SwitchJmp => {
ins => [ "base", "index" ],
out_reqs => "...",
attr_type => "ia32_switch_attr_t",
attr => "const ir_switch_table *switch_table",
attr => "const ir_switch_table *switch_table, const ir_entity *table_entity",
latency => 2,
},
......
......@@ -2941,14 +2941,47 @@ static ir_node *gen_Switch(ir_node *node)
ir_node *const block = be_transform_nodes_block(node);
ir_node *const base = get_global_base(irg);
unsigned const n_outs = get_Switch_n_outs(node);
ir_node *const new_node = new_bd_ia32_SwitchJmp(dbgi, block, base, new_sel, n_outs, table);
set_ia32_am_scale(new_node, 2);
set_ia32_op_type(new_node, ia32_AddrModeS);
set_ia32_ls_mode(new_node, ia32_mode_gp);
SET_IA32_ORIG_NODE(new_node, node);
set_am_const_entity(new_node, entity);
return new_node;
ir_node *switchjmp;
ir_node *table_am;
ir_node *target;
switch (ia32_pic_style) {
case IA32_PIC_NONE:
switchjmp = new_bd_ia32_SwitchJmp(dbgi, block, base, new_sel, n_outs,
table, entity);
table_am = switchjmp;
goto finish;
case IA32_PIC_ELF_PLT:
case IA32_PIC_ELF_NO_PLT: {
ir_node *const load = new_bd_ia32_Load(dbgi, block, base, new_sel,
nomem);
table_am = load;
ir_node *const load_res = be_new_Proj(load, pn_ia32_Load_res);
target = new_bd_ia32_Lea(dbgi, block, base, load_res);
goto simple_jmp;
}
case IA32_PIC_MACH_O: {
target = new_bd_ia32_Add(dbgi, block, base, new_sel, nomem, base,
noreg_GP);
set_ia32_commutative(target);
table_am = target;
simple_jmp:
switchjmp = new_bd_ia32_SwitchJmp(dbgi, block, target, noreg_GP, n_outs,
table, entity);
set_ia32_op_type(switchjmp, ia32_Normal);
set_ia32_ls_mode(switchjmp, ia32_mode_gp);
goto finish;
}
}
panic("invalid PIC style");
finish:
set_ia32_am_scale(table_am, 2);
set_ia32_op_type(table_am, ia32_AddrModeS);
set_ia32_ls_mode(table_am, ia32_mode_gp);
set_am_const_entity(table_am, entity);
SET_IA32_ORIG_NODE(switchjmp, node);
return switchjmp;
}
/**
......
......@@ -1267,6 +1267,13 @@ static void emit_sparc_Ba(const ir_node *node)
}
}
static void emit_jumptable_target(ir_entity const *const table,
ir_node const *const proj_x)
{
(void)table;
sparc_emit_cfop_target(proj_x);
}
static void emit_sparc_SwitchJmp(const ir_node *node)
{
const sparc_switch_jmp_attr_t *attr = get_sparc_switch_jmp_attr_const(node);
......@@ -1274,7 +1281,8 @@ static void emit_sparc_SwitchJmp(const ir_node *node)
sparc_emitf(node, "jmp %S0");
fill_delay_slot(node);
be_emit_jump_table(node, attr->table, attr->table_entity, get_jump_target);
be_emit_jump_table(node, attr->table, attr->table_entity,
emit_jumptable_target);
}
static void emit_fmov(const ir_node *node, const arch_register_t *src_reg,
......
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