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

amd64: Start using x87_sim

parent ccb426a1
......@@ -343,6 +343,8 @@ static void amd64_emit_am(const ir_node *const node, bool indirect_star)
goto emit_addr;
}
case AMD64_OP_ADDR:
case AMD64_OP_X87_ADDR:
case AMD64_OP_X87_ADDR_REG:
if (indirect_star)
be_emit_char('*');
goto emit_addr;
......@@ -504,8 +506,19 @@ end_of_mods:
amd64_addr_attr_t const *const attr
= get_amd64_addr_attr_const(node);
amd64_emit_x87_mode_suffix(attr->insn_mode);
} else
goto unknown;
} else if (*fmt == 'P') {
++fmt;
x87_attr_t const *const attr
= amd64_get_x87_attr_const(node);
if (attr->pop)
be_emit_char('p');
} else {
x87_attr_t const *const attr
= amd64_get_x87_attr_const(node);
char const *const fmt
= attr->res_in_reg ? "%%st, %%%s" : "%%%s, %%st";
be_emit_irprintf(fmt, attr->reg->name);
}
break;
}
......
......@@ -45,6 +45,28 @@ amd64_insn_mode_t get_amd64_insn_mode(const ir_node *node)
}
}
x87_attr_t *amd64_get_x87_attr(ir_node *const node)
{
amd64_attr_t const *const attr = get_amd64_attr_const(node);
switch (attr->op_mode) {
case AMD64_OP_X87:
return &get_amd64_x87_attr(node)->x87;
case AMD64_OP_X87_ADDR:
panic("TODO");
case AMD64_OP_X87_ADDR_REG:
return &get_amd64_x87_binop_addr_attr(node)->x87;
default:
break;
}
panic("try to get x87 attr from invalid node '%s'", node);
}
x87_attr_t const *amd64_get_x87_attr_const(ir_node const *const node)
{
/* hacky */
return amd64_get_x87_attr((ir_node *)node);
}
int get_insn_mode_bits(amd64_insn_mode_t insn_mode)
{
switch (insn_mode) {
......@@ -61,19 +83,21 @@ int get_insn_mode_bits(amd64_insn_mode_t insn_mode)
static const char *get_op_mode_string(amd64_op_mode_t mode)
{
switch (mode) {
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_IMM32: return "imm32";
case AMD64_OP_IMM64: return "imm64";
case AMD64_OP_NONE: return "none";
case AMD64_OP_REG_ADDR: return "reg+addr";
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_X87: return "x87";
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_IMM32: return "imm32";
case AMD64_OP_IMM64: return "imm64";
case AMD64_OP_NONE: return "none";
case AMD64_OP_REG_ADDR: return "reg+addr";
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_X87: return "x87";
case AMD64_OP_X87_ADDR: return "x87+addr";
case AMD64_OP_X87_ADDR_REG: return "x87+addr+reg";
}
return "invalid op_mode";
}
......@@ -281,5 +305,26 @@ static int amd64_call_addr_attrs_equal(const ir_node *const a,
return amd64_addr_attrs_equal(a, b) && attr_a->call_tp == attr_b->call_tp;
}
static int amd64_x87_attrs_equal(const ir_node *const a,
const ir_node *const b)
{
/* we ignore x87 attributes for now */
return amd64_attrs_equal(a, b);
}
static int amd64_x87_addr_attrs_equal(const ir_node *const a,
const ir_node *const b)
{
/* ignore x87 part for now */
return amd64_addr_attrs_equal(a, b);
}
static int amd64_x87_binop_addr_attrs_equal(const ir_node *const a,
const ir_node *const b)
{
/* ignore x87 part for now */
return amd64_binop_addr_attrs_equal(a, b);
}
/* Include the generated constructor functions */
#include "gen_amd64_new_nodes.c.inl"
......@@ -32,7 +32,8 @@ static inline bool amd64_has_binop_attr(const ir_node *node)
|| attr->op_mode == AMD64_OP_REG_IMM
|| attr->op_mode == AMD64_OP_REG_ADDR
|| attr->op_mode == AMD64_OP_ADDR_REG
|| attr->op_mode == AMD64_OP_ADDR_IMM;
|| attr->op_mode == AMD64_OP_ADDR_IMM
|| attr->op_mode == AMD64_OP_X87_ADDR_REG;
}
static inline bool amd64_has_addr_attr(const ir_node *node)
......@@ -41,7 +42,8 @@ static inline bool amd64_has_addr_attr(const ir_node *node)
return amd64_has_binop_attr(node)
|| attr->op_mode == AMD64_OP_ADDR
|| attr->op_mode == AMD64_OP_REG
|| attr->op_mode == AMD64_OP_IMM32;
|| attr->op_mode == AMD64_OP_IMM32
|| attr->op_mode == AMD64_OP_X87_ADDR;
}
static inline amd64_addr_attr_t *get_amd64_addr_attr(ir_node *node)
......@@ -147,6 +149,29 @@ static inline amd64_call_addr_attr_t *get_amd64_call_addr_attr(ir_node *node)
return (amd64_call_addr_attr_t*)get_irn_generic_attr(node);
}
static inline const amd64_x87_attr_t *get_amd64_x87_attr_const(
const ir_node *node)
{
assert(get_amd64_attr_const(node)->op_mode == AMD64_OP_X87);
return (const amd64_x87_attr_t*)get_irn_generic_attr_const(node);
}
static inline amd64_x87_attr_t *get_amd64_x87_attr(ir_node *node)
{
assert(get_amd64_attr_const(node)->op_mode == AMD64_OP_X87);
return (amd64_x87_attr_t*)get_irn_generic_attr(node);
}
static inline amd64_x87_binop_addr_attr_t *get_amd64_x87_binop_addr_attr(
ir_node *const node)
{
assert(get_amd64_attr_const(node)->op_mode == AMD64_OP_X87_ADDR_REG);
return (amd64_x87_binop_addr_attr_t*)get_irn_generic_attr(node);
}
x87_attr_t *amd64_get_x87_attr(ir_node *node);
x87_attr_t const *amd64_get_x87_attr_const(ir_node const *node);
amd64_insn_mode_t get_amd64_insn_mode(const ir_node *node);
int get_insn_mode_bits(amd64_insn_mode_t insn_mode);
......
......@@ -12,10 +12,11 @@
#include <stdint.h>
#include "../ia32/x86_asm.h"
#include "../ia32/x86_cc.h"
#include "../ia32/x86_x87.h"
#include "compiler.h"
#include "irnode_t.h"
#include "../ia32/x86_cc.h"
#include "../ia32/x86_asm.h"
enum amd64_arch_irn_flags_t {
amd64_arch_irn_flag_commutative_binop = arch_irn_flag_backend << 0,
......@@ -55,6 +56,8 @@ typedef enum {
AMD64_OP_SHIFT_REG,
AMD64_OP_SHIFT_IMM,
AMD64_OP_X87,
AMD64_OP_X87_ADDR,
AMD64_OP_X87_ADDR_REG,
} amd64_op_mode_t;
enum {
......@@ -125,4 +128,19 @@ typedef struct {
ir_type *call_tp;
} amd64_call_addr_attr_t;
typedef struct {
amd64_attr_t base;
x87_attr_t x87;
} amd64_x87_attr_t;
typedef struct {
amd64_addr_attr_t base;
x87_attr_t x87;
} amd64_x87_addr_attr_t;
typedef struct {
amd64_binop_addr_attr_t base;
x87_attr_t x87;
} amd64_x87_binop_addr_attr_t;
#endif
......@@ -90,6 +90,17 @@ $mode_x87 = "x86_mode_E";
amd64_call_addr_attr_t =>
"be_info_init_irn(res, irn_flags, in_reqs, n_res);\n"
."\t*attr = *attr_init;",
amd64_x87_attr_t =>
"init_amd64_attributes(res, irn_flags, in_reqs, n_res, AMD64_OP_X87);\n",
amd64_x87_addr_attr_t =>
"init_amd64_attributes(res, irn_flags, in_reqs, n_res, op_mode);\n"
."\tattr->base.insn_mode = insn_mode;\n"
."\tattr->base.addr = addr;\n",
amd64_x87_binop_addr_attr_t =>
"be_info_init_irn(res, irn_flags, in_reqs, n_res);\n"
."\tattr->base = *attr_init;\n"
."\tassert(attr_init->base.base.op_mode == AMD64_OP_ADDR_REG);\n"
."\tattr->base.base.base.op_mode = AMD64_OP_X87_ADDR_REG;\n",
);
my $binop = {
......@@ -742,7 +753,7 @@ fld => {
in_reqs => "...",
out_reqs => [ "x87", "none", "mem" ],
outs => [ "res", "unused", "M" ],
attr_type => "amd64_addr_attr_t",
attr_type => "amd64_x87_addr_attr_t",
attr => "amd64_insn_mode_t insn_mode, amd64_op_mode_t op_mode, amd64_addr_t addr",
emit => "fld%FM %AM",
},
......@@ -753,10 +764,22 @@ fst => {
in_reqs => "...",
out_reqs => [ "mem" ],
outs => [ "M" ],
attr_type => "amd64_binop_addr_attr_t",
attr_type => "amd64_x87_binop_addr_attr_t",
attr => "const amd64_binop_addr_attr_t *attr_init",
mode => "mode_M",
emit => "fst%FM %AM",
emit => "fst%FP%FM %AM",
},
fstp => {
op_flags => [ "uses_memory" ],
state => "exc_pinned",
in_reqs => "...",
out_reqs => [ "mem" ],
outs => [ "M" ],
attr_type => "amd64_x87_binop_addr_attr_t",
attr => "const amd64_binop_addr_attr_t *attr_init",
mode => "mode_M",
emit => "fstp%FM %AM",
},
fchs => {
......@@ -764,4 +787,34 @@ fchs => {
emit => "fchs",
},
fdup => {
in_reqs => [ "x87" ],
out_reqs => [ "x87" ],
ins => [ "val" ],
attrs_equal => "attrs_equal_false",
attr_type => "amd64_x87_attr_t",
attr => "const arch_register_t *reg",
init => "attr->x87.reg = reg;",
emit => "fld %F0",
},
fxch => {
op_flags => [ "keep" ],
out_reqs => [ "none" ],
attrs_equal => "attrs_equal_false",
attr_type => "amd64_x87_attr_t",
attr => "const arch_register_t *reg",
init => "attr->x87.reg = reg;",
emit => "fxch %F0",
},
fpop => {
op_flags => [ "keep" ],
out_reqs => [ "none" ],
attr_type => "amd64_x87_attr_t",
attr => "const arch_register_t *reg",
init => "attr->x87.reg = reg;",
emit => "fstp %F0",
},
);
......@@ -132,6 +132,12 @@ static const arch_register_req_t amd64_requirement_xmm_same_0_not_1 = {
.width = 1,
};
static const arch_register_req_t amd64_requirement_x87killed = {
.cls = &amd64_reg_classes[CLASS_amd64_x87],
.width = 1,
.kills_value = true,
};
static const arch_register_req_t *mem_reqs[] = {
&arch_memory_requirement,
};
......@@ -157,8 +163,8 @@ static const arch_register_req_t *xmm_mem_reqs[] = {
&arch_memory_requirement,
};
static const arch_register_req_t *x87_mem_reqs[] = {
&amd64_class_reg_req_x87,
static const arch_register_req_t *x87K_mem_reqs[] = {
&amd64_requirement_x87killed,
&arch_memory_requirement,
};
......@@ -180,6 +186,12 @@ static const arch_register_req_t *x87_reg_mem_reqs[] = {
&arch_memory_requirement,
};
static const arch_register_req_t *x87K_reg_mem_reqs[] = {
&amd64_requirement_x87killed,
&amd64_class_reg_req_gp,
&arch_memory_requirement,
};
static const arch_register_req_t *reg_reg_reg_mem_reqs[] = {
&amd64_class_reg_req_gp,
&amd64_class_reg_req_gp,
......@@ -194,8 +206,8 @@ static const arch_register_req_t *xmm_reg_reg_mem_reqs[] = {
&arch_memory_requirement,
};
static const arch_register_req_t *x87_reg_reg_mem_reqs[] = {
&amd64_class_reg_req_x87,
static const arch_register_req_t *x87K_reg_reg_mem_reqs[] = {
&amd64_requirement_x87killed,
&amd64_class_reg_req_gp,
&amd64_class_reg_req_gp,
&arch_memory_requirement,
......@@ -279,12 +291,12 @@ static arch_register_req_t const **const xmm_am_reqs[] = {
xmm_reg_reg_mem_reqs,
};
static arch_register_req_t const **const x87_am_reqs[] = {
static arch_register_req_t const **const x87K_am_reqs[] = {
NULL,
mem_reqs,
x87_mem_reqs,
x87_reg_mem_reqs,
x87_reg_reg_mem_reqs,
x87K_mem_reqs,
x87K_reg_mem_reqs,
x87K_reg_reg_mem_reqs,
};
static inline bool mode_needs_gp_reg(ir_mode *mode)
......@@ -1728,7 +1740,7 @@ no_call_mem:
ir_node *const nomem = get_irg_no_mem(irg);
ir_node *const in[] = { new_value, callframe, nomem };
ir_node *const store = mode_is_float(mode) ?
(mode == x86_mode_E ? new_bd_amd64_fst(dbgi, new_block, ARRAY_SIZE(in), in, x87_reg_mem_reqs, &attr)
(mode == x86_mode_E ? new_bd_amd64_fstp(dbgi, new_block, ARRAY_SIZE(in), in, x87K_reg_mem_reqs, &attr)
: new_bd_amd64_movs_store_xmm(dbgi, new_block, ARRAY_SIZE(in), in, xmm_reg_mem_reqs, &attr))
: new_bd_amd64_mov_store(dbgi, new_block, ARRAY_SIZE(in), in, reg_reg_mem_reqs, &attr);
......@@ -2097,6 +2109,7 @@ static ir_node *conv_x87_to_sse(dbg_info *dbgi, ir_node *block, ir_node *op,
ir_node *in[5];
int n_in = 0;
amd64_addr_t addr;
assert(get_mode_size_bits(dst_mode) <= 64);
store_to_temp(new_bd_amd64_fst, &addr, dbgi, block, in, &n_in, op,
dst_mode);
assert(n_in < (int)ARRAY_SIZE(in));
......@@ -2302,12 +2315,12 @@ static ir_node *gen_Store(ir_node *const node)
attr.base.insn_mode = get_insn_mode_from_mode(mode);
arch_register_req_t const **const reqs
= (mode_is_float(mode) ? (mode == x86_mode_E ? x87_am_reqs
= (mode_is_float(mode) ? (mode == x86_mode_E ? x87K_am_reqs
: xmm_am_reqs)
: gp_am_reqs)[arity];
new_store_func const cons
= mode_is_float(mode) ? (mode == x86_mode_E ? &new_bd_amd64_fst
= mode_is_float(mode) ? (mode == x86_mode_E ? &new_bd_amd64_fstp
: &new_bd_amd64_movs_store_xmm)
: &new_bd_amd64_mov_store;
ir_node *const new_store = cons(dbgi, block, arity, in, reqs, &attr);
......
#include "panic.h"
#include "bearch_amd64_t.h"
#include "amd64_new_nodes.h"
#include "gen_amd64_regalloc_if.h"
#include "../ia32/x86_x87.h"
static unsigned get_bits_from_insn_mode(amd64_insn_mode_t const insn_mode)
{
switch (insn_mode) {
case INSN_MODE_8: return 8;
case INSN_MODE_16: return 16;
case INSN_MODE_32: return 32;
case INSN_MODE_64: return 64;
case INSN_MODE_128: return 128;
case INSN_MODE_INVALID:
break;
}
panic("invalid insn_mode");
}
static void sim_amd64_fst(x87_state *const state, ir_node *const node)
{
amd64_addr_attr_t const *const attr = get_amd64_addr_attr_const(node);
unsigned const bits = get_bits_from_insn_mode(attr->insn_mode);
x86_sim_x87_store(state, node, 0, bits);
}
static void sim_amd64_fstp(x87_state *const state, ir_node *const node)
{
x86_sim_x87_store_pop(state, node, 0);
}
static void sim_amd64_fld(x87_state *const state, ir_node *const node)
{
ir_node *const value = get_Proj_for_pn(node, pn_amd64_fld_res);
x86_sim_x87_load(state, node, value);
}
static void prepare_callbacks(void)
{
x86_prepare_x87_callbacks();
x86_register_x87_sim(op_amd64_fld, sim_amd64_fld);
x86_register_x87_sim(op_amd64_fst, sim_amd64_fst);
x86_register_x87_sim(op_amd64_fstp, sim_amd64_fstp);
x86_register_x87_sim(op_amd64_ret, x86_sim_x87_ret);
}
void amd64_simulate_graph_x87(ir_graph *irg)
{
prepare_callbacks();
const x87_simulator_config_t config = {
.regclass = &amd64_reg_classes[CLASS_amd64_x87],
.new_bd_fdup = new_bd_amd64_fdup,
.new_bd_fxch = new_bd_amd64_fxch,
.new_bd_fpop = new_bd_amd64_fpop,
.get_x87_attr = amd64_get_x87_attr,
};
x86_x87_simulate_graph(irg, &config);
}
......@@ -637,6 +637,8 @@ static void amd64_finish_and_emit(ir_graph *irg)
/* Fix 2-address code constraints. */
amd64_finish_irg(irg);
amd64_simulate_graph_x87(irg);
/* emit code */
be_timer_push(T_EMIT);
amd64_emit_function(irg);
......
......@@ -38,4 +38,6 @@ void amd64_cconv_init(void);
void amd64_adjust_pic(ir_graph *irg);
void amd64_simulate_graph_x87(ir_graph *irg);
#endif
......@@ -1107,6 +1107,12 @@ static void introduce_prologue_epilogue(ir_graph *const irg)
introduce_prologue(irg);
}
static x87_attr_t *ia32_get_x87_attr(ir_node *const node)
{
ia32_x87_attr_t *const attr = get_ia32_x87_attr(node);
return &attr->x87;
}
static void ia32_emit(ir_graph *irg)
{
/*
......@@ -1140,6 +1146,7 @@ static void ia32_emit(ir_graph *irg)
/* we might have to rewrite x87 virtual registers */
ia32_irg_data_t const *const irg_data = ia32_get_irg_data(irg);
if (irg_data->do_x87_sim) {
x86_prepare_x87_callbacks_ia32();
const x87_simulator_config_t config = {
.regclass = &ia32_reg_classes[CLASS_ia32_fp],
.new_bd_fdup = new_bd_ia32_fdup,
......@@ -1147,6 +1154,7 @@ static void ia32_emit(ir_graph *irg)
.new_bd_fpop = new_bd_ia32_fpop,
.new_bd_ffreep = ia32_cg_config.use_ffreep ? new_bd_ia32_ffreep
: NULL,
.get_x87_attr = ia32_get_x87_attr,
};
x86_x87_simulate_graph(irg, &config);
}
......
......@@ -68,19 +68,11 @@ typedef struct st_entry {
/**
* The x87 state.
*/
typedef struct x87_state {
struct x87_state {
st_entry st[N_X87_REGS]; /**< the register stack */
unsigned depth; /**< the current stack depth */
x87_simulator *sim; /**< The simulator. */
} x87_state;
/**
* The type of an instruction simulator function.
*
* @param state the x87 state
* @param n the node to be simulated
*/
typedef void (*sim_func)(x87_state *state, ir_node *n);
};
/**
* A block state: Every block has a x87 state at the beginning and at the end.
......@@ -786,26 +778,29 @@ static void sim_unop(x87_state *state, ir_node *n)
* @param state the x87 state
* @param n the node that should be simulated (and patched)
*/
static void sim_load(x87_state *state, ir_node *n)
void x86_sim_x87_load(x87_state *state, ir_node *n, ir_node *value)
{
assert((unsigned)pn_ia32_fld_res == (unsigned)pn_ia32_fild_res
&& (unsigned)pn_ia32_fld_res == (unsigned)pn_ia32_fld1_res
&& (unsigned)pn_ia32_fld_res == (unsigned)pn_ia32_fldz_res);
DB((dbg, LEVEL_1, ">>> %+F\n", n));
x87_push(state, get_result_node(n));
x87_push(state, value);
DB((dbg, LEVEL_1, "<<< %s -> %s\n", get_irn_opname(n), get_st_reg(0)->name));
}
static void sim_ia32_x87_load(x87_state *state, ir_node *n)
{
ir_node *value = get_result_node(n);
x86_sim_x87_load(state, n, value);
}
/**
* Simulate a virtual Store.
*
* @param state the x87 state
* @param n the node that should be simulated (and patched)
*/
static void sim_store(x87_state *state, ir_node *n)
void x86_sim_x87_store(x87_state *state, ir_node *n, int val_pos,
unsigned store_bits)
{
ir_node *const val = get_irn_n(n, n_ia32_fst_val);
ir_node *const val = get_irn_n(n, val_pos);
DB((dbg, LEVEL_1, ">>> %+F %+F ->\n", n, val));
fp_liveness const live = fp_live_args_after(state->sim, n, 0);
......@@ -814,9 +809,7 @@ static void sim_store(x87_state *state, ir_node *n)
move_to_tos(state, n, val);
goto do_pop;
} else {
ir_mode *const mode = get_ia32_ls_mode(n);
assert(!mode_is_int(mode) || get_mode_size_bits(mode) <= 32);
if (get_mode_size_bits(mode) > 64) {
if (store_bits > 64) {
/* Problem: fst doesn't support 80bit modes. Code selection chooses
* an explicit fstp in this case which is fine, however if we create
* an 80bit fst because of a spill we may need some fixup here.
......@@ -838,7 +831,7 @@ do_pop:
ir_node *const mem = get_Proj_for_pn(n, pn_ia32_st_M);
ir_node *const base = get_irn_n(n, n_ia32_base);
ir_node *const idx = get_irn_n(n, n_ia32_index);
ir_node *const vfld = new_bd_ia32_fld(NULL, block, base, idx, mem, mode);
ir_node *const vfld = new_bd_ia32_fld(NULL, block, base, idx, mem, x86_mode_E);
/* copy all attributes */
ia32_copy_am_attrs(vfld, n);
......@@ -864,7 +857,7 @@ do_pop:
be_ssa_construction_destroy(&env);
}
get_ia32_x87_attr(n)->x87.pop = true;
x87.get_x87_attr(n)->pop = true;
} else {
/* we can only store the tos to memory */
move_to_tos(state, n, val);
......@@ -874,26 +867,50 @@ do_pop:
DB((dbg, LEVEL_1, "<<< %s %s ->\n", get_irn_opname(n), get_st_reg(0)->name));
}
/**
* Simulate a virtual fisttp.
*
* @param state the x87 state
* @param n the node that should be simulated (and patched)
*/
static void sim_store_pop(x87_state *state, ir_node *n)
static void sim_ia32_fst(x87_state *state, ir_node *n)
{
unsigned bits = get_mode_size_bits(get_ia32_ls_mode(n));
x86_sim_x87_store(state, n, n_ia32_fst_val, bits);
}
static void sim_ia32_fist(x87_state *state, ir_node *n)
{
unsigned bits = get_mode_size_bits(get_ia32_ls_mode(n));
x86_sim_x87_store(state, n, n_ia32_fist_val, bits);
}
void x86_sim_x87_store_pop(x87_state *const state, ir_node *const node,
int const val_pos)
{
assert((int)n_ia32_fisttp_val == (int)n_ia32_fistp_val);
ir_node *const val = get_irn_n(n, n_ia32_fisttp_val);
DB((dbg, LEVEL_1, ">>> %+F %s ->\n", n, arch_get_irn_register(val)->name));
ir_node *const val = get_irn_n(node, val_pos);
DB((dbg, LEVEL_1, ">>> %+F %s ->\n", node,