* @brief This file implements the x87 support and virtual to stack
* register translation for the ia32 backend.
* @author Michael Beck
- * @version $Id$
*/
#include "config.h"
#include "debug.h"
#include "error.h"
-#include "../belive_t.h"
-#include "../besched.h"
-#include "../benode.h"
+#include "belive_t.h"
+#include "besched.h"
+#include "benode.h"
#include "bearch_ia32_t.h"
#include "ia32_new_nodes.h"
#include "gen_ia32_new_nodes.h"
x87_state *end; /**< state at the end or NULL if not assigned */
} blk_state;
-#define PTR_TO_BLKSTATE(p) ((blk_state *)(p))
-
/** liveness bitset for vfp registers. */
typedef unsigned char vfp_liveness;
static int x87_get_depth(const x87_state *state)
{
return state->depth;
-} /* x87_get_depth */
+}
/**
* Return the virtual register index at st(pos).
{
assert(pos < state->depth);
return state->st[MASK_TOS(state->tos + pos)].reg_idx;
-} /* x87_get_st_reg */
+}
#ifdef DEBUG_libfirm
/**
{
assert(pos < state->depth);
return state->st[MASK_TOS(state->tos + pos)].node;
-} /* x87_get_st_node */
+}
/**
* Dump the stack for debugging.
x87_get_st_node(state, i)));
}
DB((dbg, LEVEL_2, "<-- TOS\n"));
-} /* x87_dump_stack */
+}
#endif /* DEBUG_libfirm */
/**
DB((dbg, LEVEL_2, "After SET_REG: "));
DEBUG_ONLY(x87_dump_stack(state);)
-} /* x87_set_st */
+}
/**
* Set the tos virtual register.
static void x87_set_tos(x87_state *state, int reg_idx, ir_node *node)
{
x87_set_st(state, reg_idx, node, 0);
-} /* x87_set_tos */
+}
/**
* Swap st(0) with st(pos).
DB((dbg, LEVEL_2, "After FXCH: "));
DEBUG_ONLY(x87_dump_stack(state);)
-} /* x87_fxch */
+}
/**
* Convert a virtual register to the stack index.
if (state->st[MASK_TOS(tos + i)].reg_idx == reg_idx)
return i;
return -1;
-} /* x87_on_stack */
+}
/**
* Push a virtual Register onto the stack, double pushed allowed.
state->st[state->tos].node = node;
DB((dbg, LEVEL_2, "After PUSH: ")); DEBUG_ONLY(x87_dump_stack(state);)
-} /* x87_push_dbl */
+}
/**
* Push a virtual Register onto the stack, double pushes are NOT allowed.
assert(x87_on_stack(state, reg_idx) == -1 && "double push");
x87_push_dbl(state, reg_idx, node);
-} /* x87_push */
+}
/**
* Pop a virtual Register from the stack.
state->tos = MASK_TOS(state->tos + 1);
DB((dbg, LEVEL_2, "After POP: ")); DEBUG_ONLY(x87_dump_stack(state);)
-} /* x87_pop */
+}
/**
* Empty the fpu stack
*/
static blk_state *x87_get_bl_state(x87_simulator *sim, ir_node *block)
{
- pmap_entry *entry = pmap_find(sim->blk_states, block);
+ blk_state *res = pmap_get(sim->blk_states, block);
- if (! entry) {
- blk_state *bl_state = OALLOC(&sim->obst, blk_state);
- bl_state->begin = NULL;
- bl_state->end = NULL;
+ if (res == NULL) {
+ res = OALLOC(&sim->obst, blk_state);
+ res->begin = NULL;
+ res->end = NULL;
- pmap_insert(sim->blk_states, block, bl_state);
- return bl_state;
+ pmap_insert(sim->blk_states, block, res);
}
- return PTR_TO_BLKSTATE(entry->value);
-} /* x87_get_bl_state */
+ return res;
+}
/**
* Creates a new x87 state.
res->sim = sim;
return res;
-} /* x87_alloc_state */
+}
/**
* Clone a x87 state.
*res = *src;
return res;
-} /* x87_clone_state */
+}
/**
* Patch a virtual instruction into a x87 one and return
} else if (mode_is_float(mode))
set_irn_mode(n, ia32_reg_classes[CLASS_ia32_st].mode);
return res;
-} /* x87_patch_insn */
+}
/**
* Returns the first Proj of a mode_T node having a given mode.
}
return NULL;
-} /* get_irn_Proj_for_mode */
+}
/**
* Wrap the arch_* function here so we can check for errors.
assert(res->reg_class == &ia32_reg_classes[CLASS_ia32_vfp]);
return res;
-} /* x87_get_irn_register */
+}
static inline const arch_register_t *x87_irn_get_register(const ir_node *irn,
int pos)
assert(res->reg_class == &ia32_reg_classes[CLASS_ia32_vfp]);
return res;
-} /* x87_irn_get_register */
+}
static inline const arch_register_t *get_st_reg(int index)
{
x87_fxch(state, pos);
return fxch;
-} /* x87_fxch_shuffle */
+}
/**
* Calculate the necessary permutations to reach dst_state.
}
}
return state;
-} /* x87_shuffle */
+}
/**
* Create a fxch node before another node.
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));
return fxch;
-} /* x87_create_fxch */
+}
/**
* Create a fpush before node n.
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.
DB((dbg, LEVEL_1, "<<< %s %s\n", get_irn_opname(fpop), attr->x87[0]->name));
} while (--num > 0);
return fpop;
-} /* x87_create_fpop */
+}
/* --------------------------------- liveness ------------------------------------------ */
}
}
return live;
-} /* vfp_liveness_transfer */
+}
/**
* Put all live virtual registers at the end of a block into a bitset.
}
return live;
-} /* vfp_liveness_end_of_block */
+}
/** get the register mask from an arch_register */
#define REGMASK(reg) (1 << (arch_register_get_index(reg)))
assert(idx < sim->n_idx);
return sim->live[idx] & ~kill;
-} /* vfp_live_args_after */
+}
/**
* Calculate the liveness for a whole block and cache it.
}
idx = get_irn_idx(block);
sim->live[idx] = live;
-} /* update_liveness */
+}
/**
* Returns true if a register is live in a set.
}
}
DB((dbg, LEVEL_2, "\n"));
-} /* vfp_dump_live */
+}
#endif /* DEBUG_libfirm */
/* --------------------------------- simulators ---------------------------------------- */
}
return NO_NODE_ADDED;
-} /* sim_binop */
+}
/**
* Simulate a virtual Unop.
DB((dbg, LEVEL_1, "<<< %s -> %s\n", get_irn_opname(n), out->name));
return NO_NODE_ADDED;
-} /* sim_unop */
+}
/**
* Simulate a virtual Load instruction.
DB((dbg, LEVEL_1, "<<< %s -> %s\n", get_irn_opname(n), arch_register_get_name(out)));
return NO_NODE_ADDED;
-} /* sim_load */
+}
/**
* Rewire all users of @p old_val to @new_val iff they are scheduled after @p store.
}
}
}
-} /* collect_and_rewire_users */
+}
/**
* Simulate a virtual Store.
DB((dbg, LEVEL_1, "<<< %s %s ->\n", get_irn_opname(n), arch_register_get_name(op2)));
return insn;
-} /* sim_store */
+}
#define _GEN_BINOP(op, rev) \
static int sim_##op(x87_state *state, ir_node *n) { \
DB((dbg, LEVEL_1, "<<< %s %s ->\n", get_irn_opname(n), arch_register_get_name(op2)));
return NO_NODE_ADDED;
-} /* sim_fisttp */
+}
/**
* Simulate a virtual FtstFnstsw.
x87_create_fpop(state, sched_next(n), 1);
return NO_NODE_ADDED;
-} /* sim_FtstFnstsw */
+}
/**
* Simulate a Fucom
}
return NO_NODE_ADDED;
-} /* sim_Fucom */
+}
/**
* Simulate a Keep.
DEBUG_ONLY(x87_dump_stack(state);)
return NO_NODE_ADDED;
-} /* sim_Keep */
+}
/**
* Keep the given node alive by adding a be_Keep.
arch_set_irn_register(res, out);
return res;
-} /* create_Copy */
+}
/**
* Simulate a be_Copy.
}
}
return NO_NODE_ADDED;
-} /* sim_Copy */
+}
/**
* Returns the vf0 result Proj of a Call.
}
return NULL;
-} /* get_call_result_proj */
+}
/**
* Simulate a ia32_Call.
DEBUG_ONLY(x87_dump_stack(state);)
return NO_NODE_ADDED;
-} /* sim_Call */
+}
/**
* Simulate a be_Return.
x87_pop(state);
return NO_NODE_ADDED;
-} /* sim_Return */
+}
typedef struct perm_data_t {
const arch_register_t *in;
DB((dbg, LEVEL_1, "<<< %+F\n", irn));
return NO_NODE_ADDED;
-} /* sim_Perm */
+}
/**
* Kill any dead registers at block start by popping them from the stack.
keep_alive(keep);
}
return state;
-} /* x87_kill_deads */
+}
/**
* Run a simulation and fix all virtual instructions for a block.
}
}
bl_state->end = state;
-} /* x87_simulate_block */
+}
/**
* Register a simulator function.
{
assert(op->ops.generic == NULL);
op->ops.generic = (op_func) func;
-} /* register_sim */
+}
/**
* Create a new x87 simulator.
"x87 Simulator started for %+F\n", irg));
/* set the generic function pointer of instruction we must simulate */
- clear_irp_opcodes_generic_func();
+ ir_clear_opcodes_generic_func();
register_sim(op_ia32_Call, sim_Call);
register_sim(op_ia32_vfld, sim_fld);
register_sim(op_be_Return, sim_Return);
register_sim(op_be_Perm, sim_Perm);
register_sim(op_be_Keep, sim_Keep);
-} /* x87_init_simulator */
+}
/**
* Destroy a x87 simulator.
pmap_destroy(sim->blk_states);
obstack_free(&sim->obst, NULL);
DB((dbg, LEVEL_1, "x87 Simulator stopped\n\n"));
-} /* x87_destroy_simulator */
+}
/**
* Pre-block walker: calculate the liveness information for the block
{
x87_simulator *sim = (x87_simulator*)data;
update_liveness(sim, block);
-} /* update_liveness_walker */
+}
/*
* Run a simulation and fix all virtual instructions for a graph.
sim.worklist = new_waitq();
waitq_put(sim.worklist, start_block);
- be_assure_liveness(irg);
+ be_assure_live_sets(irg);
sim.lv = be_get_irg_liveness(irg);
- be_liveness_assure_sets(sim.lv);
/* Calculate the liveness for all nodes. We must precalculate this info,
* because the simulator adds new nodes (possible before Phi nodes) which
/* kill it */
del_waitq(sim.worklist);
x87_destroy_simulator(&sim);
-} /* ia32_x87_simulate_graph */
+}
/* Initializes the x87 simulator. */
void ia32_init_x87(void)
{
FIRM_DBG_REGISTER(dbg, "firm.be.ia32.x87");
-} /* ia32_init_x87 */
+}