#include "../belive_t.h"
#include "../besched_t.h"
#include "../benode_t.h"
+#include "bearch_ia32_t.h"
#include "ia32_new_nodes.h"
#include "gen_ia32_new_nodes.h"
#include "gen_ia32_regalloc_if.h"
#define N_x87_REGS 8
-/* first and second binop index */
-#define BINOP_IDX_1 2
-#define BINOP_IDX_2 3
-
/* the unop index */
#define UNOP_IDX 0
-/* the store val index */
-#define STORE_VAL_IDX 2
-
#define MASK_TOS(x) ((x) & (N_x87_REGS - 1))
/** the debug handle */
vfp_liveness *live; /**< Liveness information. */
unsigned n_idx; /**< The cached get_irg_last_idx() result. */
waitq *worklist; /**< Worklist of blocks that must be processed. */
+ ia32_isa_t *isa; /**< the ISA object */
};
/**
DB((dbg, LEVEL_2, "After POP: ")); DEBUG_ONLY(x87_dump_stack(state));
} /* x87_pop */
+/**
+ * Empty the fpu stack
+ *
+ * @param state the x87 state
+ */
+static void x87_emms(x87_state *state) {
+ state->depth = 0;
+ state->tos = 0;
+}
+
/**
* Returns the block state of a block.
*
{
ir_node *fpop;
ia32_x87_attr_t *attr;
+ int cpu = state->sim->isa->opt_arch;
while (num > 0) {
x87_pop(state);
- fpop = new_rd_ia32_fpop(NULL, get_irn_irg(n), get_nodes_block(n), mode_E);
+ if (ARCH_ATHLON(cpu))
+ fpop = new_rd_ia32_ffreep(NULL, get_irn_irg(n), get_nodes_block(n), mode_E);
+ else
+ fpop = new_rd_ia32_fpop(NULL, get_irn_irg(n), get_nodes_block(n), mode_E);
attr = get_ia32_x87_attr(fpop);
attr->x87[0] = &ia32_st_regs[0];
attr->x87[1] = &ia32_st_regs[0];
ir_node *patched_insn;
ir_op *dst;
x87_simulator *sim = state->sim;
- ir_node *op1 = get_irn_n(n, BINOP_IDX_1);
- ir_node *op2 = get_irn_n(n, BINOP_IDX_2);
+ ir_node *op1 = get_irn_n(n, n_ia32_binary_left);
+ ir_node *op2 = get_irn_n(n, n_ia32_binary_right);
const arch_register_t *op1_reg = x87_get_irn_register(sim, op1);
const arch_register_t *op2_reg = x87_get_irn_register(sim, op2);
const arch_register_t *out = x87_get_irn_register(sim, n);
if (op1_live_after) {
/* Both operands are live: push the first one.
This works even for op1 == op2. */
- x87_create_fpush(state, n, op1_idx, BINOP_IDX_2);
+ x87_create_fpush(state, n, op1_idx, n_ia32_binary_right);
/* now do fxxx (tos=tos X op) */
op1_idx = 0;
op2_idx += 1;
/* second operand is an address mode */
if (op1_live_after) {
/* first operand is live: push it here */
- x87_create_fpush(state, n, op1_idx, BINOP_IDX_1);
+ x87_create_fpush(state, n, op1_idx, n_ia32_binary_left);
op1_idx = 0;
/* use fxxx (tos = tos X mem) */
dst = tmpl->normal_op;
*/
static int sim_store(x87_state *state, ir_node *n, ir_op *op, ir_op *op_p) {
x87_simulator *sim = state->sim;
- ir_node *val = get_irn_n(n, STORE_VAL_IDX);
+ ir_node *val = get_irn_n(n, n_ia32_vfst_val);
const arch_register_t *op2 = x87_get_irn_register(sim, val);
unsigned live = vfp_live_args_after(sim, n, 0);
int insn = NO_NODE_ADDED;
- stack not full: push value and fstp
- stack full: fstp value and load again
*/
- if (mode == mode_E) {
+ if (mode == mode_E || mode == mode_Ls) {
if (depth < N_x87_REGS) {
/* ok, we have a free register: push + fstp */
- x87_create_fpush(state, n, op2_idx, STORE_VAL_IDX);
+ x87_create_fpush(state, n, op2_idx, n_ia32_vfst_val);
x87_pop(state);
x87_patch_insn(n, op_p);
} else {
/* reroute all former users of the store memory to the load memory */
edges_reroute(mem, mproj, irg);
/* set the memory input of the load to the store memory */
- set_irn_n(vfld, 2, mem);
+ set_irn_n(vfld, n_ia32_vfld_mem, mem);
sched_add_after(n, vfld);
sched_add_after(vfld, rproj);
GEN_STORE(fist)
/**
- * Simulate a fCondJmp.
- *
* @param state the x87 state
* @param n the node that should be simulated (and patched)
*
* @return NO_NODE_ADDED
*/
-static int sim_fCmpJmp(x87_state *state, ir_node *n) {
+static int sim_FucomFnstsw(x87_state *state, ir_node *n) {
int op1_idx;
int op2_idx = -1;
int pop_cnt = 0;
- ia32_x87_attr_t *attr;
+ ia32_x87_attr_t *attr = get_ia32_x87_attr(n);
ir_op *dst;
x87_simulator *sim = state->sim;
- ir_node *op1_node = get_irn_n(n, n_ia32_vfCmpJmp_left);
- ir_node *op2_node = get_irn_n(n, n_ia32_vfCmpJmp_right);
+ ir_node *op1_node = get_irn_n(n, n_ia32_vFucomFnstsw_left);
+ ir_node *op2_node = get_irn_n(n, n_ia32_vFucomFnstsw_right);
const arch_register_t *op1 = x87_get_irn_register(sim, op1_node);
const arch_register_t *op2 = x87_get_irn_register(sim, op2_node);
int reg_index_1 = arch_register_get_index(op1);
int reg_index_2 = arch_register_get_index(op2);
unsigned live = vfp_live_args_after(sim, n, 0);
+ int flipped = attr->attr.data.cmp_flipped;
+ int xchg = 0;
DB((dbg, LEVEL_1, ">>> %+F %s, %s\n", n,
arch_register_get_name(op1), arch_register_get_name(op2)));
if (op1_idx == 0) {
/* res = tos X op */
- dst = op_ia32_fcomJmp;
+ dst = op_ia32_FucomFnstsw;
} else if (op2_idx == 0) {
/* res = op X tos */
- dst = op_ia32_fcomrJmp;
+ dst = op_ia32_FucomFnstsw;
+ flipped = !flipped;
+ xchg = 1;
} else {
/* bring the first one to tos */
x87_create_fxch(state, n, op1_idx);
op2_idx = op1_idx;
op1_idx = 0;
/* res = tos X op */
- dst = op_ia32_fcomJmp;
+ dst = op_ia32_FucomFnstsw;
}
} else {
/* second live, first operand is dead here, bring it to tos.
op1_idx = 0;
}
/* res = tos X op, pop */
- dst = op_ia32_fcompJmp;
+ dst = op_ia32_FucompFnstsw;
pop_cnt = 1;
}
} else {
op2_idx = 0;
}
/* res = op X tos, pop */
- dst = op_ia32_fcomrpJmp;
+ dst = op_ia32_FucompFnstsw;
+ flipped = !flipped;
+ xchg = 1;
pop_cnt = 1;
} else {
/* both operands are dead here, check first for identity. */
op2_idx = 0;
}
/* res = tos X op, pop */
- dst = op_ia32_fcompJmp;
+ dst = op_ia32_FucompFnstsw;
pop_cnt = 1;
}
/* different, move them to st and st(1) and pop both.
op1_idx = 0;
}
/* res = tos X op, pop, pop */
- dst = op_ia32_fcomppJmp;
+ dst = op_ia32_FucomppFnstsw;
pop_cnt = 2;
} else if (op1_idx == 1) {
/* good, first operand is already in the right place, move the second */
assert(op1_idx != 0);
op2_idx = 0;
}
- dst = op_ia32_fcomrppJmp;
+ /* res = op X tos, pop, pop */
+ dst = op_ia32_FucomppFnstsw;
+ flipped = !flipped;
+ xchg = 1;
pop_cnt = 2;
} else {
/* if one is already the TOS, we need two fxch */
x87_create_fxch(state, n, op2_idx);
op2_idx = 0;
/* res = op X tos, pop, pop */
- dst = op_ia32_fcomrppJmp;
+ dst = op_ia32_FucomppFnstsw;
+ flipped = !flipped;
+ xchg = 1;
pop_cnt = 2;
} else if (op2_idx == 0) {
/* second one is TOS, move to st(1) */
x87_create_fxch(state, n, op1_idx);
op1_idx = 0;
/* res = tos X op, pop, pop */
- dst = op_ia32_fcomppJmp;
+ dst = op_ia32_FucomppFnstsw;
pop_cnt = 2;
} else {
/* none of them is either TOS or st(1), 3 fxch needed */
x87_create_fxch(state, n, op1_idx);
op1_idx = 0;
/* res = tos X op, pop, pop */
- dst = op_ia32_fcomppJmp;
+ dst = op_ia32_FucomppFnstsw;
pop_cnt = 2;
}
}
x87_create_fxch(state, n, op1_idx);
op1_idx = 0;
}
- dst = op_ia32_fcomJmp;
+ dst = op_ia32_FucomFnstsw;
} else {
/* first operand is dead: bring it to tos */
if (op1_idx != 0) {
x87_create_fxch(state, n, op1_idx);
op1_idx = 0;
}
- dst = op_ia32_fcompJmp;
+ dst = op_ia32_FucompFnstsw;
pop_cnt = 1;
}
}
if (pop_cnt >= 1)
x87_pop(state);
+ if(xchg) {
+ int tmp = op1_idx;
+ op1_idx = op2_idx;
+ op2_idx = tmp;
+ }
+
/* patch the operation */
- attr = get_ia32_x87_attr(n);
op1 = &ia32_st_regs[op1_idx];
attr->x87[0] = op1;
if (op2_idx >= 0) {
attr->x87[1] = op2;
}
attr->x87[2] = NULL;
+ attr->attr.data.cmp_flipped = flipped;
if (op2_idx >= 0)
DB((dbg, LEVEL_1, "<<< %s %s, %s\n", get_irn_opname(n),
arch_register_get_name(op1)));
return NO_NODE_ADDED;
-} /* sim_fCondJmp */
+}
-static
-int sim_Keep(x87_state *state, ir_node *node)
+static int sim_Keep(x87_state *state, ir_node *node)
{
const ir_node *op;
const arch_register_t *op_reg;
DEBUG_ONLY(vfp_dump_live(live));
DEBUG_ONLY(x87_dump_stack(state));
+ if (kill_mask != 0 && live == 0) {
+ int cpu = sim->isa->arch;
+
+ /* special case: kill all registers */
+ if (ARCH_ATHLON(sim->isa->opt_arch) && ARCH_MMX(cpu)) {
+ if (ARCH_AMD(cpu)) {
+ /* use FEMMS on AMD processors to clear all */
+ keep = new_rd_ia32_femms(NULL, get_irn_irg(block), block, mode_E);
+ } else {
+ /* use EMMS to clear all */
+ keep = new_rd_ia32_emms(NULL, get_irn_irg(block), block, mode_E);
+ }
+ sched_add_before(first_insn, keep);
+ keep_alive(keep);
+ x87_emms(state);
+ return state;
+ }
+ }
/* now kill registers */
while (kill_mask) {
/* we can only kill from TOS, so bring them up */
sim->arch_env = arch_env;
sim->n_idx = get_irg_last_idx(irg);
sim->live = obstack_alloc(&sim->obst, sizeof(*sim->live) * sim->n_idx);
+ sim->isa = (ia32_isa_t *)arch_env->isa;
DB((dbg, LEVEL_1, "--------------------------------\n"
"x87 Simulator started for %+F\n", irg));
ASSOC_IA32(fchs);
ASSOC_IA32(fist);
ASSOC_IA32(fst);
- ASSOC_IA32(fCmpJmp);
+ ASSOC_IA32(FucomFnstsw);
ASSOC_BE(Copy);
ASSOC_BE(Call);
ASSOC_BE(Spill);