static x87_state *empty = (x87_state *)&_empty;
/** The type of an instruction simulator function. */
-typedef int (*sim_func)(x87_state *state, ir_node *n, const arch_env_t *env);
+typedef int (*sim_func)(x87_state *state, ir_node *n);
/**
* A block state: Every block has a x87 state at the beginning and at the end.
#define PTR_TO_BLKSTATE(p) ((blk_state *)(p))
+/** liveness bitset for vfp registers. */
+typedef unsigned char vfp_liveness;
+
/**
* The x87 simulator.
*/
struct _x87_simulator {
- struct obstack obst; /**< an obstack for fast allocating */
- pmap *blk_states; /**< map blocks to states */
- const arch_env_t *env; /**< architecture environment */
- unsigned char *live; /**< Liveness information. */
- unsigned n_idx; /**< cached get_irg_last_idx() result */
+ struct obstack obst; /**< An obstack for fast allocating. */
+ pmap *blk_states; /**< Map blocks to states. */
+ const arch_env_t *env; /**< The architecture environment. */
+ be_lv_t *lv; /**< intrablock liveness. */
+ vfp_liveness *live; /**< Liveness information. */
+ unsigned n_idx; /**< The cached get_irg_last_idx() result. */
+ waitq *worklist; /**< list of blocks to process. */
};
/**
state->st[MASK_TOS(state->tos + pos)].reg_idx = reg_idx;
state->st[MASK_TOS(state->tos + pos)].node = node;
- DB((dbg, LEVEL_2, "After SET_REG:\n ")); DEBUG_ONLY(x87_dump_stack(state));
+ DB((dbg, LEVEL_2, "After SET_REG: "));
+ DEBUG_ONLY(x87_dump_stack(state));
} /* x87_set_st */
/**
x87_set_st(state, reg_idx, node, 0);
} /* x87_set_tos */
+#if 0
/**
* Flush the x87 stack.
*
state->depth = 0;
state->tos = 0;
} /* x87_flush */
+#endif
/**
* Swap st(0) with st(pos).
state->st[MASK_TOS(state->tos + pos)] = state->st[MASK_TOS(state->tos)];
state->st[MASK_TOS(state->tos)] = entry;
- DB((dbg, LEVEL_2, "After FXCH:\n ")); DEBUG_ONLY(x87_dump_stack(state));
+ DB((dbg, LEVEL_2, "After FXCH: ")); DEBUG_ONLY(x87_dump_stack(state));
} /* x87_fxch */
/**
state->st[state->tos].reg_idx = reg_idx;
state->st[state->tos].node = node;
- DB((dbg, LEVEL_2, "After PUSH:\n ")); DEBUG_ONLY(x87_dump_stack(state));
+ DB((dbg, LEVEL_2, "After PUSH: ")); DEBUG_ONLY(x87_dump_stack(state));
} /* x87_push_dbl */
/**
--state->depth;
state->tos = MASK_TOS(state->tos + 1);
- DB((dbg, LEVEL_2, "After POP:\n ")); DEBUG_ONLY(x87_dump_stack(state));
+ DB((dbg, LEVEL_2, "After POP: ")); DEBUG_ONLY(x87_dump_stack(state));
} /* x87_pop */
/**
return res;
} /* x87_alloc_state */
+#if 0
/**
* Create a new empty x87 state.
*
x87_flush(res);
return res;
} /* x87_alloc_empty_state */
+#endif
/**
* Clone a x87 state.
return NULL;
} /* get_irn_Proj_for_mode */
+/**
+ * Wrap the arch_* function here so we can check for errors.
+ */
+static INLINE const arch_register_t *x87_get_irn_register(x87_simulator *sim, const ir_node *irn) {
+ const arch_register_t *res;
+
+ res = arch_get_irn_register(sim->env, irn);
+ assert(res->reg_class->regs == ia32_vfp_regs);
+ return res;
+}
+
/* -------------- x87 perm --------------- */
/**
*
* @param state the x87 state
* @param pos parameter for fxch
- * @param dst_block the block of the user
+ * @param block the block were fxch is inserted
*
* Creates a new fxch node and reroute the user of the old node
* to the fxch.
*
* @return the fxch node
*/
-static ir_node *x87_fxch_shuffle(x87_state *state, int pos, ir_node *block, ir_node *dst_block)
+static ir_node *x87_fxch_shuffle(x87_state *state, int pos, ir_node *block)
{
- const ir_edge_t *edge;
- ir_node *n = x87_get_st_node(state, pos);
- ir_node *user = NULL;
- ir_node *fxch;
- int node_idx;
- ia32_attr_t *attr;
-
- if (block == get_nodes_block(n)) {
- /* this is a node from out block: change it's user */
- foreach_out_edge(n, edge) {
- ir_node *succ = get_edge_src_irn(edge);
-
- if (is_Phi(succ) && get_nodes_block(succ) == dst_block) {
- user = succ;
- node_idx = get_edge_src_pos(edge);
- break;
- }
- }
- assert(user);
- }
+ ir_node *fxch;
+ ia32_attr_t *attr;
- fxch = new_rd_ia32_fxch(NULL, get_irn_irg(block), block, n, get_irn_mode(n));
+ fxch = new_rd_ia32_fxch(NULL, get_irn_irg(block), block, mode_E);
attr = get_ia32_attr(fxch);
attr->x87[0] = &ia32_st_regs[pos];
attr->x87[2] = &ia32_st_regs[0];
- if (user) {
- DB((dbg, LEVEL_2, "%+F replaced input %d of %+F\n", fxch, node_idx, user));
- set_irn_n(user, node_idx, fxch);
- }
- else {
- /*
- * This is a node from a dominator block. Changing it's user might be wrong,
- * so just keep it alive.
- * The "right" solution would require a new Phi, but we don't care here.
- */
- keep_alive(fxch);
- }
+ keep_alive(fxch);
x87_fxch(state, pos);
return fxch;
* @return state
*/
static x87_state *x87_shuffle(x87_simulator *sim, ir_node *block, x87_state *state, ir_node *dst_block, const x87_state *dst_state) {
- int i, n_cycles, k, ri;
+ int i, n_cycles, k, ri;
unsigned cycles[4], all_mask;
- char cycle_idx[4][8];
- ir_node *fxch;
- ir_node *before, *after;
+ char cycle_idx[4][8];
+ ir_node *fxch, *before, *after;
assert(state->depth == dst_state->depth);
for (ri = 0; ri < n_cycles; ++ri) {
if ((cycles[ri] & 1) == 0) {
/* this cycle does not include the tos */
- fxch = x87_fxch_shuffle(state, cycle_idx[ri][0], block, dst_block);
+ fxch = x87_fxch_shuffle(state, cycle_idx[ri][0], block);
if (after)
sched_add_after(after, fxch);
else
after = fxch;
}
for (k = 1; cycle_idx[ri][k] != -1; ++k) {
- fxch = x87_fxch_shuffle(state, cycle_idx[ri][k], block, dst_block);
+ fxch = x87_fxch_shuffle(state, cycle_idx[ri][k], block);
if (after)
sched_add_after(after, fxch);
else
}
if ((cycles[ri] & 1) == 0) {
/* this cycle does not include the tos */
- fxch = x87_fxch_shuffle(state, cycle_idx[ri][0], block, dst_block);
+ fxch = x87_fxch_shuffle(state, cycle_idx[ri][0], block);
sched_add_after(after, fxch);
}
}
* Create a fxch node before another node.
*
* @param state the x87 state
- * @param n the node before the fxch
+ * @param n the node after the fxch
* @param pos exchange st(pos) with st(0)
* @param op_idx if >= 0, replace input op_idx of n with the fxch result
*
* @return the fxch
*/
static ir_node *x87_create_fxch(x87_state *state, ir_node *n, int pos, int op_idx) {
- ir_node *fxch, *pred;
+ ir_node *fxch;
ia32_attr_t *attr;
+ ir_graph *irg = get_irn_irg(n);
+ ir_node *block = get_nodes_block(n);
x87_fxch(state, pos);
- if (op_idx >= 0)
- pred = get_irn_n(n, op_idx);
- else
- pred = x87_get_st_node(state, pos);
-
- fxch = new_rd_ia32_fxch(NULL, get_irn_irg(n), get_nodes_block(n), pred, get_irn_mode(pred));
+ fxch = new_rd_ia32_fxch(NULL, irg, block, mode_E);
attr = get_ia32_attr(fxch);
attr->x87[0] = &ia32_st_regs[pos];
attr->x87[2] = &ia32_st_regs[0];
- if (op_idx >= 0)
- set_irn_n(n, op_idx, fxch);
+ keep_alive(fxch);
sched_add_before(n, fxch);
DB((dbg, LEVEL_1, "<<< %s %s, %s\n", get_irn_opname(fxch), attr->x87[0]->name, attr->x87[2]->name));
* Create a fpush before node n.
*
* @param state the x87 state
- * @param n the node before the fpush
+ * @param n the node after the fpush
* @param pos push st(pos) on stack
- * @param op_idx if >= 0, replace input op_idx of n with the fpush result
+ * @param op_idx replace input op_idx of n with the fpush result
*/
-static void x87_create_fpush(const arch_env_t *env, x87_state *state, ir_node *n, int pos, int op_idx) {
- ir_node *fpush, *pred = get_irn_n(n, op_idx);
- ia32_attr_t *attr;
- const arch_register_t *out = arch_get_irn_register(env, pred);
+static void x87_create_fpush(x87_state *state, ir_node *n, int pos, int op_idx) {
+ ir_node *fpush, *pred = get_irn_n(n, op_idx);
+ ia32_attr_t *attr;
+ const arch_register_t *out = x87_get_irn_register(state->sim, pred);
x87_push_dbl(state, arch_register_get_index(out), pred);
- fpush = new_rd_ia32_fpush(NULL, get_irn_irg(n), get_nodes_block(n), pred, get_irn_mode(pred));
+ fpush = new_rd_ia32_fpush(NULL, get_irn_irg(n), get_nodes_block(n), mode_E);
attr = get_ia32_attr(fpush);
attr->x87[0] = &ia32_st_regs[pos];
attr->x87[2] = &ia32_st_regs[0];
- if (op_idx >= 0)
- set_irn_n(n, op_idx, fpush);
+ keep_alive(fpush);
sched_add_before(n, fpush);
+
DB((dbg, LEVEL_1, "<<< %s %s, %s\n", get_irn_opname(fpush), attr->x87[0]->name, attr->x87[2]->name));
} /* x87_create_fpush */
* Create a fpop before node n.
*
* @param state the x87 state
- * @param n the node before the fpop
+ * @param n the node after the fpop
* @param num pop 1 or 2 values
* @param pred node to use as predecessor of the fpop
*
* @return the fpop node
*/
-static ir_node *x87_create_fpop(const arch_env_t *env, x87_state *state, ir_node *n, int num, ir_node *pred) {
- ir_node *fpop;
+static ir_node *x87_create_fpop(x87_state *state, ir_node *n, int num, ir_node *pred) {
+ ir_node *fpop = pred;
ia32_attr_t *attr;
while (num > 0) {
+ keep_alive(pred);
+
x87_pop(state);
fpop = new_rd_ia32_fpop(NULL, get_irn_irg(n), get_nodes_block(n), mode_E);
attr = get_ia32_attr(fpop);
* Updates a live set over a single step from a given node to its predecessor.
* Everything defined at the node is removed from the set, the uses of the node get inserted.
*
- * @param arch_env The architecture environment.
+ * @param sim The simulator handle.
* @param irn The node at which liveness should be computed.
* @param live The bitset of registers live before @p irn. This set gets modified by updating it to
* the registers live after irn.
*
* @return The live bitset.
*/
-static unsigned vfp_liveness_transfer(const arch_env_t *arch_env, ir_node *irn, unsigned live)
+static vfp_liveness vfp_liveness_transfer(x87_simulator *sim, ir_node *irn, vfp_liveness live)
{
int i, n;
const arch_register_class_t *cls = &ia32_reg_classes[CLASS_ia32_vfp];
+ const arch_env_t *arch_env = sim->env;
if (arch_irn_consider_in_reg_alloc(arch_env, cls, irn)) {
- const arch_register_t *reg = arch_get_irn_register(arch_env, irn);
- live &= ~(1 << reg->index);
+ const arch_register_t *reg = x87_get_irn_register(sim, irn);
+ live &= ~(1 << arch_register_get_index(reg));
}
for (i = 0, n = get_irn_arity(irn); i < n; ++i) {
ir_node *op = get_irn_n(irn, i);
if (mode_is_float(get_irn_mode(op)) && arch_irn_consider_in_reg_alloc(arch_env, cls, op)) {
- const arch_register_t *reg = arch_get_irn_register(arch_env, op);
- live |= 1 << reg->index;
+ const arch_register_t *reg = x87_get_irn_register(sim, op);
+ live |= 1 << arch_register_get_index(reg);
}
}
return live;
/**
* Put all live virtual registers at the end of a block into a bitset.
*
- * @param env the architecture environment
+ * @param sim the simulator handle
* @param lv the liveness information
* @param bl the block
*
* @return The live bitset at the end of this block
*/
-static unsigned vfp_liveness_end_of_block(const arch_env_t *env, be_lv_t *lv, const ir_node *bl)
+static vfp_liveness vfp_liveness_end_of_block(x87_simulator *sim, const ir_node *block)
{
int i;
- unsigned live = 0;
+ vfp_liveness live = 0;
const arch_register_class_t *cls = &ia32_reg_classes[CLASS_ia32_vfp];
+ const arch_env_t *arch_env = sim->env;
+ const be_lv_t *lv = sim->lv;
- be_lv_foreach(lv, bl, be_lv_state_end, i) {
- ir_node *irn = be_lv_get_irn(lv, bl, i);
- if (arch_irn_consider_in_reg_alloc(env, cls, irn)) {
- const arch_register_t *reg = arch_get_irn_register(env, irn);
- live |= 1 << reg->index;
- }
+ be_lv_foreach(lv, block, be_lv_state_end, i) {
+ const arch_register_t *reg;
+ const ir_node *node = be_lv_get_irn(lv, block, i);
+ if (!arch_irn_consider_in_reg_alloc(arch_env, cls, node))
+ continue;
+
+ reg = x87_get_irn_register(sim, node);
+ live |= 1 << arch_register_get_index(reg);
}
return live;
} /* vfp_liveness_end_of_block */
/** get the register mask from an arch_register */
-#define REGMASK(reg) (1 << (reg)->index)
+#define REGMASK(reg) (1 << (arch_register_get_index(reg)))
/**
* Return a bitset of argument registers which are live at the end of a node.
/**
* Calculate the liveness for a whole block and cache it.
*
- * @param sim the simulator handle
- * @param lv the liveness handle
- * @param blk the block
+ * @param sim the simulator handle
+ * @param lv the liveness handle
+ * @param block the block
*/
-static void update_liveness(x87_simulator *sim, be_lv_t *lv, ir_node *blk) {
- unsigned live = vfp_liveness_end_of_block(sim->env, lv, blk);
+static void update_liveness(x87_simulator *sim, ir_node *block) {
+ vfp_liveness live = vfp_liveness_end_of_block(sim, block);
unsigned idx;
ir_node *irn;
/* now iterate through the block backward and cache the results */
- sched_foreach_reverse(blk, irn) {
+ sched_foreach_reverse(block, irn) {
/* stop at the first Phi: this produces the live-in */
if (is_Phi(irn))
break;
idx = get_irn_idx(irn);
sim->live[idx] = live;
- live = vfp_liveness_transfer(sim->env, irn, live);
+ live = vfp_liveness_transfer(sim, irn, live);
}
- idx = get_irn_idx(blk);
+ idx = get_irn_idx(block);
sim->live[idx] = live;
} /* update_liveness */
*
* @param live the live bitset
*/
-static void vfp_dump_live(unsigned live) {
+static void vfp_dump_live(vfp_liveness live) {
int i;
- DB((dbg, LEVEL_2, "Live registers here: \n"));
+ DB((dbg, LEVEL_2, "Live after: "));
for (i = 0; i < 8; ++i) {
if (live & (1 << i)) {
- DB((dbg, LEVEL_2, " vf%d", i));
+ DB((dbg, LEVEL_2, "vf%d ", i));
}
}
DB((dbg, LEVEL_2, "\n"));
*
* @param state the x87 state
* @param n the node that should be simulated (and patched)
- * @param env the architecture environment
* @param tmpl the template containing the 4 possible x87 opcodes
*/
-static int sim_binop(x87_state *state, ir_node *n, const arch_env_t *env, const exchange_tmpl *tmpl) {
- int op2_idx, op1_idx = -1;
- int out_idx, do_pop =0;
+static int sim_binop(x87_state *state, ir_node *n, const exchange_tmpl *tmpl) {
+ int op2_idx, op1_idx;
+ int out_idx, do_pop = 0;
ia32_attr_t *attr;
ir_op *dst;
- const arch_register_t *op1 = arch_get_irn_register(env, get_irn_n(n, BINOP_IDX_1));
- const arch_register_t *op2 = arch_get_irn_register(env, get_irn_n(n, BINOP_IDX_2));
- const arch_register_t *out = arch_get_irn_register(env, n);
- unsigned live = vfp_live_args_after(state->sim, n, REGMASK(out));
+ x87_simulator *sim = state->sim;
+ const arch_register_t *op1 = x87_get_irn_register(sim, get_irn_n(n, BINOP_IDX_1));
+ const arch_register_t *op2 = x87_get_irn_register(sim, get_irn_n(n, BINOP_IDX_2));
+ const arch_register_t *out = x87_get_irn_register(sim, n);
+ int reg_index_1 = arch_register_get_index(op1);
+ int reg_index_2 = arch_register_get_index(op2);
+ vfp_liveness live = vfp_live_args_after(sim, n, REGMASK(out));
DB((dbg, LEVEL_1, ">>> %+F %s, %s -> %s\n", n,
arch_register_get_name(op1), arch_register_get_name(op2),
arch_register_get_name(out)));
DEBUG_ONLY(vfp_dump_live(live));
+ DB((dbg, LEVEL_1, "Stack before: "));
+ DEBUG_ONLY(x87_dump_stack(state));
- op1_idx = x87_on_stack(state, arch_register_get_index(op1));
- op2_idx = x87_on_stack(state, arch_register_get_index(op2));
+ op1_idx = x87_on_stack(state, reg_index_1);
+ assert(op1_idx >= 0);
- if (op2->index != REG_VFP_NOREG) {
+ if (reg_index_2 != REG_VFP_NOREG) {
/* second operand is a vfp register */
+ op2_idx = x87_on_stack(state, reg_index_2);
+ assert(op2_idx >= 0);
- if (is_vfp_live(op2->index, live)) {
+ if (is_vfp_live(arch_register_get_index(op2), live)) {
/* Second operand is live. */
- if (is_vfp_live(op1->index, live)) {
+ if (is_vfp_live(arch_register_get_index(op1), live)) {
/* Both operands are live: push the first one.
This works even for op1 == op2. */
- x87_create_fpush(env, state, n, op2_idx, BINOP_IDX_2);
- out_idx = op2_idx = 0;
- ++op1_idx;
+ x87_create_fpush(state, n, op1_idx, BINOP_IDX_2);
+ /* now do fxxx (tos=tos X op) */
+ op1_idx = 0;
+ op2_idx += 1;
+ out_idx = 0;
dst = tmpl->normal_op;
- do_pop = 0;
- }
- else {
+ } else {
/* Second live, first operand is dead here, bring it to tos. */
if (op1_idx != 0) {
x87_create_fxch(state, n, op1_idx, BINOP_IDX_1);
if (op2_idx == 0)
op2_idx = op1_idx;
+ op1_idx = 0;
}
- op1_idx = out_idx = 0;
+ /* now do fxxx (tos=tos X op) */
+ out_idx = 0;
dst = tmpl->normal_op;
- do_pop = 0;
}
}
else {
/* Second operand is dead. */
- if (is_vfp_live(op1->index, live)) {
+ if (is_vfp_live(arch_register_get_index(op1), live)) {
/* First operand is live: bring second to tos. */
if (op2_idx != 0) {
x87_create_fxch(state, n, op2_idx, BINOP_IDX_2);
if (op1_idx == 0)
op1_idx = op2_idx;
+ op2_idx = 0;
}
- op2_idx = out_idx = 0;
+ /* now do fxxxr (tos = op X tos) */
+ out_idx = 0;
dst = tmpl->reverse_op;
- do_pop = 0;
}
else {
/* Both operands are dead here, pop them from the stack. */
if (op2_idx == 0) {
- out_idx = op1_idx;
- if (op1_idx == op2_idx) {
- /* Both are identically, no pop needed. */
+ if (op1_idx == 0) {
+ /* Both are identically and on tos, no pop needed. */
+ /* here fxxx (tos = tos X tos) */
dst = tmpl->normal_op;
- do_pop = 0;
+ out_idx = 0;
}
else {
+ /* now do fxxxp (op = op X tos, pop) */
dst = tmpl->normal_pop_op;
do_pop = 1;
+ out_idx = op1_idx;
}
}
else if (op1_idx == 0) {
+ assert(op1_idx != op2_idx);
+ /* now do fxxxrp (op = tos X op, pop) */
+ dst = tmpl->reverse_pop_op;
+ do_pop = 1;
out_idx = op2_idx;
- XCHG(op2_idx, op1_idx);
- if (op1_idx == op2_idx) {
- /* Both are identically, no pop needed. */
- dst = tmpl->reverse_op;
- do_pop = 0;
- }
- else {
- dst = tmpl->reverse_pop_op;
- do_pop = 1;
- }
}
else {
/* Bring the second on top. */
x87_create_fxch(state, n, op2_idx, BINOP_IDX_2);
if (op1_idx == op2_idx) {
- /* Both are identically, no pop needed. */
- out_idx = op1_idx = op2_idx = 0;
+ /* Both are identically and on tos now, no pop needed. */
+ op1_idx = 0;
+ op2_idx = 0;
+ /* use fxxx (tos = tos X tos) */
dst = tmpl->normal_op;
- do_pop = 0;
+ out_idx = 0;
}
else {
+ /* op2 is on tos now */
op2_idx = 0;
- out_idx = op1_idx;
+ /* use fxxxp (op = op X tos, pop) */
dst = tmpl->normal_pop_op;
+ out_idx = op1_idx;
do_pop = 1;
}
}
}
else {
/* second operand is an address mode */
- if (is_vfp_live(op1->index, live)) {
+ if (is_vfp_live(arch_register_get_index(op1), live)) {
/* first operand is live: push it here */
- x87_create_fpush(env, state, n, op1_idx, BINOP_IDX_1);
+ x87_create_fpush(state, n, op1_idx, BINOP_IDX_1);
+ op1_idx = 0;
+ /* use fxxx (tos = tos X mem) */
+ dst = tmpl->normal_op;
+ out_idx = 0;
}
else {
/* first operand is dead: bring it to tos */
- if (op1_idx != 0)
+ if (op1_idx != 0) {
x87_create_fxch(state, n, op1_idx, BINOP_IDX_1);
+ op1_idx = 0;
+ }
+
+ /* use fxxxp (tos = tos X mem) */
+ dst = tmpl->normal_op;
+ out_idx = 0;
}
- op1_idx = out_idx = 0;
- dst = tmpl->normal_op;
- do_pop = 0;
}
- x87_set_st(state, out->index, x87_patch_insn(n, dst), out_idx);
- if (do_pop)
+ x87_set_st(state, arch_register_get_index(out), x87_patch_insn(n, dst), out_idx);
+ if (do_pop) {
x87_pop(state);
+ }
/* patch the operation */
attr = get_ia32_attr(n);
attr->x87[0] = op1 = &ia32_st_regs[op1_idx];
- if (op2_idx >= 0)
+ if (reg_index_2 != REG_VFP_NOREG) {
attr->x87[1] = op2 = &ia32_st_regs[op2_idx];
+ }
attr->x87[2] = out = &ia32_st_regs[out_idx];
- if (op2_idx >= 0)
+ if (reg_index_2 != REG_VFP_NOREG) {
DB((dbg, LEVEL_1, "<<< %s %s, %s -> %s\n", get_irn_opname(n),
arch_register_get_name(op1), arch_register_get_name(op2),
arch_register_get_name(out)));
- else
+ } else {
DB((dbg, LEVEL_1, "<<< %s %s, [AM] -> %s\n", get_irn_opname(n),
arch_register_get_name(op1),
arch_register_get_name(out)));
+ }
return 0;
} /* sim_binop */
*
* @param state the x87 state
* @param n the node that should be simulated (and patched)
- * @param env the architecture environment
* @param op the x87 opcode that will replace n's opcode
*/
-static int sim_unop(x87_state *state, ir_node *n, const arch_env_t *env, ir_op *op) {
+static int sim_unop(x87_state *state, ir_node *n, ir_op *op) {
int op1_idx, out_idx;
- const arch_register_t *op1 = arch_get_irn_register(env, get_irn_n(n, UNOP_IDX));
- const arch_register_t *out = arch_get_irn_register(env, n);
+ x87_simulator *sim = state->sim;
+ const arch_register_t *op1 = x87_get_irn_register(sim, get_irn_n(n, UNOP_IDX));
+ const arch_register_t *out = x87_get_irn_register(sim, n);
ia32_attr_t *attr;
- unsigned live = vfp_live_args_after(state->sim, n, REGMASK(out));
+ unsigned live = vfp_live_args_after(sim, n, REGMASK(out));
DB((dbg, LEVEL_1, ">>> %+F -> %s\n", n, out->name));
DEBUG_ONLY(vfp_dump_live(live));
op1_idx = x87_on_stack(state, arch_register_get_index(op1));
- if (is_vfp_live(op1->index, live)) {
+ if (is_vfp_live(arch_register_get_index(op1), live)) {
/* push the operand here */
- x87_create_fpush(env, state, n, op1_idx, UNOP_IDX);
+ x87_create_fpush(state, n, op1_idx, UNOP_IDX);
+ op1_idx = 0;
}
else {
/* operand is dead, bring it to tos */
- if (op1_idx != 0)
+ if (op1_idx != 0) {
x87_create_fxch(state, n, op1_idx, UNOP_IDX);
+ op1_idx = 0;
+ }
}
x87_set_tos(state, arch_register_get_index(out), x87_patch_insn(n, op));
- op1_idx = out_idx = 0;
+ out_idx = 0;
attr = get_ia32_attr(n);
attr->x87[0] = op1 = &ia32_st_regs[0];
attr->x87[2] = out = &ia32_st_regs[0];
*
* @param state the x87 state
* @param n the node that should be simulated (and patched)
- * @param env the architecture environment
* @param op the x87 opcode that will replace n's opcode
*/
-static int sim_load(x87_state *state, ir_node *n, const arch_env_t *env, ir_op *op) {
- const arch_register_t *out = arch_get_irn_register(env, n);
+static int sim_load(x87_state *state, ir_node *n, ir_op *op) {
+ const arch_register_t *out = x87_get_irn_register(state->sim, n);
ia32_attr_t *attr;
DB((dbg, LEVEL_1, ">>> %+F -> %s\n", n, arch_register_get_name(out)));
x87_push(state, arch_register_get_index(out), x87_patch_insn(n, op));
+ assert(out == x87_get_irn_register(state->sim, n));
attr = get_ia32_attr(n);
attr->x87[2] = out = &ia32_st_regs[0];
DB((dbg, LEVEL_1, "<<< %s -> %s\n", get_irn_opname(n), arch_register_get_name(out)));
*
* @param state the x87 state
* @param n the node that should be simulated (and patched)
- * @param env the architecture environment
* @param op the x87 store opcode
* @param op_p the x87 store and pop opcode
*/
-static int sim_store(x87_state *state, ir_node *n, const arch_env_t *env, ir_op *op, ir_op *op_p) {
+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);
- const arch_register_t *op2 = arch_get_irn_register(env, val);
- unsigned live = vfp_live_args_after(state->sim, n, 0);
+ const arch_register_t *op2 = x87_get_irn_register(sim, val);
+ unsigned live = vfp_live_args_after(sim, n, 0);
int insn = 0;
ia32_attr_t *attr;
int op2_idx, depth;
mode = get_ia32_ls_mode(n);
depth = x87_get_depth(state);
- /*
- We can only store the tos to memory.
- A store of mode_E with free registers
- pushes value to tos, so skip it here.
- */
- if (! (mode == mode_E && depth < N_x87_REGS) && op2_idx != 0)
- x87_create_fxch(state, n, op2_idx, STORE_VAL_IDX);
-
- if (is_vfp_live(op2->index, live)) {
+ if (is_vfp_live(arch_register_get_index(op2), live)) {
/*
Problem: fst doesn't support mode_E (spills), only fstp does
Solution:
if (mode == mode_E) {
if (depth < N_x87_REGS) {
/* ok, we have a free register: push + fstp */
- x87_create_fpush(env, state, n, op2_idx, STORE_VAL_IDX);
+ x87_create_fpush(state, n, op2_idx, STORE_VAL_IDX);
x87_pop(state);
x87_patch_insn(n, op_p);
}
assert(mem && "Store memory not found");
- arch_set_irn_register(env, rproj, op2);
+ arch_set_irn_register(sim->env, rproj, op2);
/* reroute all former users of the store memory to the load memory */
edges_reroute(mem, mproj, irg);
}
}
else {
+ /* we can only store the tos to memory */
+ if(op2_idx != 0)
+ x87_create_fxch(state, n, op2_idx, STORE_VAL_IDX);
+
/* mode != mode_E -> use normal fst */
x87_patch_insn(n, op);
}
}
else {
+ /* we can only store the tos to memory */
+ if(op2_idx != 0)
+ x87_create_fxch(state, n, op2_idx, STORE_VAL_IDX);
+
x87_pop(state);
x87_patch_insn(n, op_p);
}
#define _GEN_BINOP(op, rev) \
-static int sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
+static int sim_##op(x87_state *state, ir_node *n) { \
exchange_tmpl tmpl = { op_ia32_##op, op_ia32_##rev, op_ia32_##op##p, op_ia32_##rev##p }; \
- return sim_binop(state, n, env, &tmpl); \
+ return sim_binop(state, n, &tmpl); \
}
#define GEN_BINOP(op) _GEN_BINOP(op, op)
#define GEN_BINOPR(op) _GEN_BINOP(op, op##r)
#define GEN_LOAD2(op, nop) \
-static int sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
- return sim_load(state, n, env, op_ia32_##nop); \
+static int sim_##op(x87_state *state, ir_node *n) { \
+ return sim_load(state, n, op_ia32_##nop); \
}
#define GEN_LOAD(op) GEN_LOAD2(op, op)
#define GEN_UNOP(op) \
-static int sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
- return sim_unop(state, n, env, op_ia32_##op); \
+static int sim_##op(x87_state *state, ir_node *n) { \
+ return sim_unop(state, n, op_ia32_##op); \
}
#define GEN_STORE(op) \
-static int sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
- return sim_store(state, n, env, op_ia32_##op, op_ia32_##op##p); \
+static int sim_##op(x87_state *state, ir_node *n) { \
+ return sim_store(state, n, op_ia32_##op, op_ia32_##op##p); \
}
/* all stubs */
GEN_BINOPR(fsub)
GEN_BINOP(fmul)
GEN_BINOPR(fdiv)
+GEN_BINOP(fprem)
GEN_UNOP(fabs)
GEN_UNOP(fchs)
*
* @param state the x87 state
* @param n the node that should be simulated (and patched)
- * @param env the architecture environment
*/
-static int sim_fCondJmp(x87_state *state, ir_node *n, const arch_env_t *env) {
- int op2_idx, op1_idx = -1, pop_cnt = 0;
+static int sim_fCondJmp(x87_state *state, ir_node *n) {
+ int op1_idx;
+ int op2_idx = -1;
+ int pop_cnt = 0;
ia32_attr_t *attr;
ir_op *dst;
- const arch_register_t *op1 = arch_get_irn_register(env, get_irn_n(n, BINOP_IDX_1));
- const arch_register_t *op2 = arch_get_irn_register(env, get_irn_n(n, BINOP_IDX_2));
- unsigned live = vfp_live_args_after(state->sim, n, 0);
+ x87_simulator *sim = state->sim;
+ const arch_register_t *op1 = x87_get_irn_register(sim, get_irn_n(n, BINOP_IDX_1));
+ const arch_register_t *op2 = x87_get_irn_register(sim, get_irn_n(n, BINOP_IDX_2));
+ 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);
DB((dbg, LEVEL_1, ">>> %+F %s, %s\n", n,
arch_register_get_name(op1), arch_register_get_name(op2)));
DEBUG_ONLY(vfp_dump_live(live));
+ DB((dbg, LEVEL_1, "Stack before: "));
+ DEBUG_ONLY(x87_dump_stack(state));
- op1_idx = x87_on_stack(state, op1->index);
- op2_idx = x87_on_stack(state, op2->index);
+ op1_idx = x87_on_stack(state, reg_index_1);
+ assert(op1_idx >= 0);
/* BEWARE: check for comp a,a cases, they might happen */
- if (op2->index != REG_VFP_NOREG) {
+ if (reg_index_2 != REG_VFP_NOREG) {
/* second operand is a vfp register */
+ op2_idx = x87_on_stack(state, reg_index_2);
+ assert(op2_idx >= 0);
- if (is_vfp_live(op2->index, live)) {
+ if (is_vfp_live(arch_register_get_index(op2), live)) {
/* second operand is live */
- if (is_vfp_live(op1->index, live)) {
- /* both operands are live: move one of them to tos */
- if (op2_idx == 0) {
- XCHG(op2_idx, op1_idx);
- dst = op_ia32_fcomrJmp;
- }
- else if (op1_idx == 0) {
+ if (is_vfp_live(arch_register_get_index(op1), live)) {
+ /* both operands are live */
+
+ if (op1_idx == 0) {
dst = op_ia32_fcomJmp;
- }
- else {
- /* bring the first on top */
+ } else if (op2_idx == 0) {
+ dst = op_ia32_fcomrJmp;
+ } else {
+ /* bring the first one to tos */
x87_create_fxch(state, n, op1_idx, BINOP_IDX_1);
- if (op1_idx == op2_idx)
- op2_idx = 0;
+ if (op2_idx == 0)
+ op2_idx = op1_idx;
op1_idx = 0;
dst = op_ia32_fcomJmp;
}
else {
/* second live, first operand is dead here, bring it to tos.
This means further, op1_idx != op2_idx. */
+ assert(op1_idx != op2_idx);
if (op1_idx != 0) {
x87_create_fxch(state, n, op1_idx, BINOP_IDX_1);
if (op2_idx == 0)
op2_idx = op1_idx;
+ op1_idx = 0;
}
- op1_idx = 0;
dst = op_ia32_fcompJmp;
pop_cnt = 1;
}
}
else {
/* second operand is dead */
- if (is_vfp_live(op1->index, live)) {
+ if (is_vfp_live(arch_register_get_index(op1), live)) {
/* first operand is live: bring second to tos.
This means further, op1_idx != op2_idx. */
+ assert(op1_idx != op2_idx);
if (op2_idx != 0) {
x87_create_fxch(state, n, op2_idx, BINOP_IDX_2);
if (op1_idx == 0)
op1_idx = op2_idx;
+ op2_idx = 0;
}
- op2_idx = 0;
dst = op_ia32_fcomrpJmp;
pop_cnt = 1;
}
else {
/* both operands are dead here, check first for identity. */
if (op1_idx == op2_idx) {
- /* identically, one one needed */
+ /* identically, one pop needed */
if (op1_idx != 0) {
x87_create_fxch(state, n, op1_idx, BINOP_IDX_1);
- op1_idx = op2_idx = 0;
+ op1_idx = 0;
+ op2_idx = 0;
}
dst = op_ia32_fcompJmp;
pop_cnt = 1;
/* none of them is either TOS or st(1), 3 fxch needed */
x87_create_fxch(state, n, op2_idx, BINOP_IDX_2);
x87_create_fxch(state, n, 1, BINOP_IDX_2);
+ op2_idx = 1;
x87_create_fxch(state, n, op1_idx, BINOP_IDX_1);
op1_idx = 0;
- op2_idx = 1;
dst = op_ia32_fcomppJmp;
pop_cnt = 2;
}
}
else {
/* second operand is an address mode */
- if (is_vfp_live(op1->index, live)) {
+ if (is_vfp_live(arch_register_get_index(op1), live)) {
/* first operand is live: bring it to TOS */
if (op1_idx != 0) {
x87_create_fxch(state, n, op1_idx, BINOP_IDX_1);
x87_create_fxch(state, n, op1_idx, BINOP_IDX_1);
op1_idx = 0;
}
+ dst = op_ia32_fcompJmp;
+ pop_cnt = 1;
}
- dst = op_ia32_fcompJmp;
- pop_cnt = 1;
}
x87_patch_insn(n, dst);
- if (pop_cnt > 1)
+ assert(pop_cnt < 3);
+ if (pop_cnt >= 2)
x87_pop(state);
- if (pop_cnt > 0)
+ if (pop_cnt >= 1)
x87_pop(state);
/* patch the operation */
attr = get_ia32_attr(n);
- attr->x87[1] = op1 = &ia32_st_regs[op1_idx];
- if (op2_idx >= 0)
- attr->x87[2] = op2 = &ia32_st_regs[op2_idx];
+ op1 = &ia32_st_regs[op1_idx];
+ attr->x87[0] = op1;
+ if (op2_idx >= 0) {
+ op2 = &ia32_st_regs[op2_idx];
+ attr->x87[1] = op2;
+ }
+ attr->x87[2] = NULL;
if (op2_idx >= 0)
DB((dbg, LEVEL_1, "<<< %s %s, %s\n", get_irn_opname(n),
*
* @param state the x87 state
* @param n the node that should be simulated (and patched)
- * @param env the architecture environment
*/
-static int sim_Copy(x87_state *state, ir_node *n, const arch_env_t *env) {
+static int sim_Copy(x87_state *state, ir_node *n) {
ir_mode *mode = get_irn_mode(n);
if (mode_is_float(mode)) {
- const arch_register_t *op1 = arch_get_irn_register(env, get_irn_n(n, 0));
- const arch_register_t *out = arch_get_irn_register(env, n);
- ir_node *node, *next;
- ia32_attr_t *attr;
- int op1_idx, out_idx;
- unsigned live = vfp_live_args_after(state->sim, n, REGMASK(out));
+ x87_simulator *sim = state->sim;
+ ir_node *pred = get_irn_n(n, 0);
+ const arch_register_t *out = x87_get_irn_register(sim, n);
+ const arch_register_t *op1 = x87_get_irn_register(sim, pred);
+ ir_node *node, *next;
+ ia32_attr_t *attr;
+ int op1_idx, out_idx;
+ unsigned live = vfp_live_args_after(sim, n, REGMASK(out));
+ ir_node *(*cnstr)(dbg_info *, ir_graph *, ir_node *, ir_mode *);
+
+ DB((dbg, LEVEL_1, ">>> %+F %s -> %s\n", n,
+ arch_register_get_name(op1), arch_register_get_name(out)));
+ DEBUG_ONLY(vfp_dump_live(live));
+
+ /* Do not copy constants, recreate them. */
+ switch (get_ia32_irn_opcode(pred)) {
+ case iro_ia32_fldz:
+ cnstr = new_rd_ia32_fldz;
+ break;
+ case iro_ia32_fld1:
+ cnstr = new_rd_ia32_fld1;
+ break;
+ case iro_ia32_fldpi:
+ cnstr = new_rd_ia32_fldpi;
+ break;
+ case iro_ia32_fldl2e:
+ cnstr = new_rd_ia32_fldl2e;
+ break;
+ case iro_ia32_fldl2t:
+ cnstr = new_rd_ia32_fldl2t;
+ break;
+ case iro_ia32_fldlg2:
+ cnstr = new_rd_ia32_fldlg2;
+ break;
+ case iro_ia32_fldln2:
+ cnstr = new_rd_ia32_fldln2;
+ break;
+ default:
+ goto no_constant;
+ }
+
+ /* copy a constant */
+ node = (*cnstr)(get_irn_dbg_info(n), get_irn_irg(n), get_nodes_block(n), mode);
+ arch_set_irn_register(sim->env, node, out);
+
+ x87_push(state, arch_register_get_index(out), node);
+
+ attr = get_ia32_attr(node);
+ attr->x87[2] = out = &ia32_st_regs[0];
+
+ next = sched_next(n);
+ sched_remove(n);
+ exchange(n, node);
+ sched_add_before(next, node);
+ DB((dbg, LEVEL_1, ">>> %+F -> %s\n", node, arch_register_get_name(out)));
+ return 0;
+no_constant:
/* handle the infamous unknown value */
- if (op1->index == REG_VFP_UKNWN) {
+ if (arch_register_get_index(op1) == REG_VFP_UKNWN) {
/* This happens before Phi nodes */
if (x87_state_is_empty(state)) {
/* create some value */
x87_patch_insn(n, op_ia32_fldz);
attr = get_ia32_attr(n);
attr->x87[2] = out = &ia32_st_regs[0];
- DB((dbg, LEVEL_1, ">>> %+F -> %s\n", n, out->name));
+ DB((dbg, LEVEL_1, "<<< %+F -> %s\n", n,
+ arch_register_get_name(out)));
} else {
- /* just copy one */
- node = new_rd_ia32_fpush(get_irn_dbg_info(n), get_irn_irg(n), get_nodes_block(n), get_irn_n(n, 0), mode);
- arch_set_irn_register(env, node, out);
+ /* Just copy one. We need here an fpush that can hold a
+ a register, so use the fpushCopy. */
+ node = new_rd_ia32_fpushCopy(get_irn_dbg_info(n), get_irn_irg(n), get_nodes_block(n), get_irn_n(n, 0), mode);
+ arch_set_irn_register(sim->env, node, out);
x87_push(state, arch_register_get_index(out), node);
sched_remove(n);
exchange(n, node);
sched_add_before(next, node);
- DB((dbg, LEVEL_1, ">>> %+F %s -> %s\n", node, op1->name, out->name));
+ DB((dbg, LEVEL_1, "<<< %+F %s -> %s\n", node,
+ arch_register_get_name(op1),
+ arch_register_get_name(out)));
}
return 0;
}
op1_idx = x87_on_stack(state, arch_register_get_index(op1));
- DB((dbg, LEVEL_1, ">>> %+F %s -> %s\n", n,
- arch_register_get_name(op1), arch_register_get_name(out)));
- DEBUG_ONLY(vfp_dump_live(live));
-
- if (is_vfp_live(op1->index, live)) {
- /* operand is still live,a real copy */
- node = new_rd_ia32_fpush(get_irn_dbg_info(n), get_irn_irg(n), get_nodes_block(n), get_irn_n(n, 0), mode);
- arch_set_irn_register(env, node, out);
+ if (is_vfp_live(arch_register_get_index(op1), live)) {
+ /* Operand is still live,a real copy. We need here an fpush that can hold a
+ a register, so use the fpushCopy. */
+ node = new_rd_ia32_fpushCopy(get_irn_dbg_info(n), get_irn_irg(n), get_nodes_block(n), get_irn_n(n, 0), mode);
+ arch_set_irn_register(sim->env, node, out);
x87_push(state, arch_register_get_index(out), node);
}
}
}
-
return 0;
} /* sim_Copy */
*
* Should not happen, spills are lowered before x87 simulator see them.
*/
-static int sim_Spill(x87_state *state, ir_node *n, const arch_env_t *env) {
+static int sim_Spill(x87_state *state, ir_node *n) {
assert(0 && "Spill not lowered");
- return sim_fst(state, n, env);
+ return sim_fst(state, n);
} /* sim_Spill */
/**
*
* Should not happen, reloads are lowered before x87 simulator see them.
*/
-static int sim_Reload(x87_state *state, ir_node *n, const arch_env_t *env) {
+static int sim_Reload(x87_state *state, ir_node *n) {
assert(0 && "Reload not lowered");
- return sim_fld(state, n, env);
+ return sim_fld(state, n);
} /* sim_Reload */
/**
* @param n the node that should be simulated (and patched)
* @param env the architecture environment
*/
-static int sim_Return(x87_state *state, ir_node *n, const arch_env_t *env) {
+static int sim_Return(x87_state *state, ir_node *n) {
int n_res = be_Return_get_n_rets(n);
int i, n_float_res = 0;
*
* @param state the x87 state
* @param irn the node that should be simulated (and patched)
- * @param env the architecture environment
*/
-static int sim_Perm(x87_state *state, ir_node *irn, const arch_env_t *env) {
+static int sim_Perm(x87_state *state, ir_node *irn) {
int i, n;
+ x87_simulator *sim = state->sim;
ir_node *pred = get_irn_n(irn, 0);
int *stack_pos;
const ir_edge_t *edge;
/* collect old stack positions */
for (i = 0; i < n; ++i) {
- const arch_register_t *inreg = arch_get_irn_register(env, get_irn_n(irn, i));
- int idx = x87_on_stack(state, inreg->index);
+ const arch_register_t *inreg = x87_get_irn_register(sim, get_irn_n(irn, i));
+ int idx = x87_on_stack(state, arch_register_get_index(inreg));
assert(idx >= 0 && "Perm argument not on x87 stack");
/* now do the permutation */
foreach_out_edge(irn, edge) {
ir_node *proj = get_edge_src_irn(edge);
- const arch_register_t *out = arch_get_irn_register(env, proj);
+ const arch_register_t *out = x87_get_irn_register(sim, proj);
long num = get_Proj_proj(proj);
assert(0 <= num && num < n && "More Proj's than Perm inputs");
- x87_set_st(state, out->index, proj, stack_pos[(unsigned)num]);
+ x87_set_st(state, arch_register_get_index(out), proj, stack_pos[(unsigned)num]);
}
DB((dbg, LEVEL_1, "<<< %+F\n", irn));
depth -= num_pop;
kill_mask >>= num_pop;
- keep = x87_create_fpop(sim->env, state, first_insn, num_pop, keep);
+ keep = x87_create_fpop(state, first_insn, num_pop, keep);
}
- add_End_keepalive(get_irg_end(get_irn_irg(block)), keep);
+ keep_alive(keep);
}
return state;
} /* x87_kill_deads */
* @return non-zero if simulation is complete,
* zero if the simulation must be rerun
*/
-static int x87_simulate_block(x87_simulator *sim, ir_node *block) {
+static void x87_simulate_block(x87_simulator *sim, ir_node *block) {
ir_node *n, *next;
blk_state *bl_state = x87_get_bl_state(sim, block);
x87_state *state = bl_state->begin;
const ir_edge_t *edge;
ir_node *start_block;
- /* if we have no assigned start state, we must wait ... */
- if (! state)
- return 0;
+ assert(state != NULL);
+ // already processed?
+ if(bl_state->end != NULL)
+ return;
- assert(bl_state->end == NULL);
+ update_liveness(sim, block);
DB((dbg, LEVEL_1, "Simulate %+F\n", block));
- DB((dbg, LEVEL_2, "State at Block begin:\n ")); DEBUG_ONLY(x87_dump_stack(state));
+ DB((dbg, LEVEL_2, "State at Block begin:\n "));
+ DEBUG_ONLY(x87_dump_stack(state));
/* at block begin, kill all dead registers */
state = x87_kill_deads(sim, block, state);
/* beware, n might changed */
for (n = sched_first(block); !sched_is_end(n); n = next) {
+ int node_inserted;
+ sim_func func;
ir_op *op = get_irn_op(n);
next = sched_next(n);
- if (op->ops.generic) {
- int node_inserted;
- sim_func func = (sim_func)op->ops.generic;
-
- /* have work to do */
- if (state == bl_state->begin) {
- /* create a new state, will be changed */
- state = x87_clone_state(sim, state);
- }
+ if (op->ops.generic == NULL)
+ continue;
- /* simulate it */
- node_inserted = (*func)(state, n, sim->env);
+ func = (sim_func)op->ops.generic;
- /*
- sim_func might have added additional nodes after n,
- so update next node
- beware: n must not be changed by sim_func
- (i.e. removed from schedule) in this case
- */
- if (node_inserted)
- next = sched_next(n);
+ /* have work to do */
+ if (state == bl_state->begin) {
+ /* create a new state, will be changed */
+ state = x87_clone_state(sim, state);
}
+
+ /* simulate it */
+ node_inserted = (*func)(state, n);
+
+ /*
+ sim_func might have added additional nodes after n,
+ so update next node
+ beware: n must not be changed by sim_func
+ (i.e. removed from schedule) in this case
+ */
+ if (node_inserted)
+ next = sched_next(n);
}
start_block = get_irg_start_block(get_irn_irg(block));
/* check if the state must be shuffled */
foreach_block_succ(block, edge) {
ir_node *succ = get_edge_src_irn(edge);
- blk_state *succ_state = x87_get_bl_state(sim, succ);
+ blk_state *succ_state;
- if (succ_state->begin && succ != start_block) {
- /* There is already a begin state for this block, bad.
+ if(succ == start_block)
+ continue;
+
+ succ_state = x87_get_bl_state(sim, succ);
+
+ if (succ_state->begin == NULL) {
+ succ_state->begin = state;
+ waitq_put(sim->worklist, succ);
+ } else {
+ /* There is already a begin state for the successor, bad.
Do the necessary permutations.
Note that critical edges are removed, so this is always possible. */
x87_shuffle(sim, block, state, succ, succ_state->begin);
-
- /* Note further, that there can be only one such situation,
- so we can break here. */
- break;
}
}
bl_state->end = state;
- /* now propagate the state to all successor blocks */
- foreach_block_succ(block, edge) {
- ir_node *succ = get_edge_src_irn(edge);
- blk_state *succ_state = x87_get_bl_state(sim, succ);
-
- if (! succ_state->begin)
- succ_state->begin = state;
- }
-
DB((dbg, LEVEL_2, "State at Block end:\n ")); DEBUG_ONLY(x87_dump_stack(state));
-
- return 1;
} /* x87_simulate_block */
/**
DB((dbg, LEVEL_1, "--------------------------------\n"
"x87 Simulator started for %+F\n", irg));
- /* set the generic function pointer of instruction we must simulate */
+ /* set the generic function pointer of instruction we must simulate */
clear_irp_opcodes_generic_func();
#define ASSOC(op) (op_ ## op)->ops.generic = (op_func)(sim_##op)
ASSOC_IA32(fsub);
ASSOC_IA32(fmul);
ASSOC_IA32(fdiv);
- ASSOC_IA32(fldz);
+ ASSOC_IA32(fprem);
ASSOC_IA32(fabs);
ASSOC_IA32(fchs);
ASSOC_IA32(fsin);
*
* @param env the architecture environment
* @param irg the current graph
- * @param blk_list the block schedule list
*
* Needs a block-schedule.
*/
-void x87_simulate_graph(const arch_env_t *env, ir_graph *irg, ir_node **blk_list) {
- ir_node *block, *start_block;
- waitq *worklist;
- blk_state *bl_state;
+void x87_simulate_graph(const arch_env_t *env, be_irg_t *birg) {
+ ir_node *block, *start_block;
+ blk_state *bl_state;
x87_simulator sim;
- int i, n;
- be_lv_t *lv;
+ ir_graph *irg = birg->irg;
/* create the simulator */
x87_init_simulator(&sim, irg, env);
bl_state->begin = empty;
empty->sim = ∼
- worklist = new_waitq();
+ sim.worklist = new_waitq();
+ waitq_put(sim.worklist, start_block);
+ be_invalidate_liveness(birg);
+ be_assure_liveness(birg);
+ sim.lv = birg->lv;
+
+#if 0
/* Create the worklist for the schedule and calculate the liveness
for all nodes. We must precalculate this info, because the
simulator adds new nodes (and possible before Phi nodes) which
On the other hand we reduce the computation amount due to
precaching from O(n^2) to O(n) at the expense of O(n) cache memory.
*/
- lv = be_liveness(irg);
for (i = 0, n = ARR_LEN(blk_list); i < n; ++i) {
update_liveness(&sim, lv, blk_list[i]);
waitq_put(worklist, blk_list[i]);
}
- be_liveness_free(lv);
+#endif
/* iterate */
do {
- block = waitq_get(worklist);
- if (! x87_simulate_block(&sim, block)) {
- waitq_put(worklist, block);
- continue;
- }
- } while (! pdeq_empty(worklist));
+ block = waitq_get(sim.worklist);
+ x87_simulate_block(&sim, block);
+ } while (! pdeq_empty(sim.worklist));
/* kill it */
- del_waitq(worklist);
+ del_waitq(sim.worklist);
x87_destroy_simulator(&sim);
} /* x87_simulate_graph */