+2007-06-10 Aleksey Demakov <ademakov@gmail.com>
+
+ * tools/gen-rules-parser.y (gensel_output_clauses): alter selection
+ logic so that "reg" rules are chosen over "local" in case the value
+ is used again in the same basic block.
+
+ * jit/jit-rules-x86.ins: tweak COPY rules for bytes, shorts, and
+ ints.
+
+ * jit/jit-live.c (forward_propagation, backward_propagation)
+ (is_copy_insn): do not perform copy propagation if JIT_OP_COPY_INT
+ is used for byte and short values.
+
2007-05-28 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-live.c (forward_propagation, backward_propagation): do not
}
#if defined(USE_FORWARD_PROPAGATION) || defined(USE_BACKWARD_PROPAGATION)
+/*
+ * Check if the instruction is eligible for copy propagation.
+ */
static int
-is_copy_opcode(int opcode)
+is_copy_insn(jit_insn_t insn)
{
- switch(opcode)
+ jit_type_t dtype;
+ jit_type_t vtype;
+
+ if (!insn || !insn->dest || !insn->value1)
+ {
+ return 0;
+ }
+
+ switch(insn->opcode)
{
case JIT_OP_COPY_INT:
+ /* Currently JIT_INSN_COPY_INT is used not only for int-to-int
+ copying but for byte-to-int and short-to-int copying too
+ (see jit_insn_convert). Propagation of byte and short values
+ to instructions that expect ints might confuse them. */
+ dtype = jit_type_normalize(insn->dest->type);
+ vtype = jit_type_normalize(insn->value1->type);
+ if(dtype != vtype)
+ {
+ /* signed/unsigned int conversion should be safe */
+ if((dtype->kind == JIT_TYPE_INT || dtype->kind == JIT_TYPE_UINT)
+ && (vtype->kind == JIT_TYPE_INT || vtype->kind == JIT_TYPE_UINT))
+ {
+ return 1;
+ }
+ return 0;
+ }
+ return 1;
+
+ case JIT_OP_COPY_LOAD_SBYTE:
+ case JIT_OP_COPY_LOAD_UBYTE:
+ case JIT_OP_COPY_LOAD_SHORT:
+ case JIT_OP_COPY_LOAD_USHORT:
case JIT_OP_COPY_LONG:
case JIT_OP_COPY_FLOAT32:
case JIT_OP_COPY_FLOAT64:
case JIT_OP_COPY_NFLOAT:
- /*case JIT_OP_STRUCT:*/
+ case JIT_OP_COPY_STRUCT:
+ case JIT_OP_COPY_STORE_BYTE:
+ case JIT_OP_COPY_STORE_SHORT:
return 1;
}
+
return 0;
}
#endif
jit_insn_iter_init(&iter, block);
while((insn = jit_insn_iter_next(&iter)) != 0)
{
- if(!is_copy_opcode(insn->opcode))
+ if(!is_copy_insn(insn))
{
continue;
}
dest = insn->dest;
- if(dest == 0 || dest->is_constant)
- {
- continue;
- }
-
value = insn->value1;
- if(value == 0)
- {
- continue;
- }
/* Discard copy to itself */
if(dest == value)
{
continue;
}
+ if(value->is_addressable || value->is_volatile)
+ {
+ continue;
+ }
iter2 = iter;
while((insn2 = jit_insn_iter_next(&iter2)) != 0)
jit_insn_iter_init_last(&iter, block);
while((insn = jit_insn_iter_previous(&iter)) != 0)
{
- if(!is_copy_opcode(insn->opcode))
+ if(!is_copy_insn(insn))
{
continue;
}
dest = insn->dest;
- if(dest == 0 || dest->is_constant)
- {
- continue;
- }
- if(dest->is_addressable || dest->is_volatile)
- {
- continue;
- }
-
value = insn->value1;
- if(value == 0)
- {
- continue;
- }
- if(value->is_addressable || value->is_volatile)
- {
- continue;
- }
/* Discard copy to itself */
if(dest == value)
continue;
}
+ if(dest->is_addressable || dest->is_volatile)
+ {
+ continue;
+ }
+ if(value->is_addressable || value->is_volatile)
+ {
+ continue;
+ }
+
iter2 = iter;
while((insn2 = jit_insn_iter_previous(&iter2)) != 0)
{
* Data manipulation.
*/
-JIT_OP_COPY_LOAD_SBYTE: copy
- [reg] -> {}
-
-JIT_OP_COPY_LOAD_UBYTE: copy
- [reg] -> {}
-
-JIT_OP_COPY_LOAD_SHORT: copy
+JIT_OP_COPY_LOAD_SBYTE, JIT_OP_COPY_LOAD_UBYTE, JIT_OP_COPY_STORE_BYTE: copy
+ [=local, imm] -> {
+ x86_mov_membase_imm(inst, X86_EBP, $1, $2, 1);
+ }
+ [=local, breg] -> {
+ x86_mov_membase_reg(inst, X86_EBP, $1, $2, 1);
+ }
[reg] -> {}
-JIT_OP_COPY_LOAD_USHORT: copy
+JIT_OP_COPY_LOAD_SHORT, JIT_OP_COPY_LOAD_USHORT, JIT_OP_COPY_STORE_SHORT: copy
+ [=local, imm] -> {
+ x86_mov_membase_imm(inst, X86_EBP, $1, $2, 2);
+ }
+ [=local, reg] -> {
+ x86_mov_membase_reg(inst, X86_EBP, $1, $2, 2);
+ }
[reg] -> {}
JIT_OP_COPY_INT: copy
+ [=local, imm] -> {
+ x86_mov_membase_imm(inst, X86_EBP, $1, $2, 4);
+ }
[reg] -> {}
JIT_OP_COPY_LONG: copy
jit_type_get_size(jit_value_get_type(insn->dest)));
}
-JIT_OP_COPY_STORE_BYTE:
- [=frame, imm] -> {
- x86_mov_membase_imm(inst, X86_EBP, $1, $2, 1);
- }
- [=frame, breg] -> {
- x86_mov_membase_reg(inst, X86_EBP, $1, $2, 1);
- }
-
-JIT_OP_COPY_STORE_SHORT:
- [=frame, imm] -> {
- x86_mov_membase_imm(inst, X86_EBP, $1, $2, 2);
- }
- [=frame, reg] -> {
- x86_mov_membase_reg(inst, X86_EBP, $1, $2, 2);
- }
-
JIT_OP_ADDRESS_OF:
[=reg, frame] -> {
x86_lea_membase(inst, $1, X86_EBP, $2);
#include <config.h>
#include <stdio.h>
+#include <ctype.h>
#ifdef HAVE_STRING_H
#include <string.h>
#elif defined(HAVE_STRINGS_H)
}
/*
- * Create string value.
+ * Create literal string value.
*/
static gensel_value_t
gensel_create_string_value(char *value)
}
/*
- * Create string value.
+ * Create register class value.
*/
static gensel_value_t
gensel_create_regclass_value(char *value)
gensel_output_register(name, pattern->values->value, pattern->values->next);
}
+/*
+ * Create an upper-case copy of a string.
+ */
+static char *
+gensel_string_upper(char *string)
+{
+ char *cp;
+ if(string)
+ {
+ string = strdup(string);
+ for(cp = string; *cp; cp++)
+ {
+ *cp = toupper(*cp);
+ }
+ }
+ return string;
+}
+
/*
* Output the clauses for a rule.
*/
int ternary, free_dest;
int contains_registers;
gensel_regclass_t regclass;
+ char *uc_arg;
/* If the clause is manual, then output it as-is */
if(gensel_search_option(options, GENSEL_OPT_MANUAL))
printf("!insn->%s->is_constant && ", args[index]);
printf("!insn->%s->in_register && ", args[index]);
printf("!insn->%s->has_global_register", args[index]);
+ /* If the value is used again in the same basic block
+ it is highly likely that using a register instead
+ of the stack will be a win. Assume that if the
+ "local" pattern is not the last one then it must
+ be followed by a "reg" pattern. */
+ uc_arg = gensel_string_upper(args[index]);
+ printf("&& (insn->flags & JIT_INSN_%s_NEXT_USE) == 0", uc_arg);
+ free(uc_arg);
seen_option = 1;
++index;
break;