Commit 16c12b0e authored by Matthias Braun's avatar Matthias Braun
Browse files

amd64: Implement switchjmp in PIC, refactoring

parent 6ab03ddc
......@@ -778,8 +778,9 @@ 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,
amd64_emitf(node, "jmp %*AM");
ir_mode *entry_mode = be_options.pic ? mode_Iu : mode_Lu;
be_emit_jump_table(node, attr->table, attr->table_entity, entry_mode,
emit_jumptable_target);
}
......
......@@ -118,7 +118,7 @@ typedef struct {
} amd64_cc_attr_t;
typedef struct {
amd64_attr_t base;
amd64_addr_attr_t base;
const ir_switch_table *table;
ir_entity *table_entity;
} amd64_switch_jmp_attr_t;
......
......@@ -76,7 +76,9 @@ $mode_x87 = "x86_mode_E";
"be_info_init_irn(res, irn_flags, in_reqs, n_res);\n"
."\t*attr = *attr_init;",
amd64_switch_jmp_attr_t =>
"init_amd64_attributes(res, irn_flags, in_reqs, n_res, AMD64_OP_NONE);\n"
"init_amd64_attributes(res, irn_flags, in_reqs, n_res, op_mode);\n"
."\tattr->base.insn_mode = INSN_MODE_64;\n"
."\tattr->base.addr = *addr;\n"
."\tinit_amd64_switch_attributes(res, table, table_entity);",
amd64_cc_attr_t =>
"init_amd64_attributes(res, irn_flags, in_reqs, n_res, AMD64_OP_NONE);\n"
......@@ -521,10 +523,10 @@ mov_store => {
jmp_switch => {
op_flags => [ "cfopcode", "forking" ],
state => "pinned",
in_reqs => [ "gp" ],
in_reqs => "...",
out_reqs => "...",
attr_type => "amd64_switch_jmp_attr_t",
attr => "const ir_switch_table *table, ir_entity *table_entity",
attr => "amd64_op_mode_t op_mode, const amd64_addr_t *addr, const ir_switch_table *table, ir_entity *table_entity",
},
call => {
......
......@@ -482,6 +482,22 @@ static ir_node *gen_Address(ir_node *const node)
return new_bd_amd64_mov_imm(dbgi, block, INSN_MODE_64, &imm);
}
static ir_node *create_picaddr_lea(ir_node *const block,
x86_immediate_kind_t const kind,
ir_entity *const entity)
{
amd64_addr_t addr = {
.immediate = (x86_imm32_t) {
.kind = kind,
.entity = entity,
},
.base_input = RIP_INPUT,
.index_input = NO_INPUT,
.mem_input = NO_INPUT,
};
return new_bd_amd64_lea(NULL, block, 0, NULL, NULL, INSN_MODE_64, addr);
}
static ir_node *gen_be_Relocation(ir_node *const node)
{
ir_node *const block = be_transform_nodes_block(node);
......@@ -498,18 +514,8 @@ static ir_node *gen_be_Relocation(ir_node *const node)
return new_bd_amd64_mov_imm(NULL, block, INSN_MODE_64, &imm);
}
case X86_IMM_PCREL:
case X86_IMM_GOTPCREL: { /* can GOTPCREL happen here? */
amd64_addr_t addr;
memset(&addr, 0, sizeof(addr));
addr.base_input = RIP_INPUT;
addr.index_input = NO_INPUT;
addr.mem_input = NO_INPUT;
addr.immediate = (x86_imm32_t) {
.kind = kind,
.entity = entity,
};
return new_bd_amd64_lea(NULL, block, 0, NULL, NULL, INSN_MODE_64, addr);
}
case X86_IMM_GOTPCREL: /* can GOTPCREL happen here? */
return create_picaddr_lea(block, kind, entity);
default:
break;
}
......@@ -1004,35 +1010,42 @@ static ir_node *gen_shift_binop(ir_node *node, ir_node *op1, ir_node *op2,
return be_new_Proj(new_node, pn_res);
}
static ir_node *create_lea_as_add(ir_node *node, ir_node *op1, ir_node *op2)
static ir_node *create_add_lea(dbg_info *dbgi, ir_node *new_block,
amd64_insn_mode_t insn_mode, ir_node *op1,
ir_node *op2)
{
dbg_info *const dbgi = get_irn_dbg_info(node);
ir_node *const new_block = be_transform_nodes_block(node);
ir_mode *const mode = get_irn_mode(node);
amd64_insn_mode_t insn_mode = get_mode_size_bits(mode) <= 32
? INSN_MODE_32 : INSN_MODE_64;
const arch_register_req_t **reqs;
amd64_addr_t addr;
memset(&addr, 0, sizeof(addr));
ir_node *in[2];
int arity = 0;
ir_node *in[] = { op1, op2 };
amd64_addr_t addr = {
.base_input = 0,
.index_input = 1,
};
return new_bd_amd64_lea(dbgi, new_block, ARRAY_SIZE(in), in,
amd64_reg_reg_reqs, insn_mode, addr);
}
if (match_immediate_32(&addr.immediate, op2, false, true)) {
in[arity++] = be_transform_node(op1);
reqs = reg_reqs;
addr.index_input = NO_INPUT;
static ir_node *match_simple_lea(dbg_info *dbgi, ir_node *new_block,
amd64_insn_mode_t insn_mode, ir_node *op1,
ir_node *op2)
{
x86_imm32_t immediate;
memset(&immediate, 0, sizeof(immediate));
if (match_immediate_32(&immediate, op2, false, true)) {
ir_node *in[] = {
be_transform_node(op1)
};
amd64_addr_t addr = {
.immediate = immediate,
.base_input = 0,
.index_input = NO_INPUT,
.mem_input = NO_INPUT,
};
return new_bd_amd64_lea(dbgi, new_block, ARRAY_SIZE(in), in, reg_reqs,
insn_mode, addr);
} else {
in[arity++] = be_transform_node(op1);
in[arity++] = be_transform_node(op2);
addr.base_input = 0;
addr.index_input = 1;
reqs = amd64_reg_reg_reqs;
ir_node *const new_op1 = be_transform_node(op1);
ir_node *const new_op2 = be_transform_node(op2);
return create_add_lea(dbgi, new_block, insn_mode, new_op1, new_op2);
}
return new_bd_amd64_lea(dbgi, new_block, arity, in, reqs, insn_mode, addr);
}
static ir_node *gen_Add(ir_node *const node)
......@@ -1060,8 +1073,13 @@ static ir_node *gen_Add(ir_node *const node)
if (use_am)
res = gen_binop_am(node, op1, op2, new_bd_amd64_add, pn_amd64_add_res,
flags);
else
res = create_lea_as_add(node, op1, op2);
else {
amd64_insn_mode_t insn_mode = get_mode_size_bits(mode) <= 32
? INSN_MODE_32 : INSN_MODE_64;
dbg_info *const dbgi = get_irn_dbg_info(node);
ir_node *const new_block = be_transform_node(block);
res = match_simple_lea(dbgi, new_block, insn_mode, op1, op2);
}
x86_mark_non_am(node);
return res;
......@@ -1511,10 +1529,60 @@ static ir_node *gen_Switch(ir_node *const node)
set_entity_visibility(entity, ir_visibility_private);
add_entity_linkage(entity, IR_LINKAGE_CONSTANT);
arch_register_req_t const **in_reqs;
amd64_op_mode_t op_mode;
int arity = 0;
ir_node *in[1];
amd64_addr_t addr;
if (be_options.pic) {
ir_node *const base
= create_picaddr_lea(new_block, X86_IMM_PCREL, entity);
ir_node *load_in[3];
int load_arity = 0;
int load_base = load_arity++;
int load_index = load_arity++;
load_in[load_base] = base;
load_in[load_index] = new_sel;
addr = (amd64_addr_t) {
.base_input = load_base,
.index_input = load_index,
.mem_input = NO_INPUT,
.log_scale = 2,
};
ir_node *const load
= new_bd_amd64_movs(dbgi, new_block, load_arity, load_in,
amd64_reg_reg_reqs, INSN_MODE_32,
AMD64_OP_ADDR, addr);
ir_node *const load_res = be_new_Proj(load, pn_amd64_movs_res);
ir_node *const add = create_add_lea(dbgi, new_block, INSN_MODE_64,
base, load_res);
memset(&addr, 0, sizeof(addr));
op_mode = AMD64_OP_REG;
in[arity++] = add;
in_reqs = reg_reqs;
} else {
int index_in = arity++;
in[index_in] = new_sel;
in_reqs = reg_reqs;
addr = (amd64_addr_t) {
.immediate = {
.kind = X86_IMM_ADDR,
.entity = entity,
},
.base_input = NO_INPUT,
.index_input = index_in,
.log_scale = 3,
};
op_mode = AMD64_OP_ADDR;
}
table = ir_switch_table_duplicate(irg, table);
ir_node *const out = new_bd_amd64_jmp_switch(dbgi, new_block, new_sel,
n_outs, table, entity);
ir_node *const out = new_bd_amd64_jmp_switch(dbgi, new_block, arity, in,
in_reqs, n_outs, op_mode,
&addr, table, entity);
return out;
}
......
......@@ -502,7 +502,7 @@ 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, emit_jumptable_target);
be_emit_jump_table(irn, attr->table, NULL, mode_P, emit_jumptable_target);
}
/** Emit an IncSP node */
......
......@@ -1515,7 +1515,7 @@ 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 const *const entity,
ir_entity const *const entity, ir_mode *entry_mode,
emit_target_func emit_target)
{
/* go over all proj's and collect their jump targets */
......@@ -1581,9 +1581,10 @@ void be_emit_jump_table(const ir_node *node, const ir_switch_table *table,
}
/* emit table */
unsigned pointer_size = get_mode_size_bytes(mode_P);
unsigned pointer_size = get_mode_size_bytes(entry_mode);
if (entity != NULL) {
be_gas_emit_switch_section(GAS_SECTION_RODATA);
if (be_gas_object_file_format != OBJECT_FILE_FORMAT_MACH_O)
be_gas_emit_switch_section(GAS_SECTION_RODATA);
be_emit_irprintf("\t.align %u\n", pointer_size);
be_gas_emit_entity(entity);
be_emit_cstring(":\n");
......@@ -1599,7 +1600,8 @@ void be_emit_jump_table(const ir_node *node, const ir_switch_table *table,
be_emit_write_line();
}
if (entity != NULL)
if (entity != NULL
&& be_gas_object_file_format != OBJECT_FILE_FORMAT_MACH_O)
be_gas_emit_switch_section(GAS_SECTION_TEXT);
free(labels);
......
......@@ -129,7 +129,7 @@ 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 const *entity,
ir_entity const *entity, ir_mode *entry_mode,
emit_target_func get_cfop_target);
bool be_gas_produces_dwarf_line_info(void);
......
......@@ -896,7 +896,7 @@ static void emit_ia32_SwitchJmp(const ir_node *node)
{
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,
be_emit_jump_table(node, attr->table, attr->table_entity, mode_P,
emit_jumptable_target);
}
......@@ -2714,7 +2714,7 @@ static void bemit_switchjmp(const ir_node *node)
bemit_mod_am(0x05, node);
ia32_switch_attr_t const *const attr = get_ia32_switch_attr_const(node);
be_emit_jump_table(node, attr->table, attr->table_entity,
be_emit_jump_table(node, attr->table, attr->table_entity, mode_P,
emit_jumptable_target);
}
......
......@@ -1282,7 +1282,7 @@ 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,
be_emit_jump_table(node, attr->table, attr->table_entity, mode_P,
emit_jumptable_target);
}
......
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