[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[dotgnu-pnet-commits] libjit ./ChangeLog jit/jit-reg-alloc.h jit/jit-...
From: |
Aleksey Demakov |
Subject: |
[dotgnu-pnet-commits] libjit ./ChangeLog jit/jit-reg-alloc.h jit/jit-... |
Date: |
Sat, 18 Feb 2006 19:58:10 +0000 |
CVSROOT: /sources/dotgnu-pnet
Module name: libjit
Branch:
Changes by: Aleksey Demakov <address@hidden> 06/02/18 19:58:10
Modified files:
. : ChangeLog
jit : jit-reg-alloc.h jit-reg-alloc.c jit-rules.h
jit-rules-x86.c jit-rules-interp.c
jit-rules-arm.c
Log message:
New local register allocator.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/dotgnu-pnet/libjit/ChangeLog.diff?tr1=1.201&tr2=1.202&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/dotgnu-pnet/libjit/jit/jit-reg-alloc.h.diff?tr1=1.6&tr2=1.7&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/dotgnu-pnet/libjit/jit/jit-reg-alloc.c.diff?tr1=1.20&tr2=1.21&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/dotgnu-pnet/libjit/jit/jit-rules.h.diff?tr1=1.10&tr2=1.11&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/dotgnu-pnet/libjit/jit/jit-rules-x86.c.diff?tr1=1.28&tr2=1.29&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/dotgnu-pnet/libjit/jit/jit-rules-interp.c.diff?tr1=1.23&tr2=1.24&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/dotgnu-pnet/libjit/jit/jit-rules-arm.c.diff?tr1=1.20&tr2=1.21&r1=text&r2=text
Patches:
Index: libjit/ChangeLog
diff -u libjit/ChangeLog:1.201 libjit/ChangeLog:1.202
--- libjit/ChangeLog:1.201 Mon Feb 13 09:26:18 2006
+++ libjit/ChangeLog Sat Feb 18 19:58:10 2006
@@ -1,3 +1,16 @@
+2006-02-19 Aleksey Demakov <address@hidden>
+
+ * jit/jit-reg-alloc.h:
+ * jit/jit-reg-alloc.c: Initial version of new local register
+ allocator.
+
+ * jit/jit-rules.h:
+ * jit/jit-rules-arm.c (_jit_gen_spill_global):
+ * jit/jit-rules-interp.c (_jit_gen_spill_global):
+ * jit/jit-rules-x86.c (_jit_gen_spill_global): add function for
+ spilling global registers. Used by the new allocator. Only x86
+ version is really implemented.
+
2006-02-13 Aleksey Demakov <address@hidden>
* jit/jit-internal.h (struct _jit_value): add index field.
Index: libjit/jit/jit-reg-alloc.c
diff -u libjit/jit/jit-reg-alloc.c:1.20 libjit/jit/jit-reg-alloc.c:1.21
--- libjit/jit/jit-reg-alloc.c:1.20 Fri Jan 13 20:26:19 2006
+++ libjit/jit/jit-reg-alloc.c Sat Feb 18 19:58:10 2006
@@ -1627,3 +1627,1161 @@
_jit_regs_want_reg(gen, index, 0);
}
}
+
+/*
+ * New Reg Alloc API
+ */
+
+/*
+ * Set assigned and clobbered flags for register.
+ */
+static void
+set_register_bits(_jit_regs_t *regs, _jit_regdesc_t *desc, int output)
+{
+ int clobber;
+ if(desc->reg >= 0)
+ {
+ clobber = desc->clobber;
+ if(output && desc->value->in_register && desc->value->reg ==
desc->reg)
+ {
+ clobber = 0;
+ }
+
+ jit_reg_set_used(regs->assigned, desc->reg);
+ if(clobber)
+ {
+ jit_reg_set_used(regs->clobber, desc->reg);
+ }
+ if(desc->other_reg >= 0)
+ {
+ jit_reg_set_used(regs->assigned, desc->other_reg);
+ if(clobber)
+ {
+ jit_reg_set_used(regs->clobber,
desc->other_reg);
+ }
+ }
+ }
+}
+
+/*
+ * Determine the type of register that we need.
+ */
+static int
+get_register_type(jit_value_t value, int need_pair)
+{
+ switch(jit_type_normalize(value->type)->kind)
+ {
+ case JIT_TYPE_SBYTE:
+ case JIT_TYPE_UBYTE:
+ case JIT_TYPE_SHORT:
+ case JIT_TYPE_USHORT:
+ case JIT_TYPE_INT:
+ case JIT_TYPE_UINT:
+ case JIT_TYPE_NINT:
+ case JIT_TYPE_NUINT:
+ case JIT_TYPE_SIGNATURE:
+ case JIT_TYPE_PTR:
+ return JIT_REG_WORD;
+
+ case JIT_TYPE_LONG:
+ case JIT_TYPE_ULONG:
+ return need_pair ? JIT_REG_LONG : JIT_REG_WORD;
+
+ case JIT_TYPE_FLOAT32:
+ return JIT_REG_FLOAT32;
+
+ case JIT_TYPE_FLOAT64:
+ return JIT_REG_FLOAT64;
+
+ case JIT_TYPE_NFLOAT:
+ return JIT_REG_NFLOAT;
+ }
+
+ return 0;
+}
+
+/*
+ * Assign diplicate input value to the same register if possible.
+ * The first value has to be already assigned. The second value
+ * is assigned to the same register if it is equal to the first
+ * and neither of them is clobbered.
+ */
+static void
+reuse_duplicate_value(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
+{
+ if(desc1->value == desc2->value
+ && desc1->reg >= 0 && desc2->reg < 0
+ && !desc1->clobber && !desc2->clobber)
+ {
+ desc2->reg = desc1->reg;
+ desc2->other_reg = desc1->other_reg;
+ }
+}
+
+/*
+ * Assign value to the register it is already in if possible. This is the case
+ * if the register is not already assigned to and one of the following is true:
+ * 1. The value is output and it the only value in register.
+ * 2. The value is input and it is not clobbered.
+ * 3. The value is input and it the only value in register, it is clobbered
+ * but not used afterwards.
+ * 4. The value is input and it is clobbered even if we do not use its
+ * register. This might be because the instruction clobbers all or
+ * some registers (see _jit_regs_clobber_all(), jit_regs_clobber()).
+ * NOTE: In the last case it might be possible to find a not clobbered register
+ * where the value could be moved to so that the original copy can be used for
+ * input without spilling. However probaly this corner case is not worth the
+ * effort.
+ */
+static void
+reuse_register(jit_gencode_t gen, _jit_regs_t *regs, _jit_regdesc_t *desc, int
output)
+{
+ int reg;
+ int other_reg;
+
+ reg = -1;
+ other_reg = -1;
+ if(desc->value->in_register)
+ {
+ reg = desc->value->reg;
+
+ if(_jit_regs_needs_long_pair(desc->value->type))
+ {
+ other_reg = _jit_reg_info[reg].other_reg;
+ }
+ else
+ {
+ other_reg = -1;
+ }
+ }
+ else if(desc->value->in_global_register
+ && (regs->is_ternary
+ || desc->value == regs->descs[0].value
+ || desc->value != regs->descs[1].value))
+ {
+ /* It is safe to use the global register directly when it
+ is not a binary operation which output value is going
+ to override the original one. */
+ reg = desc->value->global_reg;
+ other_reg = -1;
+ }
+
+ if(reg < 0)
+ {
+ return;
+ }
+
+ if(jit_reg_is_used(regs->assigned, reg))
+ {
+ return;
+ }
+ if(output)
+ {
+ if(gen->contents[reg].num_values > 1)
+ {
+ return;
+ }
+ }
+ else
+ {
+ if(desc->clobber
+ && (desc->live || desc->used ||
gen->contents[reg].num_values > 1)
+ && !jit_reg_is_used(regs->clobber, reg))
+ {
+ return;
+ }
+ }
+
+ if(other_reg >= 0)
+ {
+ if(jit_reg_is_used(regs->assigned, other_reg))
+ {
+ return;
+ }
+
+ if(output)
+ {
+ if(gen->contents[other_reg].num_values > 1)
+ {
+ return;
+ }
+ }
+ else
+ {
+ if(desc->clobber
+ && (desc->live || desc->used ||
gen->contents[other_reg].num_values > 1)
+ && !jit_reg_is_used(regs->clobber, other_reg))
+ {
+ return;
+ }
+ }
+ }
+
+ desc->reg = reg;
+ desc->other_reg = other_reg;
+ set_register_bits(regs, desc, output);
+}
+
+/*
+ * Assign value to a register that is cheapest to use. We are here either
+ * because the value is not in register or it is but the register will be
+ * clobbered so the reuse_register() function failed to assign the register.
+ *
+ * Depending on the value location and on the presence of a free register we
+ * do one of the following:
+ *
+ * 1. The value is in register and there is a free register.
+ * In this case we will generate a reg-to-reg move.
+ * 2. The value is in register and there are no free regsiters.
+ * In this case we will generate a spill if the register is dirty.
+ * 3. The value is in frame and there is a free register.
+ * In this case we will generate a value load.
+ * 4. The value is in frame and there are no free registers.
+ * In this case we choose a register to evict. We will generate a
+ * spill for the dirty register and load the value there.
+ *
+ * In the last case we choose the register using the following rules:
+ *
+ * 1. Choose clean registers over dirty.
+ * 2. Choose registers that contain global values over those that don't.
+ * 2. Choose old registers over new.
+ *
+ * NOTE: A register is clean if the value it contains has not changed since
+ * it was loaded form the frame. Otherwise it is dirty. There is no need to
+ * spill clean registers. Dirty registers has to be spilled.
+ *
+ * TODO: build use lists in CFG and choose the register on the basis of next
+ * value use instead of the register age.
+ *
+ */
+static int
+use_cheapest_register(jit_gencode_t gen, _jit_regs_t *regs, _jit_regdesc_t
*desc, int output)
+{
+ int type;
+ int need_pair;
+ int reg;
+ int other_reg;
+ int cost;
+ int free_reg;
+ int suitable_reg;
+ int suitable_cost;
+ int suitable_age;
+ int index;
+
+ if(desc)
+ {
+ type = get_register_type(desc->value, need_pair);
+ if(!type)
+ {
+ return -1;
+ }
+
+ need_pair = _jit_regs_needs_long_pair(desc->value->type);
+ }
+ else
+ {
+ type = JIT_REG_WORD;
+ need_pair = 0;
+ }
+
+ free_reg = -1;
+ suitable_reg = -1;
+ suitable_cost = 0;
+ suitable_age = -1;
+ for(reg = 0; reg < JIT_NUM_REGS; ++reg)
+ {
+ if((_jit_reg_info[reg].flags & type) == 0)
+ {
+ continue;
+ }
+
+ if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0)
+ {
+ /* TODO: Support stack registers. */
+ return -1;
+ }
+
+ if(need_pair)
+ {
+ other_reg = _jit_reg_info[reg].other_reg;
+ }
+ else
+ {
+ other_reg = -1;
+ }
+
+ if(jit_reg_is_used(gen->permanent, reg)
+ || jit_reg_is_used(gen->inhibit, reg)
+ || jit_reg_is_used(regs->assigned, reg))
+ {
+ continue;
+ }
+ if(other_reg >= 0)
+ {
+ if(jit_reg_is_used(gen->permanent, other_reg)
+ || jit_reg_is_used(gen->inhibit, other_reg)
+ || jit_reg_is_used(regs->assigned, other_reg))
+ {
+ continue;
+ }
+ }
+
+ if(gen->contents[reg].num_values == 0
+ && !gen->contents[reg].is_long_end
+ && (other_reg < 0 || gen->contents[other_reg].num_values ==
0))
+ {
+ free_reg = reg;
+ break;
+ }
+
+ cost = 0;
+ for(index = 0; index < gen->contents[reg].num_values; index++)
+ {
+
if(gen->contents[reg].values[index]->has_global_register)
+ {
+
if(!gen->contents[reg].values[index]->in_global_register)
+ {
+ cost += 1;
+ }
+ }
+ else
+ {
+ if(!gen->contents[reg].values[index]->in_frame)
+ {
+ cost += 3;
+ }
+ }
+ }
+ if(other_reg >= 0)
+ {
+ for(index = 0; index <
gen->contents[other_reg].num_values; index++)
+ {
+
if(gen->contents[other_reg].values[index]->has_global_register)
+ {
+
if(!gen->contents[other_reg].values[index]->in_global_register)
+ {
+ cost += 1;
+ }
+ }
+ else
+ {
+
if(!gen->contents[other_reg].values[index]->in_frame)
+ {
+ cost += 3;
+ }
+ }
+ }
+ }
+
+ if(suitable_reg == -1
+ || cost < suitable_cost
+ || (cost == suitable_cost && gen->contents[reg].age <
suitable_age))
+ {
+ /* This is the oldest suitable register of this type */
+ suitable_reg = reg;
+ suitable_cost = cost;
+ suitable_age = gen->contents[reg].age;
+ }
+ }
+
+ if(desc && desc->value->in_register && free_reg < 0)
+ {
+ /* Case 2. */
+ reg = desc->value->reg;
+ }
+ else if(free_reg >= 0)
+ {
+ /* Cases 1 and 3. */
+ reg = free_reg;
+ }
+ else
+ {
+ /* Case 4. */
+ reg = suitable_reg;
+ }
+
+ if(desc && reg >= 0)
+ {
+ if(need_pair)
+ {
+ other_reg = _jit_reg_info[reg].other_reg;
+ }
+ else
+ {
+ other_reg = -1;
+ }
+
+ desc->reg = reg;
+ desc->other_reg = other_reg;
+ set_register_bits(regs, desc, output);
+ }
+
+ return reg;
+}
+
+static void
+set_register(jit_gencode_t gen, _jit_regdesc_t *desc, int still_in_frame)
+{
+ int reg, other_reg;
+ int first_stack_reg;
+
+ reg = desc->reg;
+ other_reg = desc->other_reg;
+
+ if(desc->value->has_global_register && desc->value->global_reg == reg)
+ {
+ desc->value->in_register = 0;
+ desc->value->in_global_register = 1;
+ return;
+ }
+
+ gen->contents[reg].values[0] = desc->value;
+ gen->contents[reg].num_values = 1;
+ gen->contents[reg].age = gen->current_age;
+ gen->contents[reg].used_for_temp = 0;
+ gen->contents[reg].is_long_end = 0;
+ if(other_reg == -1)
+ {
+ gen->contents[reg].is_long_start = 0;
+ }
+ else
+ {
+ gen->contents[reg].is_long_start = 1;
+ gen->contents[other_reg].num_values = 0;
+ gen->contents[other_reg].age = gen->current_age;
+ gen->contents[other_reg].used_for_temp = 0;
+ gen->contents[other_reg].is_long_start = 0;
+ gen->contents[other_reg].is_long_end = 1;
+ }
+
+ /* Set the stack mappings for this register */
+ if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0)
+ {
+ first_stack_reg = reg;
+ while((_jit_reg_info[first_stack_reg].flags &
JIT_REG_START_STACK) == 0)
+ {
+ --first_stack_reg;
+ }
+ gen->contents[reg].remap = first_stack_reg;
+ gen->stack_map[first_stack_reg] = desc->reg;
+ }
+
+ /* Adjust the value to reflect that it is in "reg", and maybe the frame
*/
+ desc->value->in_register = 1;
+ if(desc->value->has_global_register)
+ desc->value->in_global_register = still_in_frame;
+ else
+ desc->value->in_frame = still_in_frame;
+ desc->value->reg = reg;
+}
+
+static void
+load_single(jit_gencode_t gen, _jit_regdesc_t *desc)
+{
+ if(!desc->value)
+ {
+ return;
+ }
+
+ if(desc->value->in_register)
+ {
+ if(desc->value->reg != desc->reg)
+ {
+ if(gen->contents[desc->reg].num_values > 0)
+ {
+ spill_register(gen, desc->reg);
+ }
+ if(desc->other_reg >= 0 &&
gen->contents[desc->other_reg].num_values > 0)
+ {
+ spill_register(gen, desc->other_reg);
+ }
+ _jit_gen_load_value(gen, desc->reg, desc->other_reg,
desc->value);
+ }
+ }
+ else if(desc->value->in_global_register)
+ {
+ if(desc->value->global_reg != desc->reg)
+ {
+ if(gen->contents[desc->reg].num_values > 0)
+ {
+ spill_register(gen, desc->reg);
+ }
+ if(desc->other_reg >= 0 &&
gen->contents[desc->other_reg].num_values > 0)
+ {
+ spill_register(gen, desc->other_reg);
+ }
+ _jit_gen_load_value(gen, desc->reg, desc->other_reg,
desc->value);
+ set_register(gen, desc, 1);
+ }
+ }
+ else
+ {
+ if(gen->contents[desc->reg].num_values > 0)
+ {
+ spill_register(gen, desc->reg);
+ }
+ if(desc->other_reg >= 0 &&
gen->contents[desc->other_reg].num_values > 0)
+ {
+ spill_register(gen, desc->other_reg);
+ }
+ _jit_gen_load_value(gen, desc->reg, desc->other_reg,
desc->value);
+ set_register(gen, desc, 1);
+ }
+}
+
+static void
+load_couple(jit_gencode_t gen, _jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
+{
+ int reg2, other_reg2;
+
+ if(!desc1->value || !desc1->value->in_register || desc1->value->reg ==
desc1->reg)
+ {
+ load_single(gen, desc2);
+ load_single(gen, desc1);
+ }
+ else if(!desc2->value || !desc2->value->in_register ||
desc2->value->reg == desc2->reg)
+ {
+ load_single(gen, desc1);
+ load_single(gen, desc2);
+ }
+ else
+ {
+ reg2 = desc2->value->reg;
+ if(gen->contents[reg2].is_long_start)
+ {
+ other_reg2 = _jit_reg_info[reg2].other_reg;
+ }
+ else
+ {
+ other_reg2 = -1;
+ }
+
+ if(desc1->reg != reg2 && desc1->other_reg != reg2
+ && (other_reg2 < 0
+ || (desc1->reg != other_reg2 && desc1->other_reg !=
other_reg2)))
+ {
+ load_single(gen, desc1);
+ load_single(gen, desc2);
+ }
+ else
+ {
+ load_single(gen, desc2);
+ load_single(gen, desc1);
+ }
+ }
+}
+
+static void
+load_triple(jit_gencode_t gen, _jit_regdesc_t *desc1, _jit_regdesc_t *desc2,
_jit_regdesc_t *desc3)
+{
+ int reg1, other_reg1;
+ int reg2, other_reg2;
+ int reg3, other_reg3;
+
+ if(!desc1->value || !desc1->value->in_register || desc1->value->reg ==
desc1->reg)
+ {
+ load_couple(gen, desc2, desc3);
+ load_single(gen, desc1);
+ }
+ else if(!desc2->value || !desc2->value->in_register ||
desc2->value->reg == desc2->reg)
+ {
+ load_couple(gen, desc1, desc3);
+ load_single(gen, desc2);
+ }
+ else if(!desc3->value || !desc3->value->in_register ||
desc3->value->reg == desc3->reg)
+ {
+ load_couple(gen, desc1, desc2);
+ load_single(gen, desc3);
+ }
+ else
+ {
+ reg1 = desc1->value->reg;
+ if(gen->contents[reg1].is_long_start)
+ {
+ other_reg1 = _jit_reg_info[reg1].other_reg;
+ }
+ else
+ {
+ other_reg1 = -1;
+ }
+
+ reg2 = desc2->value->reg;
+ if(gen->contents[reg2].is_long_start)
+ {
+ other_reg2 = _jit_reg_info[reg2].other_reg;
+ }
+ else
+ {
+ other_reg2 = -1;
+ }
+
+ reg3 = desc3->value->reg;
+ if(gen->contents[reg3].is_long_start)
+ {
+ other_reg3 = _jit_reg_info[reg3].other_reg;
+ }
+ else
+ {
+ other_reg3 = -1;
+ }
+
+ if(desc1->reg != reg2 && desc1->other_reg != reg2
+ && desc1->reg != reg3 && desc1->other_reg != reg3
+ && (other_reg2 < 0
+ || (desc1->reg != other_reg2 && desc1->other_reg !=
other_reg2))
+ && (other_reg3 < 0
+ || (desc1->reg != other_reg3 && desc1->other_reg !=
other_reg3)))
+ {
+ load_single(gen, desc1);
+ load_couple(gen, desc2, desc3);
+ }
+ else if(desc2->reg != reg1 && desc2->other_reg != reg1
+ && desc2->reg != reg3 && desc2->other_reg != reg3
+ && (other_reg1 < 0
+ || (desc2->reg != other_reg1 && desc2->other_reg !=
other_reg1))
+ && (other_reg3 < 0
+ || (desc2->reg != other_reg3 && desc2->other_reg !=
other_reg3)))
+ {
+ load_single(gen, desc2);
+ load_couple(gen, desc1, desc3);
+ }
+ else
+ {
+ load_single(gen, desc3);
+ load_couple(gen, desc1, desc2);
+ }
+ }
+}
+
+void
+_jit_regs_init(_jit_regs_t *regs, int is_ternary, int is_commutative)
+{
+ int i;
+
+ regs->is_ternary = is_ternary;
+ regs->is_commutative = is_commutative;
+
+ for(i = 0; i < _JIT_REGS_VALUE_MAX; i++)
+ {
+ regs->descs[i].value = 0;
+ regs->descs[i].reg = -1;
+ regs->descs[i].other_reg = -1;
+ regs->descs[i].clobber = 0;
+ regs->descs[i].live = 0;
+ regs->descs[i].used = 0;
+ }
+ regs->num_descs = 0;
+
+ for(i = 0; i < _JIT_REGS_SCRATCH_MAX; i++)
+ {
+ regs->scratch[1] = -1;
+ }
+ regs->num_scratch = 0;
+
+ regs->assigned = jit_regused_init;
+ regs->clobber = jit_regused_init;
+}
+
+void
+_jit_regs_set_dest(_jit_regs_t *regs, jit_insn_t insn, int clobber, int reg,
int other_reg)
+{
+ if(regs->num_descs < 1)
+ {
+ regs->num_descs = 1;
+ }
+
+ regs->descs[0].value = insn->dest;
+ if(reg >= 0)
+ {
+ regs->descs[0].reg = reg;
+ regs->descs[0].other_reg = other_reg;
+ }
+ if(!regs->is_ternary || clobber)
+ {
+ regs->descs[0].clobber = 1;
+ }
+ if((insn->flags & JIT_INSN_DEST_LIVE) != 0)
+ {
+ regs->descs[0].live = 1;
+ }
+ if((insn->flags & JIT_INSN_DEST_NEXT_USE) != 0)
+ {
+ regs->descs[0].used = 1;
+ }
+}
+
+void
+_jit_regs_set_value1(_jit_regs_t *regs, jit_insn_t insn, int clobber, int reg,
int other_reg)
+{
+ if(regs->num_descs < 2)
+ {
+ regs->num_descs = 2;
+ }
+
+ regs->descs[1].value = insn->value1;
+ if(reg >= 0)
+ {
+ regs->descs[1].reg = reg;
+ regs->descs[1].other_reg = other_reg;
+ }
+ if(clobber)
+ {
+ regs->descs[1].clobber = 1;
+ }
+ if((insn->flags & JIT_INSN_VALUE1_LIVE) != 0)
+ {
+ regs->descs[1].live = 1;
+ }
+ if((insn->flags & JIT_INSN_VALUE1_NEXT_USE) != 0)
+ {
+ regs->descs[1].used = 1;
+ }
+}
+
+void
+_jit_regs_set_value2(_jit_regs_t *regs, jit_insn_t insn, int clobber, int reg,
int other_reg)
+{
+ if(regs->num_descs < 3)
+ {
+ regs->num_descs = 3;
+ }
+
+ regs->descs[2].value = insn->value2;
+ if(reg >= 0)
+ {
+ regs->descs[2].reg = reg;
+ regs->descs[2].other_reg = other_reg;
+ }
+ if(clobber)
+ {
+ regs->descs[2].clobber = 1;
+ }
+ if((insn->flags & JIT_INSN_VALUE2_LIVE) != 0)
+ {
+ regs->descs[2].live = 1;
+ }
+ if((insn->flags & JIT_INSN_VALUE2_NEXT_USE) != 0)
+ {
+ regs->descs[2].used = 1;
+ }
+}
+
+void
+_jit_regs_set_scratch(_jit_regs_t *regs, int reg)
+{
+ if(regs->num_scratch < _JIT_REGS_SCRATCH_MAX)
+ {
+ regs->scratch[regs->num_scratch++] = reg;
+ }
+}
+
+void
+_jit_regs_clobber(_jit_regs_t *regs, int reg)
+{
+ jit_reg_set_used(regs->clobber, reg);
+}
+
+void
+_jit_regs_clobber_all(_jit_regs_t *regs)
+{
+ regs->clobber = jit_regused_init_used;
+}
+
+int
+_jit_regs_dest(_jit_regs_t *regs)
+{
+ int reg;
+ reg = regs->descs[0].reg;
+ if(reg >= 0)
+ {
+ return _jit_reg_info[reg].cpu_reg;
+ }
+ return -1;
+}
+
+int
+_jit_regs_value1(_jit_regs_t *regs)
+{
+ int reg;
+ reg = regs->descs[1].reg;
+ if(reg >= 0)
+ {
+ return _jit_reg_info[reg].cpu_reg;
+ }
+ return -1;
+}
+
+int
+_jit_regs_value2(_jit_regs_t *regs)
+{
+ int reg;
+ reg = regs->descs[2].reg;
+ if(reg >= 0)
+ {
+ return _jit_reg_info[reg].cpu_reg;
+ }
+ return -1;
+}
+
+int
+_jit_regs_dest_other(_jit_regs_t *regs)
+{
+ int reg;
+ reg = regs->descs[0].other_reg;
+ if(reg >= 0)
+ {
+ return _jit_reg_info[reg].cpu_reg;
+ }
+ return -1;
+}
+
+int
+_jit_regs_value1_other(_jit_regs_t *regs)
+{
+ int reg;
+ reg = regs->descs[1].other_reg;
+ if(reg >= 0)
+ {
+ return _jit_reg_info[reg].cpu_reg;
+ }
+ return -1;
+}
+
+int
+_jit_regs_value2_other(_jit_regs_t *regs)
+{
+ int reg;
+ reg = regs->descs[2].other_reg;
+ if(reg >= 0)
+ {
+ return _jit_reg_info[reg].cpu_reg;
+ }
+ return -1;
+}
+
+int
+_jit_regs_scratch(_jit_regs_t *regs, int index)
+{
+ int reg;
+ if(index < regs->num_scratch && index >= 0)
+ {
+ reg = regs->scratch[index];
+ if(reg >= 0)
+ {
+ return _jit_reg_info[reg].cpu_reg;
+ }
+ }
+ return -1;
+}
+
+int
+_jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs)
+{
+ _jit_regdesc_t *desc1;
+ _jit_regdesc_t *desc2;
+ _jit_regdesc_t *desc3;
+ _jit_regdesc_t tmp;
+ int index;
+
+ desc1 = ®s->descs[0];
+ desc2 = ®s->descs[1];
+ desc3 = ®s->descs[2];
+
+ /* If the operation is not ternary its output clobbers the first input
value. */
+ if(!regs->is_ternary && desc1->value && desc2->value)
+ {
+ /* If the operation is commutative choose which value is
cheaper to clobber. */
+ if(regs->is_commutative && desc3->value)
+ {
+ if((desc2->value != desc1->value && desc3->value ==
desc1->value)
+ || (desc2->live && !desc3->live && !desc2->used &&
!desc3->used)
+ || (desc2->used && !desc3->used)
+ || (!desc2->value->in_frame &&
desc3->value->in_frame))
+ {
+ tmp = *desc2;
+ *desc2 = *desc3;
+ *desc3 = tmp;
+ }
+ }
+
+ if(desc1->value != desc2->value)
+ {
+ desc2->clobber = 1;
+ }
+ }
+
+ /* Process pre-assigned registers. */
+
+ if(desc1->reg >= 0)
+ {
+ if(regs->is_ternary)
+ {
+ set_register_bits(regs, desc1, 0);
+ }
+ else
+ {
+ set_register_bits(regs, desc1, 1);
+ }
+ }
+ if(desc2->reg >= 0)
+ {
+ set_register_bits(regs, desc2, 0);
+ }
+ if(desc3->reg >= 0)
+ {
+ set_register_bits(regs, desc3, 0);
+ }
+
+ for(index = 0; index < regs->num_scratch; index++)
+ {
+ if(regs->scratch[index] >= 0)
+ {
+ jit_reg_set_used(regs->assigned, regs->scratch[index]);
+ jit_reg_set_used(regs->clobber, regs->scratch[index]);
+ }
+ }
+
+ /* For values that are already in registers try to keep them there. */
+
+ if(!regs->is_ternary && desc1->value && desc2->value)
+ {
+ if(desc1->reg < 0 && desc2->reg < 0)
+ {
+ /* If input value is in register and it will not be
+ used again we can save one move by placing output
+ value into that register. */
+ if(!(desc2->live || desc2->used))
+ {
+ reuse_register(gen, regs, desc2, 0);
+ if(desc2->reg >= 0)
+ {
+ desc1->reg = desc2->reg;
+ desc1->other_reg = desc2->other_reg;
+ set_register_bits(regs, desc1, 1);
+ }
+ }
+ if(desc1->reg < 0)
+ {
+ reuse_register(gen, regs, desc1, 1);
+ if(desc1->reg >= 0)
+ {
+ desc2->reg = desc1->reg;
+ desc2->other_reg = desc1->other_reg;
+ set_register_bits(regs, desc2, 0);
+ }
+ }
+ }
+ }
+ else
+ {
+ if(desc1->value && desc1->reg < 0)
+ {
+ reuse_register(gen, regs, desc1, 0);
+ }
+ if(desc2->value && desc2->reg < 0)
+ {
+ reuse_register(gen, regs, desc2, 0);
+ }
+ }
+ if(desc3->value && desc3->reg < 0)
+ {
+ reuse_register(gen, regs, desc3, 0);
+ }
+
+ /* Assign the remaining registers. */
+
+ if(regs->is_ternary)
+ {
+ if(desc1->value && desc1->reg < 0)
+ {
+ use_cheapest_register(gen, regs, desc1, 0);
+ if(desc1->reg < 0)
+ {
+ return 0;
+ }
+ }
+
+ reuse_duplicate_value(desc1, desc2);
+ reuse_duplicate_value(desc1, desc3);
+
+ if(desc2->value && desc2->reg < 0)
+ {
+ use_cheapest_register(gen, regs, desc2, 0);
+ if(desc2->reg < 0)
+ {
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ if(desc1->value && desc1->reg < 0)
+ {
+ if(desc2->reg >= 0)
+ {
+ desc1->reg = desc2->reg;
+ desc1->other_reg = desc2->other_reg;
+ set_register_bits(regs, desc1, 1);
+ }
+ else
+ {
+ use_cheapest_register(gen, regs, desc1, 1);
+ if(desc1->reg < 0)
+ {
+ return 0;
+ }
+ }
+ }
+
+ if(desc2->value && desc2->reg < 0)
+ {
+ if(desc1->reg >= 0)
+ {
+ desc2->reg = desc1->reg;
+ desc2->other_reg = desc1->other_reg;
+ set_register_bits(regs, desc2, 0);
+ }
+ else
+ {
+ use_cheapest_register(gen, regs, desc2, 0);
+ if(desc2->reg < 0)
+ {
+ return 0;
+ }
+ }
+ }
+ }
+
+ reuse_duplicate_value(desc2, desc3);
+
+ if(desc3->value && desc3->reg < 0)
+ {
+ use_cheapest_register(gen, regs, desc3, 0);
+ if(desc3->reg < 0)
+ {
+ return 0;
+ }
+ }
+
+ for(index = 0; index < regs->num_scratch; index++)
+ {
+ if(regs->scratch[index] < 0)
+ {
+ regs->scratch[index] = use_cheapest_register(gen, regs,
0, 0);
+ jit_reg_set_used(regs->assigned, regs->scratch[index]);
+ jit_reg_set_used(regs->clobber, regs->scratch[index]);
+ }
+ }
+
+ return 1;
+}
+
+int
+_jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs)
+{
+ _jit_regdesc_t *desc1;
+ _jit_regdesc_t *desc2;
+ _jit_regdesc_t *desc3;
+ int reg;
+
+ desc1 = ®s->descs[0];
+ desc2 = ®s->descs[1];
+ desc3 = ®s->descs[2];
+
+ /* Load values. */
+ if(regs->is_ternary)
+ {
+ load_triple(gen, desc1, desc2, desc3);
+ }
+ else
+ {
+ if(desc1->value)
+ {
+ /* To avoid spilling the value that we are about to
+ change pretend that its current content is already
+ in the frame. The correct flags will be set by the
+ _jit_regs_commit() function. */
+ if(desc1->value->has_global_register)
+ {
+ desc1->value->in_global_register = 1;
+ }
+ else
+ {
+ desc1->value->in_frame = 1;
+ }
+ }
+
+ load_couple(gen, desc2, desc3);
+ }
+
+ /* Spill clobbered registers. */
+ for(reg = 0; reg < JIT_NUM_REGS; reg++)
+ {
+ if(jit_reg_is_used(regs->clobber, reg))
+ {
+ if(jit_reg_is_used(gen->permanent, reg))
+ {
+ /* Oops, global register. */
+ _jit_gen_spill_global(gen,
gen->contents[reg].values[0]);
+ }
+ else
+ {
+ spill_register(gen, reg);
+ }
+ }
+ }
+
+ return 1;
+}
+
+void
+_jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs)
+{
+ _jit_regdesc_t *desc1;
+ int reg;
+
+ desc1 = ®s->descs[0];
+
+ /* If the output register is used in this basic block remember it.
+ Otherwise spill it. */
+ if(!regs->is_ternary && desc1->value)
+ {
+ if(desc1->used)
+ {
+ set_register(gen, desc1, 0);
+ }
+ else
+ {
+ if(desc1->value->has_global_register)
+ {
+ if(desc1->value->global_reg != desc1->reg)
+ {
+ _jit_gen_spill_reg(gen, desc1->reg,
desc1->other_reg, desc1->value);
+ }
+ desc1->value->in_register = 0;
+ desc1->value->in_global_register = 1;
+ }
+ else
+ {
+ _jit_gen_spill_reg(gen, desc1->reg,
desc1->other_reg, desc1->value);
+ desc1->value->in_register = 0;
+ desc1->value->in_frame = 1;
+ }
+ }
+
+ jit_reg_clear_used(regs->clobber, desc1->reg);
+ if(desc1->other_reg >= 0)
+ {
+ jit_reg_clear_used(regs->clobber, desc1->other_reg);
+ }
+ }
+
+ /* Load clobbered global registers. */
+ for(reg = 0; reg < JIT_NUM_REGS; reg++)
+ {
+ if(jit_reg_is_used(regs->clobber, reg) &&
jit_reg_is_used(gen->permanent, reg))
+ {
+ _jit_gen_load_global(gen, gen->contents[reg].values[0]);
+ }
+ }
+}
Index: libjit/jit/jit-reg-alloc.h
diff -u libjit/jit/jit-reg-alloc.h:1.6 libjit/jit/jit-reg-alloc.h:1.7
--- libjit/jit/jit-reg-alloc.h:1.6 Sun Jun 6 04:53:08 2004
+++ libjit/jit/jit-reg-alloc.h Sat Feb 18 19:58:10 2006
@@ -57,7 +57,73 @@
void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest);
void _jit_regs_alloc_global(jit_gencode_t gen, jit_function_t func);
void _jit_regs_get_reg_pair(jit_gencode_t gen, int not_this1, int not_this2,
- int not_this3, int *reg,
int *reg2);
+ int not_this3, int *reg, int *reg2);
+
+
+/*
+ * New Reg Alloc API
+ */
+
+/*
+ * The maximum number of values per instruction.
+ */
+#define _JIT_REGS_VALUE_MAX 3
+
+/*
+ * The maximum number of temporaries per instruction.
+ */
+#define _JIT_REGS_SCRATCH_MAX 4
+
+/*
+ * Contains register assignment data for single operand.
+ */
+typedef struct
+{
+ jit_value_t value;
+ short reg;
+ short other_reg;
+ unsigned clobber : 1;
+ unsigned live : 1;
+ unsigned used : 1;
+
+} _jit_regdesc_t;
+
+/*
+ * Contains register assignment data for instruction.
+ */
+typedef struct
+{
+ int is_ternary;
+ int is_commutative;
+
+ _jit_regdesc_t descs[_JIT_REGS_VALUE_MAX];
+ int num_descs;
+
+ int scratch[_JIT_REGS_SCRATCH_MAX];
+ int num_scratch;
+
+ jit_regused_t assigned;
+ jit_regused_t clobber;
+
+} _jit_regs_t;
+
+void _jit_regs_init(_jit_regs_t *regs, int is_ternary, int is_commutative);
+void _jit_regs_set_dest(_jit_regs_t *regs, jit_insn_t insn, int clobber, int
reg, int other_reg);
+void _jit_regs_set_value1(_jit_regs_t *regs, jit_insn_t insn, int clobber, int
reg, int other_reg);
+void _jit_regs_set_value2(_jit_regs_t *regs, jit_insn_t insn, int clobber, int
reg, int other_reg);
+void _jit_regs_set_scratch(_jit_regs_t *regs, int reg);
+void _jit_regs_clobber(_jit_regs_t *regs, int reg);
+void _jit_regs_clobber_all(_jit_regs_t *regs);
+int _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs);
+int _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs);
+void _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs);
+int _jit_regs_dest(_jit_regs_t *regs);
+int _jit_regs_value1(_jit_regs_t *regs);
+int _jit_regs_value2(_jit_regs_t *regs);
+int _jit_regs_dest_other(_jit_regs_t *regs);
+int _jit_regs_value1_other(_jit_regs_t *regs);
+int _jit_regs_value2_other(_jit_regs_t *regs);
+int _jit_regs_scratch(_jit_regs_t *regs, int index);
#ifdef __cplusplus
};
Index: libjit/jit/jit-rules-arm.c
diff -u libjit/jit/jit-rules-arm.c:1.20 libjit/jit/jit-rules-arm.c:1.21
--- libjit/jit/jit-rules-arm.c:1.20 Fri Jun 18 06:51:33 2004
+++ libjit/jit/jit-rules-arm.c Sat Feb 18 19:58:10 2006
@@ -761,6 +761,11 @@
jit_cache_end_output();
}
+void _jit_gen_spill_global(jit_gencode_t gen, jit_value_t value)
+{
+ /* TODO: Implement if ARM needs it. */
+}
+
void _jit_gen_load_global(jit_gencode_t gen, jit_value_t value)
{
jit_cache_setup_output(32);
Index: libjit/jit/jit-rules-interp.c
diff -u libjit/jit/jit-rules-interp.c:1.23 libjit/jit/jit-rules-interp.c:1.24
--- libjit/jit/jit-rules-interp.c:1.23 Wed Jan 11 00:24:43 2006
+++ libjit/jit/jit-rules-interp.c Sat Feb 18 19:58:10 2006
@@ -906,6 +906,21 @@
}
/*@
+ * @deftypefun void _jit_gen_spill_global (jit_gencode_t gen, jit_value_t
value)
+ * Spill the contents of @code{value} from its corresponding global register.
+ * This is used in rare cases when a machine instruction requires its operand
+ * to be in the specific register that happens to be global. In such cases the
+ * register is spilled just before the instruction and loaded back immediately
+ * after it.
+ * @end deftypefun
address@hidden/
+void _jit_gen_spill_global(jit_gencode_t gen, jit_value_t value)
+{
+ /* Global registers are not used in the interpreted back end */
+}
+
+
+/*@
* @deftypefun void _jit_gen_load_global (jit_gencode_t gen, jit_value_t value)
* Load the contents of @code{value} into its corresponding global register.
* This is used at the head of a function to pull parameters out of stack
Index: libjit/jit/jit-rules-x86.c
diff -u libjit/jit/jit-rules-x86.c:1.28 libjit/jit/jit-rules-x86.c:1.29
--- libjit/jit/jit-rules-x86.c:1.28 Mon Jan 30 11:35:02 2006
+++ libjit/jit/jit-rules-x86.c Sat Feb 18 19:58:10 2006
@@ -1135,6 +1135,15 @@
jit_cache_end_output();
}
+void _jit_gen_spill_global(jit_gencode_t gen, jit_value_t value)
+{
+ jit_cache_setup_output(16);
+ _jit_gen_fix_value(value);
+ x86_mov_membase_reg(inst, X86_EBP, value->frame_offset,
+ _jit_reg_info[value->global_reg].cpu_reg,
sizeof(void *));
+ jit_cache_end_output();
+}
+
void _jit_gen_load_global(jit_gencode_t gen, jit_value_t value)
{
jit_cache_setup_output(16);
Index: libjit/jit/jit-rules.h
diff -u libjit/jit/jit-rules.h:1.10 libjit/jit/jit-rules.h:1.11
--- libjit/jit/jit-rules.h:1.10 Thu Jun 24 04:11:46 2004
+++ libjit/jit/jit-rules.h Sat Feb 18 19:58:10 2006
@@ -99,6 +99,7 @@
#if !defined(jit_regused_init)
typedef jit_uint jit_regused_t;
#define jit_regused_init (0)
+#define jit_regused_init_used (~0)
#define jit_reg_is_used(mask,reg) \
(((mask) & (((jit_uint)1) << (reg))) != 0)
#define jit_reg_set_used(mask,reg) ((mask) |=
(((jit_uint)1) << (reg)))
@@ -192,6 +193,7 @@
int other_reg, int value_used);
void _jit_gen_load_value
(jit_gencode_t gen, int reg, int other_reg, jit_value_t value);
+void _jit_gen_spill_global(jit_gencode_t gen, jit_value_t value);
void _jit_gen_load_global(jit_gencode_t gen, jit_value_t value);
void _jit_gen_fix_value(jit_value_t value);
void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [dotgnu-pnet-commits] libjit ./ChangeLog jit/jit-reg-alloc.h jit/jit-...,
Aleksey Demakov <=