Commit 9ced62c2 authored by Tobias Rapp's avatar Tobias Rapp
Browse files

rework AMD64_OP_CALL_XXX and AMD64_OP_UNOP_XXX and fix IJmp address mode matching

parent 5ae1d579
......@@ -278,15 +278,16 @@ static void amd64_emit_am(const ir_node *const node)
case AMD64_OP_ADDR:
amd64_emit_addr(node, &attr->addr);
return;
case AMD64_OP_UNOP_REG:
case AMD64_OP_REG: {
const arch_register_t *reg = arch_get_irn_register_in(node, 0);
emit_register_insn_mode(reg, attr->insn_mode);
return;
}
case AMD64_OP_CALL_IMM32:
case AMD64_OP_UNOP_IMM32:
amd64_emit_immediate32(&attr->addr.immediate);
return;
case AMD64_OP_CALL_ADDR:
case AMD64_OP_UNOP_ADDR:
be_emit_char('*');
amd64_emit_addr(node, &attr->addr);
return;
......@@ -303,7 +304,6 @@ static void amd64_emit_am(const ir_node *const node)
case AMD64_OP_IMM32:
case AMD64_OP_IMM64:
case AMD64_OP_NONE:
case AMD64_OP_UNOP_REG:
case AMD64_OP_SHIFT_REG:
case AMD64_OP_SHIFT_IMM:
break;
......@@ -480,19 +480,6 @@ emit_R:
break;
}
case 'U':
if (*fmt == 'O') {
++fmt;
const amd64_unop_attr_t *attr
= get_amd64_unop_attr_const(node);
const arch_register_t *reg
= arch_get_irn_register_in(node, 0);
emit_register_insn_mode(reg, attr->insn_mode);
} else {
panic("invalid emit spec 'U'");
}
break;
case 'M': {
amd64_insn_mode_t insn_mode;
if (*fmt == 'S') {
......@@ -505,11 +492,6 @@ emit_R:
const amd64_movimm_attr_t *attr
= get_amd64_movimm_attr_const(node);
insn_mode = attr->insn_mode;
} else if (*fmt == 'U') {
++fmt;
const amd64_unop_attr_t *attr
= get_amd64_unop_attr_const(node);
insn_mode = attr->insn_mode;
} else {
amd64_addr_attr_t const *const attr
= get_amd64_addr_attr_const(node);
......
......@@ -32,22 +32,22 @@
static const char *get_op_mode_string(amd64_op_mode_t mode)
{
switch (mode) {
case AMD64_OP_NONE: return "none";
case AMD64_OP_ADDR_IMM: return "addr+imm";
case AMD64_OP_ADDR_REG: return "addr+reg";
case AMD64_OP_ADDR: return "addr";
case AMD64_OP_REG: return "reg";
case AMD64_OP_REG_REG: return "reg+reg";
case AMD64_OP_REG_IMM: return "reg+imm";
case AMD64_OP_IMM32: return "imm32";
case AMD64_OP_IMM64: return "imm64";
case AMD64_OP_ADDR_REG: return "addr+reg";
case AMD64_OP_ADDR_IMM: return "addr+imm";
case AMD64_OP_UNOP_REG: return "unop_reg";
case AMD64_OP_SHIFT_REG: return "shift_reg";
case AMD64_OP_SHIFT_IMM: return "shift_imm";
case AMD64_OP_CALL_ADDR: return "call_addr";
case AMD64_OP_CALL_IMM32: return "call_imm32";
case AMD64_OP_RAX_REG: return "rax_reg";
case AMD64_OP_NONE: return "none";
case AMD64_OP_RAX_ADDR: return "rax_addr";
case AMD64_OP_RAX_REG: return "rax_reg";
case AMD64_OP_REG_IMM: return "reg+imm";
case AMD64_OP_REG_REG: return "reg+reg";
case AMD64_OP_REG: return "reg";
case AMD64_OP_SHIFT_IMM: return "shift_imm";
case AMD64_OP_SHIFT_REG: return "shift_reg";
case AMD64_OP_UNOP_ADDR: return "unop_addr";
case AMD64_OP_UNOP_IMM32: return "unop_imm32";
case AMD64_OP_UNOP_REG: return "unop_reg";
}
panic("invalid op_mode");
}
......@@ -87,18 +87,11 @@ static void amd64_dump_node(FILE *F, const ir_node *n, dump_reason_t reason)
arch_dump_reqs_and_registers(F, n);
const amd64_attr_t *attr = get_amd64_attr_const(n);
fprintf(F, "mode = %s\n", get_op_mode_string(attr->op_mode));
switch (attr->op_mode) {
case AMD64_OP_UNOP_REG: {
const amd64_unop_attr_t *unop_attr = get_amd64_unop_attr_const(n);
fprintf(F, "size = %s\n", get_insn_mode_string(unop_attr->insn_mode));
break;
}
case AMD64_OP_ADDR_REG: {
if (attr->op_mode == AMD64_OP_ADDR_REG) {
const amd64_binop_addr_attr_t *binop_attr = get_amd64_binop_addr_attr_const(n);
fprintf(F, "reg input: %d\n", binop_attr->u.reg_input);
} /* FALLTHROUGH */
case AMD64_OP_ADDR: {
}
if (amd64_has_addr_attr(n)) {
const amd64_addr_attr_t *addr_attr = get_amd64_addr_attr_const(n);
fprintf(F, "size = %s\n", get_insn_mode_string(addr_attr->insn_mode));
fprintf(F, "base input: %d\n", addr_attr->addr.base_input);
......@@ -106,8 +99,6 @@ static void amd64_dump_node(FILE *F, const ir_node *n, dump_reason_t reason)
ir_fprintf(F, "am imm: %+F%+" PRId32 "\n", addr_attr->addr.immediate.entity, addr_attr->addr.immediate.offset);
break;
}
}
break;
}
}
......@@ -200,14 +191,6 @@ static int cmp_amd64_addr_attr(const ir_node *a, const ir_node *b)
|| attr_a->needs_frame_ent != attr_b->needs_frame_ent;
}
static int cmp_amd64_unop_attr(const ir_node *a, const ir_node *b)
{
const amd64_unop_attr_t *attr_a = get_amd64_unop_attr_const(a);
const amd64_unop_attr_t *attr_b = get_amd64_unop_attr_const(b);
return cmp_amd64_attr(a, b)
|| attr_a->insn_mode != attr_b->insn_mode;
}
static int cmp_amd64_binop_addr_attr(const ir_node *a,
const ir_node *b)
{
......
......@@ -28,85 +28,112 @@ static inline const amd64_attr_t *get_amd64_attr_const(const ir_node *node)
return (const amd64_attr_t*)get_irn_generic_attr_const(node);
}
static inline bool amd64_has_binop_attr(const ir_node *node)
{
const amd64_attr_t *attr = get_amd64_attr_const(node);
return attr->op_mode == AMD64_OP_REG_REG
|| attr->op_mode == AMD64_OP_REG_IMM
|| attr->op_mode == AMD64_OP_ADDR_REG
|| attr->op_mode == AMD64_OP_ADDR_IMM;
}
static inline bool amd64_has_addr_attr(const ir_node *node)
{
const amd64_attr_t *attr = get_amd64_attr_const(node);
return amd64_has_binop_attr(node)
|| attr->op_mode == AMD64_OP_ADDR
|| attr->op_mode == AMD64_OP_REG
|| attr->op_mode == AMD64_OP_UNOP_ADDR
|| attr->op_mode == AMD64_OP_UNOP_IMM32
|| attr->op_mode == AMD64_OP_UNOP_REG
|| attr->op_mode == AMD64_OP_RAX_ADDR;
}
static inline amd64_addr_attr_t *get_amd64_addr_attr(ir_node *node)
{
assert(amd64_has_addr_attr(node));
return (amd64_addr_attr_t*)get_irn_generic_attr(node);
}
static inline const amd64_addr_attr_t *get_amd64_addr_attr_const(
const ir_node *node)
{
assert(amd64_has_addr_attr(node));
return (const amd64_addr_attr_t*)get_irn_generic_attr_const(node);
}
static inline const amd64_unop_attr_t *get_amd64_unop_attr_const(
const ir_node *node)
{
return (const amd64_unop_attr_t*)get_irn_generic_attr_const(node);
}
static inline amd64_binop_addr_attr_t *get_amd64_binop_addr_attr(ir_node *node)
{
assert(amd64_has_binop_attr(node));
return (amd64_binop_addr_attr_t*)get_irn_generic_attr(node);
}
static inline const amd64_binop_addr_attr_t *get_amd64_binop_addr_attr_const(
const ir_node *node)
{
assert(amd64_has_binop_attr(node));
return (const amd64_binop_addr_attr_t*)get_irn_generic_attr_const(node);
}
static inline bool amd64_has_shift_attr(const ir_node *node)
{
const amd64_attr_t *attr = get_amd64_attr_const(node);
return attr->op_mode == AMD64_OP_SHIFT_REG
|| attr->op_mode == AMD64_OP_SHIFT_IMM;
}
static inline const amd64_shift_attr_t *get_amd64_shift_attr_const(
const ir_node *node)
{
assert(amd64_has_shift_attr(node));
return (const amd64_shift_attr_t*)get_irn_generic_attr_const(node);
}
static inline amd64_shift_attr_t *get_amd64_shift_attr(ir_node *node)
{
assert(amd64_has_shift_attr(node));
return (amd64_shift_attr_t*)get_irn_generic_attr(node);
}
static inline const amd64_switch_jmp_attr_t *get_amd64_switch_jmp_attr_const(
const ir_node *node)
{
assert(is_amd64_SwitchJmp(node));
return (const amd64_switch_jmp_attr_t*)get_irn_generic_attr_const(node);
}
static inline amd64_switch_jmp_attr_t *get_amd64_switch_jmp_attr(ir_node *node)
{
assert(is_amd64_SwitchJmp(node));
return (amd64_switch_jmp_attr_t*)get_irn_generic_attr(node);
}
static inline const amd64_cc_attr_t *get_amd64_cc_attr_const(
const ir_node *node)
{
assert(is_amd64_Jcc(node));
return (const amd64_cc_attr_t*)get_irn_generic_attr_const(node);
}
static inline amd64_cc_attr_t *get_amd64_cc_attr(ir_node *node)
{
assert(is_amd64_Jcc(node));
return (amd64_cc_attr_t*)get_irn_generic_attr(node);
}
static inline const amd64_movimm_attr_t *get_amd64_movimm_attr_const(
const ir_node *node)
{
assert(is_amd64_MovImm(node));
return (const amd64_movimm_attr_t*)get_irn_generic_attr_const(node);
}
static inline amd64_movimm_attr_t *get_amd64_movimm_attr(ir_node *node)
{
assert(is_amd64_MovImm(node));
return (amd64_movimm_attr_t*)get_irn_generic_attr(node);
}
static inline bool amd64_has_addr_attr(const ir_node *node)
{
const amd64_attr_t *attr = get_amd64_attr_const(node);
return attr->op_mode == AMD64_OP_ADDR || attr->op_mode == AMD64_OP_ADDR_REG
|| attr->op_mode == AMD64_OP_ADDR_IMM;
}
/* Include the generated headers */
#include "gen_amd64_new_nodes.h"
......
......@@ -44,10 +44,10 @@ typedef enum {
AMD64_OP_ADDR_REG,
AMD64_OP_ADDR_IMM,
AMD64_OP_UNOP_REG,
AMD64_OP_UNOP_IMM32,
AMD64_OP_UNOP_ADDR,
AMD64_OP_SHIFT_REG,
AMD64_OP_SHIFT_IMM,
AMD64_OP_CALL_ADDR,
AMD64_OP_CALL_IMM32,
/** A binary operation with 1 operand being RAX (which is usually not
* explicitely given in the assembly */
AMD64_OP_RAX_REG,
......@@ -83,11 +83,6 @@ typedef struct {
ENUMBF(amd64_op_mode_t) op_mode : 4;
} amd64_attr_t;
typedef struct {
amd64_attr_t base;
ENUMBF(amd64_insn_mode_t) insn_mode : 2;
} amd64_unop_attr_t;
typedef struct {
amd64_attr_t base;
bool needs_frame_ent : 1;
......
......@@ -54,9 +54,6 @@ $default_copy_attr = "amd64_copy_attr";
amd64_binop_addr_attr_t =>
"init_be_info(res, irn_flags_, in_reqs, n_res);\n"
."\t*attr = *attr_init;",
amd64_unop_attr_t =>
"init_amd64_attributes(res, irn_flags_, in_reqs, n_res, op_mode);"
."\tattr->insn_mode = insn_mode;",
amd64_switch_jmp_attr_t =>
"init_amd64_attributes(res, irn_flags_, in_reqs, n_res, op_mode);\n"
."\tinit_amd64_switch_attributes(res, table, table_entity);",
......@@ -79,7 +76,6 @@ $default_copy_attr = "amd64_copy_attr";
amd64_movimm_attr_t => "cmp_amd64_movimm_attr",
amd64_shift_attr_t => "cmp_amd64_shift_attr",
amd64_switch_jmp_attr_t => "cmp_amd64_switch_jmp_attr",
amd64_unop_attr_t => "cmp_amd64_unop_attr",
);
%nodes = (
......@@ -259,10 +255,11 @@ Neg => {
reg_req => { in => [ "gp" ], out => [ "in_r1" ] },
ins => [ "val" ],
outs => [ "res" ],
attr_type => "amd64_unop_attr_t",
attr_type => "amd64_addr_attr_t",
attr => "amd64_insn_mode_t insn_mode",
fixed => "amd64_op_mode_t op_mode = AMD64_OP_REG;\n",
emit => "neg%MU %UO",
fixed => "amd64_op_mode_t op_mode = AMD64_OP_UNOP_REG;\n"
."amd64_addr_t addr = { { NULL, 0 }, NO_INPUT, NO_INPUT, NO_INPUT, 0, AMD64_SEGMENT_DEFAULT };",
emit => "neg%M %AM",
mode => $mode_gp,
modified_flags => $status_flags
},
......@@ -274,9 +271,10 @@ Not => {
reg_req => { in => [ "gp" ], out => [ "in_r1" ] },
ins => [ "val" ],
outs => [ "res" ],
attr_type => "amd64_unop_attr_t",
fixed => "amd64_op_mode_t op_mode = AMD64_OP_REG;\n",
emit => "not%MU %UO",
attr_type => "amd64_addr_attr_t",
fixed => "amd64_op_mode_t op_mode = AMD64_OP_UNOP_REG;\n"
."amd64_addr_t addr = { { NULL, 0 }, NO_INPUT, NO_INPUT, NO_INPUT, 0, AMD64_SEGMENT_DEFAULT };",
emit => "not%M %AM",
mode => $mode_gp,
modified_flags => $status_flags
},
......@@ -337,11 +335,11 @@ Mov => {
IJmp => {
state => "pinned",
op_flags => [ "cfopcode", "unknown_jump" ],
reg_req => { in => [ "gp" ], out => [ "none" ] },
reg_req => { in => [ "gp" ], out => [ "none", "none", "none" ] },
outs => [ "X", "unused", "M" ],
arity => "variable",
attr_type => "amd64_addr_attr_t",
attr => "amd64_insn_mode_t insn_mode, amd64_op_mode_t op_mode, amd64_addr_t addr",
mode => "mode_X",
emit => "jmp %AM",
},
......
......@@ -144,6 +144,9 @@ static const arch_register_req_t *reg_rcx_reqs[] = {
&amd64_requirement_rcx,
};
static const arch_register_req_t *no_reqs[] = {
};
static inline bool mode_needs_gp_reg(ir_mode *mode)
{
return get_mode_arithmetic(mode) == irma_twos_complement;
......@@ -950,38 +953,67 @@ static ir_node *gen_Sel(ir_node *const node)
static ir_node *gen_IJmp(ir_node *node)
{
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *new_block = be_transform_node(get_nodes_block(node));
ir_node *op = get_IJmp_target(node);
ir_mode *mode = get_irn_mode(op);
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 *op = get_IJmp_target(node);
ir_mode *mode = get_irn_mode(op);
assert(mode == mode_P);
int arity = 0;
ir_node *in[2];
ir_node *in[3];
amd64_addr_t addr;
memset(&addr, 0, sizeof(addr));
perform_address_matching(op, &arity, in, &addr);
const arch_register_req_t **reqs = mem_reqs;
if (addr.base_input != NO_INPUT && addr.index_input != NO_INPUT) {
reqs = reg_reg_mem_reqs;
} else if(addr.base_input != NO_INPUT || addr.index_input != NO_INPUT) {
reqs = reg_mem_reqs;
}
const arch_register_req_t **reqs;
amd64_op_mode_t op_mode;
ir_node *mem_proj = NULL;
if (match_immediate_32(&addr.immediate, op, true, false)) {
// TODO: do we need a must_match_ip_relative in match_immediate_32
op_mode = AMD64_OP_UNOP_IMM32;
arity = 0;
reqs = no_reqs;
} else if (source_am_possible(block, op, NULL)) {
ir_node *load = get_Proj_pred(op);
ir_node *load_ptr = get_Load_ptr(load);
mem_proj = be_get_Proj_for_pn(load, pn_Load_M);
perform_address_matching(load_ptr, &arity, in, &addr);
assert((size_t)arity < ARRAY_SIZE(in));
reqs = mem_reqs;
if (addr.base_input != NO_INPUT && addr.index_input != NO_INPUT) {
reqs = reg_reg_mem_reqs;
} else if(addr.base_input != NO_INPUT || addr.index_input != NO_INPUT) {
reqs = reg_mem_reqs;
}
ir_node *load_mem = get_Load_mem(load);
ir_node *new_mem = be_transform_node(load_mem);
int mem_input = arity++;
in[mem_input] = new_mem;
addr.mem_input = mem_input;
amd64_op_mode_t op_mode;
if (addr.immediate.entity == NULL) {
op_mode = AMD64_OP_CALL_ADDR;
op_mode = AMD64_OP_UNOP_ADDR;
} else {
op_mode = AMD64_OP_ADDR;
op_mode = AMD64_OP_UNOP_REG;
arity = 1;
in[0] = be_transform_node(op);
addr.base_input = NO_INPUT;
addr.index_input = NO_INPUT;
reqs = reg_reqs;
}
ir_node *jmp = new_bd_amd64_IJmp(dbgi, new_block, arity, in,
INSN_MODE_64, op_mode, addr);
INSN_MODE_64, op_mode, addr);
arch_set_irn_register_reqs_in(jmp, reqs);
return jmp;
if (mem_proj != NULL) {
ir_node *load = get_Proj_pred(mem_proj);
be_set_transformed_node(load, jmp);
}
ir_node *proj_X = new_r_Proj(jmp, mode_X, pn_amd64_IJmp_X);
return proj_X;
}
static ir_node *gen_Jmp(ir_node *node)
......@@ -1301,7 +1333,7 @@ static ir_node *gen_Call(ir_node *node)
addr.mem_input = NO_INPUT;
amd64_op_mode_t op_mode;
if (match_immediate_32(&addr.immediate, callee, true, true)) {
op_mode = AMD64_OP_CALL_IMM32;
op_mode = AMD64_OP_UNOP_IMM32;
} else if (source_am_possible(block, callee, NULL)) {
/* TODO: check condition, can't other call inputs be dependent
* on the load which would make this invalid? */
......@@ -1328,14 +1360,14 @@ static ir_node *gen_Call(ir_node *node)
} else {
addr.index_input = NO_INPUT;
}
op_mode = AMD64_OP_CALL_ADDR;
op_mode = AMD64_OP_UNOP_ADDR;
} else {
int base_input = in_arity++;
in[base_input] = be_transform_node(callee);
in_req[base_input] = &amd64_requirement_gp;
addr.base_input = base_input;
addr.index_input = NO_INPUT;
op_mode = AMD64_OP_CALL_ADDR;
op_mode = AMD64_OP_UNOP_REG;
}
assert(in_arity <= (int)max_inputs);
......
......@@ -307,7 +307,7 @@ static void amd64_set_frame_entity(ir_node *node, ir_entity *entity)
*/
static void amd64_collect_frame_entity_nodes(ir_node *node, void *data)
{
if (!is_amd64_Mov(node) && !is_amd64_Movs(node))
if (!is_amd64_irn(node) || !amd64_has_addr_attr(node))
return;
const amd64_addr_attr_t *attr = get_amd64_addr_attr_const(node);
......
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