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) ...@@ -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) static void emit_amd64_jmp_switch(const ir_node *node)
{ {
const amd64_switch_jmp_attr_t *attr = get_amd64_switch_jmp_attr_const(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); amd64_emitf(node, "jmp *%E(,%^S0,8)", attr->table_entity);
be_emit_jump_table(node, attr->table, 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) ...@@ -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) static void emit_arm_SwitchJmp(const ir_node *irn)
{ {
const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(irn); const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(irn);
arm_emitf(irn, "ldrls pc, [pc, %S0, asl #2]"); 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 */ /** Emit an IncSP node */
......
...@@ -1504,17 +1504,16 @@ static void emit_global_decls(const be_main_env_t *main_env) ...@@ -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, 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 */ /* go over all proj's and collect their jump targets */
unsigned n_outs = arch_get_irn_n_outs(node); unsigned n_outs = arch_get_irn_n_outs(node);
const ir_node **targets = XMALLOCNZ(const ir_node*, n_outs); const ir_node **targets = XMALLOCNZ(const ir_node*, n_outs);
foreach_out_edge(node, edge) { foreach_out_edge(node, edge) {
ir_node *proj = get_edge_src_irn(edge); ir_node *proj = get_edge_src_irn(edge);
unsigned pn = get_Proj_num(proj); unsigned pn = get_Proj_num(proj);
ir_node *target = get_cfop_target(proj); targets[pn] = proj;
assert(targets[pn] == NULL);
targets[pn] = target;
} }
/* go over table to determine max value (note that we normalized the /* 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, ...@@ -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) { for (unsigned long i = 0; i < length; ++i) {
const ir_node *block = labels[i]; const ir_node *target = labels[i];
if (block == NULL) if (target == NULL)
block = targets[0]; target = targets[0];
emit_size_type(pointer_size); emit_size_type(pointer_size);
be_gas_emit_block_name(block); emit_target(entity, target);
be_emit_char('\n'); be_emit_char('\n');
be_emit_write_line(); be_emit_write_line();
} }
......
...@@ -123,14 +123,14 @@ void be_gas_end_compilation_unit(const be_main_env_t *env); ...@@ -123,14 +123,14 @@ void be_gas_end_compilation_unit(const be_main_env_t *env);
*/ */
const char *be_gas_insn_label_prefix(void); 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 * Emits a jump table for switch operations
*/ */
void be_emit_jump_table(const ir_node *node, const ir_switch_table *table, void be_emit_jump_table(const ir_node *node, const ir_switch_table *table,
ir_entity *entity, ir_entity const *entity,
get_cfop_target_func get_cfop_target); emit_target_func get_cfop_target);
bool be_gas_produces_dwarf_line_info(void); bool be_gas_produces_dwarf_line_info(void);
......
...@@ -874,16 +874,30 @@ static void emit_ia32_Setcc(const ir_node *node) ...@@ -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 * Emits code for a SwitchJmp
*/ */
static void emit_ia32_SwitchJmp(const ir_node *node) static void emit_ia32_SwitchJmp(const ir_node *node)
{ {
ir_entity *jump_table = get_ia32_am_ent(node); ia32_switch_attr_t const *const attr = get_ia32_switch_attr_const(node);
const ir_switch_table *table = get_ia32_switch_table(node); ia32_emitf(node, "jmp %*AS0");
be_emit_jump_table(node, attr->table, attr->table_entity,
ia32_emitf(node, "jmp %*AM"); emit_jumptable_target);
be_emit_jump_table(node, table, jump_table, get_cfop_target_block);
} }
/** /**
...@@ -2702,7 +2716,7 @@ static void bemit_switchjmp(const ir_node *node) ...@@ -2702,7 +2716,7 @@ static void bemit_switchjmp(const ir_node *node)
bemit8(0xFF); // jmp *tbl.label(,%in,4) bemit8(0xFF); // jmp *tbl.label(,%in,4)
bemit_mod_am(0x05, node); 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) static void bemit_return(const ir_node *node)
......
...@@ -735,13 +735,15 @@ static void init_ia32_climbframe_attributes(ir_node *res, unsigned count) ...@@ -735,13 +735,15 @@ static void init_ia32_climbframe_attributes(ir_node *res, unsigned count)
} }
static void init_ia32_switch_attributes(ir_node *node, 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); ia32_switch_attr_t *attr = (ia32_switch_attr_t*) get_irn_generic_attr(node);
#ifndef NDEBUG #ifndef NDEBUG
attr->attr.attr_type |= IA32_ATTR_ia32_switch_attr_t; attr->attr.attr_type |= IA32_ATTR_ia32_switch_attr_t;
#endif #endif
attr->table = table; attr->table = table;
attr->table_entity = table_entity;
be_foreach_out(node, o) { be_foreach_out(node, o) {
arch_set_irn_register_req_out(node, o, arch_exec_req); 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) ...@@ -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); const ia32_switch_attr_t *attr_b = get_ia32_switch_attr_const(b);
return ia32_attrs_equal_(&attr_a->attr, &attr_b->attr) return ia32_attrs_equal_(&attr_a->attr, &attr_b->attr)
&& attr_a->table == attr_b->table && 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) 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; ...@@ -147,7 +147,7 @@ typedef struct ia32_switch_attr_t ia32_switch_attr_t;
struct ia32_switch_attr_t { struct ia32_switch_attr_t {
ia32_attr_t attr; /**< generic attribute */ ia32_attr_t attr; /**< generic attribute */
const ir_switch_table *table; 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; ...@@ -100,7 +100,7 @@ $custom_init_attr_func = \&ia32_custom_init_attr;
"\tinit_ia32_condcode_attributes(res, condition_code);", "\tinit_ia32_condcode_attributes(res, condition_code);",
ia32_switch_attr_t => ia32_switch_attr_t =>
"init_ia32_attributes(res, irn_flags, in_reqs, n_res);\n". "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 => ia32_copyb_attr_t =>
"init_ia32_attributes(res, irn_flags, in_reqs, n_res);\n". "init_ia32_attributes(res, irn_flags, in_reqs, n_res);\n".
"\tinit_ia32_copyb_attributes(res, size);", "\tinit_ia32_copyb_attributes(res, size);",
...@@ -821,7 +821,7 @@ SwitchJmp => { ...@@ -821,7 +821,7 @@ SwitchJmp => {
ins => [ "base", "index" ], ins => [ "base", "index" ],
out_reqs => "...", out_reqs => "...",
attr_type => "ia32_switch_attr_t", 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, latency => 2,
}, },
......
...@@ -2941,14 +2941,47 @@ static ir_node *gen_Switch(ir_node *node) ...@@ -2941,14 +2941,47 @@ static ir_node *gen_Switch(ir_node *node)
ir_node *const block = be_transform_nodes_block(node); ir_node *const block = be_transform_nodes_block(node);
ir_node *const base = get_global_base(irg); ir_node *const base = get_global_base(irg);
unsigned const n_outs = get_Switch_n_outs(node); 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) ...@@ -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) static void emit_sparc_SwitchJmp(const ir_node *node)
{ {
const sparc_switch_jmp_attr_t *attr = get_sparc_switch_jmp_attr_const(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) ...@@ -1274,7 +1281,8 @@ static void emit_sparc_SwitchJmp(const ir_node *node)
sparc_emitf(node, "jmp %S0"); sparc_emitf(node, "jmp %S0");
fill_delay_slot(node); 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, 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