fix problem with restarted compilation getting constants as already loaded.
allow long pairs to use EBX even if it is used as a global register.
+2006-06-03 avd <avd@buzz.wiraqocha.local>
+
+ * jit/jit-rules-x86.ins: remove _jit_regs_free_reg() call from
+ JIT_OP_RETURN_FLOAT32, JIT_OP_PUSH_FLOAT32, JIT_OP_RETURN_FLOAT64,
+ JIT_OP_RETURN_NFLOAT, JIT_OP_PUSH_FLOAT64, and JIT_OP_PUSH_NFLOAT
+ rules. With new ``gen-rules'' tool it frees wrong register and
+ the right register is anyway freed automatically by the new
+ allocator.
+
+ * jit/jit-reg-alloc.h, jit/jit-reg-alloc.c (_jit_regs_abort): add
+ function to unbind values from registers if the code generation
+ failed. This is required because new allocator may temporary bind
+ constants to registers and if neither _jit_regs_commit() nor
+ _jit_regs_abort() is called the constant value will be left in
+ inconsistent state. The problem shows up when the end of a cache
+ block has been reached and the compilation is restarted with a new
+ block.
+
+ * jit/jit-reg-alloc.c (_jit_regs_begin, _jit_regs_end): add
+ convenience functions.
+
+ * tools/gen-rules-parser.y (gensel_output_clauses): make generated
+ code more readable by using _jit_regs_begin() and _jit_regs_end()
+ where appropriate.
+
+ * jit/jit-reg-alloc.c: allow to load the second part of a register
+ pair to a global register. This is because x86 long arithmetics
+ use 4 registers at once: EAX:EDX and ECX:EBX. At the same time
+ EBX is the global register candidate. If the instruction clobbers
+ the global register, the new allocator automatically pushes it on
+ the stack before and pops after the instruction.
+
+ * jit/jit-function.c (compile_block): modify trace messages.
+
2006-05-28 Klaus Treichel <ktreichel@web.de>
* jit/jit-insn.c: Add a code_label in initialize_setjmp_block just
#ifdef _JIT_COMPILE_DEBUG
unsigned char *p1, *p2;
p1 = gen->posn.ptr;
- printf("Insn %5d: 0x%04x - ", func->builder->insn_count++, insn->opcode);
+ printf("Insn: %5d, Opcode: 0x%04x\n", func->builder->insn_count++, insn->opcode);
+ printf("Start of binary code: 0x%08x\n", p1);
#endif
switch(insn->opcode)
#ifdef _JIT_COMPILE_DEBUG
p2 = gen->posn.ptr;
- printf("%d\n", p2 - p1);
+ printf("Length of binary code: %d\n\n", p2 - p1);
#endif
}
}
@*/
void _jit_regs_spill_all(jit_gencode_t gen)
{
+#ifdef JIT_REG_DEBUG
+ printf("enter _jit_regs_spill_all\n");
+#endif
+
spill_all_between(gen, 0, JIT_NUM_REGS - 1);
+
+#ifdef JIT_REG_DEBUG
+ printf("leave _jit_regs_spill_all\n");
+#endif
}
/*
@*/
void _jit_regs_free_reg(jit_gencode_t gen, int reg, int value_used)
{
+#ifdef JIT_REG_DEBUG
+ printf("enter _jit_regs_free_reg(reg = %d, value_used = %d)\n", reg, value_used);
+#endif
+
free_reg_and_spill(gen, reg, value_used, 0);
+
+#ifdef JIT_REG_DEBUG
+ printf("leave _jit_regs_free_reg\n");
+#endif
}
/*@
#define COST_SPILL_DIRTY_GLOBAL 2
#define COST_SPILL_CLEAN 1
#define COST_SPILL_CLEAN_GLOBAL 1
+#define COST_CLOBBER_GLOBAL 1000
+
+#define ALLOW_CLOBBER_GLOBAL 1
/* Value usage flags. */
#define VALUE_INPUT 1
if(reg >= 0)
{
+ if(jit_reg_is_used(gen->permanent, reg))
+ {
+ return 1;
+ }
for(index = 0; index < gen->contents[reg].num_values; index++)
{
usage = value_usage(regs, gen->contents[reg].values[index]);
return 1;
}
+ if(desc->value->in_register)
+ {
+ reg = desc->value->reg;
+ if(gen->contents[reg].is_long_start)
+ {
+ other_reg = OTHER_REG(reg);
+ }
+ else
+ {
+ other_reg = -1;
+ }
+ }
+ else
+ {
+ reg = -1;
+ other_reg = -1;
+ }
+
if(index > 0 || regs->ternary)
{
+ /* See if the value needs to be loaded or copied or none. */
if(desc->value->has_global_register)
{
if(desc->value->global_reg != desc->reg
- && !(desc->value->in_register && desc->value->reg == desc->reg))
+ && !(desc->value->in_register && reg == desc->reg))
{
desc->copy = 1;
}
{
desc->load = 1;
}
- else if(desc->value->reg != desc->reg)
+ else if(reg != desc->reg)
{
desc->copy = 1;
}
}
+ /* See if the input value needs to be saved before the
+ instruction and if it stays or not in the register
+ after the instruction. */
if(desc->value->is_constant)
{
desc->kill = 1;
}
else if(desc->value->in_register)
{
- reg = desc->value->reg;
- if(gen->contents[reg].is_long_start)
- {
- other_reg = OTHER_REG(reg);
- }
- else
- {
- other_reg = -1;
- }
-
if(desc->used)
{
if(jit_reg_is_used(regs->clobber, reg)
}
}
+ /* See if the value clobbers a global register. In this case the global
+ register is pushed onto stack before the instruction and popped back
+ after it. */
+ if((!desc->value->has_global_register || desc->value->global_reg != desc->reg)
+ && (jit_reg_is_used(gen->permanent, desc->reg)
+ || (desc->other_reg >= 0 && jit_reg_is_used(gen->permanent, desc->other_reg))))
+ {
+ desc->kill = 1;
+ }
+
if(IS_STACK_REG(desc->reg))
{
stack_start = get_stack_start(desc->reg);
{
continue;
}
+#if !ALLOW_CLOBBER_GLOBAL
if(jit_reg_is_used(gen->permanent, other_reg))
{
continue;
}
+#endif
}
else
{
copy_cost = 0;
cost = compute_spill_cost(gen, regs, reg, other_reg);
}
+#if ALLOW_CLOBBER_GLOBAL
+ if(other_reg >= 0 && jit_reg_is_used(gen->permanent, other_reg))
+ {
+ cost += COST_CLOBBER_GLOBAL;
+ }
+#endif
}
#if COST_COPY != 1
}
}
+static void
+abort_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
+{
+ _jit_regdesc_t *desc;
+ int reg, other_reg;
+
+#ifdef JIT_REG_DEBUG
+ printf("abort_input_value(%d)\n", index);
+#endif
+
+ desc = ®s->descs[index];
+ if(!desc->value || desc->duplicate)
+ {
+ return;
+ }
+
+ if(desc->load && desc->value->in_register)
+ {
+ reg = desc->value->reg;
+ if(gen->contents[reg].is_long_start)
+ {
+ other_reg = OTHER_REG(reg);
+ }
+ else
+ {
+ other_reg = -1;
+ }
+
+ if(IS_STACK_REG(reg))
+ {
+ unbind_value(gen, desc->value, reg, -1);
+ remap_stack_down(gen, regs->stack_start, reg);
+ }
+ else
+ {
+ unbind_value(gen, desc->value, reg, other_reg);
+ }
+ }
+}
+
static void
commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
{
free_value(gen, desc->value, desc->reg, desc->other_reg);
}
}
+ else if(desc->kill)
+ {
+ save_value(gen, desc->value, desc->reg, desc->other_reg, 1);
+ }
#ifdef JIT_REG_DEBUG
printf("value = ");
if(jit_reg_is_used(gen->permanent, reg))
{
/* Oops, global register. */
+#ifdef JIT_REG_DEBUG
+ printf("*** Spill global register: %d ***\n", reg);
+#endif
if(regs->branch)
{
/* After the branch is taken there is no way
to load global register back. */
return 0;
}
- _jit_gen_spill_global(gen, reg, gen->contents[reg].values[0]);
+ _jit_gen_spill_global(gen, reg, 0);
continue;
}
{
if(jit_reg_is_used(regs->spill, reg) && jit_reg_is_used(gen->permanent, reg))
{
- _jit_gen_load_global(gen, reg, gen->contents[reg].values[0]);
+ _jit_gen_load_global(gen, reg, 0);
}
}
#endif
}
+void
+_jit_regs_abort(jit_gencode_t gen, _jit_regs_t *regs)
+{
+ if(regs->ternary)
+ {
+ abort_input_value(gen, regs, 0);
+ }
+ abort_input_value(gen, regs, 1);
+ abort_input_value(gen, regs, 2);
+}
+
+unsigned char *
+_jit_regs_inst_ptr(jit_gencode_t gen, int space)
+{
+ unsigned char *inst;
+
+ inst = (unsigned char *)(gen->posn.ptr);
+ if(!jit_cache_check_for_n(&(gen->posn), space))
+ {
+ jit_cache_mark_full(&(gen->posn));
+ return 0;
+ }
+
+ return inst;
+}
+
+unsigned char *
+_jit_regs_begin(jit_gencode_t gen, _jit_regs_t *regs, int space)
+{
+ unsigned char *inst;
+
+ if(!_jit_regs_assign(gen, regs))
+ {
+ return 0;
+ }
+ if(!_jit_regs_gen(gen, regs))
+ {
+ return 0;
+ }
+
+ inst = _jit_regs_inst_ptr(gen, space);
+ if(!inst)
+ {
+ _jit_regs_abort(gen, regs);
+ }
+
+ return inst;
+}
+
+void
+_jit_regs_end(jit_gencode_t gen, _jit_regs_t *regs, unsigned char *inst)
+{
+ gen->posn.ptr = inst;
+ _jit_regs_commit(gen, regs);
+}
+
/*@
* @deftypefun void _jit_regs_lookup (char *name)
* Get register by name.
int _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs);
int _jit_regs_select(_jit_regs_t *regs);
void _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs);
+void _jit_regs_abort(jit_gencode_t gen, _jit_regs_t *regs);
+unsigned char *_jit_regs_inst_ptr(jit_gencode_t gen, int space);
+unsigned char *_jit_regs_begin(jit_gencode_t gen, _jit_regs_t *regs, int space);
+void _jit_regs_end(jit_gencode_t gen, _jit_regs_t *regs, unsigned char *inst);
int _jit_regs_dest(_jit_regs_t *regs);
int _jit_regs_value1(_jit_regs_t *regs);
JIT_OP_RETURN_FLOAT32: unary_note, stack, only
[freg] -> {
- _jit_regs_free_reg(gen, reg, 1);
inst = jump_to_epilog(gen, inst, block);
}
JIT_OP_RETURN_FLOAT64: unary_note, stack, only
[freg] -> {
- _jit_regs_free_reg(gen, reg, 1);
inst = jump_to_epilog(gen, inst, block);
}
JIT_OP_RETURN_NFLOAT: unary_note, stack, only
[freg] -> {
- _jit_regs_free_reg(gen, reg, 1);
inst = jump_to_epilog(gen, inst, block);
}
x86_push_membase(inst, X86_EBP, $1);
gen->stack_changed = 1;
}
- [reg] -> {
+ [freg] -> {
x86_alu_reg_imm(inst, X86_SUB, X86_ESP, sizeof(jit_float32));
x86_fst_membase(inst, X86_ESP, 0, 0, 1);
- _jit_regs_free_reg(gen, reg, 1);
gen->stack_changed = 1;
}
x86_push_membase(inst, X86_EBP, $1);
gen->stack_changed = 1;
}
- [reg] -> {
+ [freg] -> {
x86_alu_reg_imm(inst, X86_SUB, X86_ESP, sizeof(jit_float64));
x86_fst_membase(inst, X86_ESP, 0, 1, 1);
- _jit_regs_free_reg(gen, reg, 1);
gen->stack_changed = 1;
}
x86_alu_reg_imm(inst, X86_SUB, X86_ESP, sizeof(jit_float64));
x86_fst_membase(inst, X86_ESP, 0, 1, 1);
}
- _jit_regs_free_reg(gen, reg, 1);
gen->stack_changed = 1;
}
gensel_output_code(clause->pattern, clause->code, names, other_names, 0);
}
-/*
- * Output a single clause for a rule.
- */
-static void gensel_output_clause(
- gensel_clause_t clause,
- char *names[MAX_PATTERN],
- char *other_names[MAX_PATTERN],
- gensel_option_t options)
-{
- gensel_option_t space, more_space;
-
- /* Cache the instruction pointer into "inst" */
- if(gensel_new_inst_type)
- {
- printf("\t\tjit_gen_load_inst_ptr(gen, inst);\n");
- }
- else
- {
- space = gensel_search_option(clause->pattern, GENSEL_PATT_SPACE);
- more_space = gensel_search_option(options, GENSEL_OPT_MORE_SPACE);
-
- printf("\t\tinst = (%s)(gen->posn.ptr);\n", gensel_inst_type);
- printf("\t\tif(!jit_cache_check_for_n(&(gen->posn), ");
- if(space && space->values && space->values->value)
- {
- printf("(");
- gensel_output_code(
- clause->pattern,
- space->values->value,
- names, other_names, 1);
- printf(")");
- }
- else
- {
- printf("%d", ((more_space == 0)
- ? gensel_reserve_space
- : gensel_reserve_more_space));
- }
- printf("))\n");
- printf("\t\t{\n");
- printf("\t\t\tjit_cache_mark_full(&(gen->posn));\n");
- printf("\t\t\treturn;\n");
- printf("\t\t}\n");
- }
-
- /* Output the clause code */
- gensel_output_clause_code(clause, names, other_names);
-
- /* Copy "inst" back into the generation context */
- if(gensel_new_inst_type)
- {
- printf("\t\tjit_gen_save_inst_ptr(gen, inst);\n");
- }
- else
- {
- printf("\t\tgen->posn.ptr = (unsigned char *)inst;\n");
- }
-}
-
/*
* Output the clauses for a rule.
*/
char *other_names[MAX_PATTERN];
gensel_clause_t clause;
gensel_option_t pattern;
+ gensel_option_t space, more_space;
gensel_value_t values, child;
int first, seen_option;
int regs, imms, locals, scratch, index;
pattern = pattern->next;
}
- if(contains_registers)
+ if(gensel_new_inst_type)
{
- printf("\t\tif(!_jit_regs_assign(gen, ®s))\n");
- printf("\t\t{\n");
- printf("\t\t\treturn;\n");
- printf("\t\t}\n");
- printf("\t\tif(!_jit_regs_gen(gen, ®s))\n");
- printf("\t\t{\n");
- printf("\t\t\treturn;\n");
- printf("\t\t}\n");
+ if(contains_registers)
+ {
+ printf("\t\tif(!_jit_regs_assign(gen, ®s))\n");
+ printf("\t\t{\n");
+ printf("\t\t\treturn;\n");
+ printf("\t\t}\n");
+ printf("\t\tif(!_jit_regs_gen(gen, ®s))\n");
+ printf("\t\t{\n");
+ printf("\t\t\treturn;\n");
+ printf("\t\t}\n");
+ }
+ printf("\t\tjit_gen_load_inst_ptr(gen, inst);\n");
}
+ else
+ {
+ space = gensel_search_option(clause->pattern, GENSEL_PATT_SPACE);
+ more_space = gensel_search_option(options, GENSEL_OPT_MORE_SPACE);
+
+ if(contains_registers)
+ {
+ printf("\t\tif(!(inst = (%s)_jit_regs_begin(gen, ®s, ", gensel_inst_type);
+ }
+ else
+ {
+ printf("\t\tinst = (%s)(gen->posn.ptr);\n", gensel_inst_type);
+ printf("\t\tif(!jit_cache_check_for_n(&(gen->posn), ");
+ }
+ if(space && space->values && space->values->value)
+ {
+ printf("(");
+ gensel_build_imm_arg_index(
+ clause->pattern, MAX_PATTERN,
+ names, other_names, ternary, free_dest);
+ gensel_output_code(
+ clause->pattern,
+ space->values->value,
+ names, other_names, 1);
+ printf(")");
+ }
+ else
+ {
+ printf("%d", ((more_space == 0)
+ ? gensel_reserve_space
+ : gensel_reserve_more_space));
+ }
+ if(contains_registers)
+ {
+ printf(")))\n");
+ printf("\t\t{\n");
+ printf("\t\t\treturn;\n");
+ printf("\t\t}\n");
+ }
+ else
+ {
+ printf("))\n");
+ printf("\t\t{\n");
+ printf("\t\t\tjit_cache_mark_full(&(gen->posn));\n");
+ printf("\t\t\treturn;\n");
+ printf("\t\t}\n");
+ }
+ }
+
regs = 0;
imms = 0;
}
gensel_build_var_index(clause->pattern, names, other_names);
- gensel_output_clause(clause, names, other_names, options);
+ gensel_output_clause_code(clause, names, other_names);
- if(contains_registers)
+ /* Copy "inst" back into the generation context */
+ if(gensel_new_inst_type)
+ {
+ printf("\t\tjit_gen_save_inst_ptr(gen, inst);\n");
+ if(contains_registers)
+ {
+ printf("\t\t_jit_regs_commit(gen, ®s);\n");
+ }
+ }
+ else if(contains_registers)
+ {
+ printf("\t\t_jit_regs_end(gen, ®s, (unsigned char *)inst);\n");
+ }
+ else
{
- printf("\t\t_jit_regs_commit(gen, ®s);\n");
+ printf("\t\tgen->posn.ptr = (unsigned char *)inst;\n");
}
printf("\t}\n");