* Branch opcodes.
*/
-/* TODO */
+JIT_OP_BR: spill_before
+ [] -> {
+ inst = output_branch(inst, 0xE9, insn);
+ }
+
+JIT_OP_BR_IFALSE: unary_branch
+ [reg] -> {
+ x86_alu_reg_reg(inst, X86_OR, $1, $1);
+ inst = output_branch(inst, 0x74 /* eq */, insn);
+ }
+
+JIT_OP_BR_ITRUE: unary_branch
+ [reg] -> {
+ x86_alu_reg_reg(inst, X86_OR, $1, $1);
+ inst = output_branch(inst, 0x75 /* ne */, insn);
+ }
+
+JIT_OP_BR_IEQ: binary_branch
+ [reg, immzero] -> {
+ x86_alu_reg_reg(inst, X86_OR, $1, $1);
+ inst = output_branch(inst, 0x74 /* eq */, insn);
+ }
+ [reg, imm] -> {
+ x86_alu_reg_imm(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x74 /* eq */, insn);
+ }
+ [reg, local] -> {
+ x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
+ inst = output_branch(inst, 0x74 /* eq */, insn);
+ }
+ [reg, reg] -> {
+ x86_alu_reg_reg(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x74 /* eq */, insn);
+ }
+
+JIT_OP_BR_INE: binary_branch
+ [reg, immzero] -> {
+ x86_alu_reg_reg(inst, X86_OR, $1, $1);
+ inst = output_branch(inst, 0x75 /* ne */, insn);
+ }
+ [reg, imm] -> {
+ x86_alu_reg_imm(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x75 /* ne */, insn);
+ }
+ [reg, local] -> {
+ x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
+ inst = output_branch(inst, 0x75 /* ne */, insn);
+ }
+ [reg, reg] -> {
+ x86_alu_reg_reg(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x75 /* ne */, insn);
+ }
+
+JIT_OP_BR_ILT: binary_branch
+ [reg, imm] -> {
+ x86_alu_reg_imm(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x7C /* lt */, insn);
+ }
+ [reg, local] -> {
+ x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
+ inst = output_branch(inst, 0x7C /* lt */, insn);
+ }
+ [reg, reg] -> {
+ x86_alu_reg_reg(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x7C /* lt */, insn);
+ }
+
+JIT_OP_BR_ILT_UN: binary_branch
+ [reg, imm] -> {
+ x86_alu_reg_imm(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x72 /* lt_un */, insn);
+ }
+ [reg, local] -> {
+ x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
+ inst = output_branch(inst, 0x72 /* lt_un */, insn);
+ }
+ [reg, reg] -> {
+ x86_alu_reg_reg(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x72 /* lt_un */, insn);
+ }
+
+JIT_OP_BR_ILE: binary_branch
+ [reg, imm] -> {
+ x86_alu_reg_imm(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x7E /* le */, insn);
+ }
+ [reg, local] -> {
+ x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
+ inst = output_branch(inst, 0x7E /* le */, insn);
+ }
+ [reg, reg] -> {
+ x86_alu_reg_reg(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x7E /* le */, insn);
+ }
+
+JIT_OP_BR_ILE_UN: binary_branch
+ [reg, imm] -> {
+ x86_alu_reg_imm(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x76 /* le_un */, insn);
+ }
+ [reg, local] -> {
+ x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
+ inst = output_branch(inst, 0x76 /* le_un */, insn);
+ }
+ [reg, reg] -> {
+ x86_alu_reg_reg(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x76 /* le_un */, insn);
+ }
+
+JIT_OP_BR_IGT: binary_branch
+ [reg, imm] -> {
+ x86_alu_reg_imm(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x7F /* gt */, insn);
+ }
+ [reg, local] -> {
+ x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
+ inst = output_branch(inst, 0x7F /* gt */, insn);
+ }
+ [reg, reg] -> {
+ x86_alu_reg_reg(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x7F /* gt */, insn);
+ }
+
+JIT_OP_BR_IGT_UN: binary_branch
+ [reg, imm] -> {
+ x86_alu_reg_imm(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x77 /* gt_un */, insn);
+ }
+ [reg, local] -> {
+ x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
+ inst = output_branch(inst, 0x77 /* gt_un */, insn);
+ }
+ [reg, reg] -> {
+ x86_alu_reg_reg(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x77 /* gt_un */, insn);
+ }
+
+JIT_OP_BR_IGE: binary_branch
+ [reg, imm] -> {
+ x86_alu_reg_imm(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x7D /* ge */, insn);
+ }
+ [reg, local] -> {
+ x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
+ inst = output_branch(inst, 0x7D /* ge */, insn);
+ }
+ [reg, reg] -> {
+ x86_alu_reg_reg(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x7D /* ge */, insn);
+ }
+
+JIT_OP_BR_IGE_UN: binary_branch
+ [reg, imm] -> {
+ x86_alu_reg_imm(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x73 /* ge_un */, insn);
+ }
+ [reg, local] -> {
+ x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
+ inst = output_branch(inst, 0x73 /* ge_un */, insn);
+ }
+ [reg, reg] -> {
+ x86_alu_reg_reg(inst, X86_CMP, $1, $2);
+ inst = output_branch(inst, 0x73 /* ge_un */, insn);
+ }
/*
* Comparison opcodes.
*/
JIT_OP_IEQ: binary
+ [reg, immzero] -> {
+ x86_alu_reg_reg(inst, X86_OR, $1, $1);
+ inst = setcc_reg(inst, $1, X86_CC_EQ, 0);
+ }
[reg, imm] -> {
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
inst = setcc_reg(inst, $1, X86_CC_EQ, 0);
}
JIT_OP_INE: binary
+ [reg, immzero] -> {
+ x86_alu_reg_reg(inst, X86_OR, $1, $1);
+ inst = setcc_reg(inst, $1, X86_CC_NE, 0);
+ }
[reg, imm] -> {
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
inst = setcc_reg(inst, $1, X86_CC_NE, 0);
#define GENSEL_OPT_UNARY 0x0004
#define GENSEL_OPT_TERNARY 0x0008
#define GENSEL_OPT_STACK 0x0010
+#define GENSEL_OPT_UNARY_BRANCH 0x0020
+#define GENSEL_OPT_BINARY_BRANCH 0x0040
/*
* Pattern values.
#define GENSEL_PATT_LREG 2
#define GENSEL_PATT_FREG 3
#define GENSEL_PATT_IMM 4
-#define GENSEL_PATT_IMMS8 5
-#define GENSEL_PATT_IMMU8 6
-#define GENSEL_PATT_IMMS16 7
-#define GENSEL_PATT_IMMU16 8
-#define GENSEL_PATT_LOCAL 9
+#define GENSEL_PATT_IMMZERO 5
+#define GENSEL_PATT_IMMS8 6
+#define GENSEL_PATT_IMMU8 7
+#define GENSEL_PATT_IMMS16 8
+#define GENSEL_PATT_IMMU16 9
+#define GENSEL_PATT_LOCAL 10
/*
* Information about clauses.
}
break;
+ case GENSEL_PATT_IMMZERO: break;
+
case GENSEL_PATT_IMM:
case GENSEL_PATT_IMMS8:
case GENSEL_PATT_IMMU8:
break;
case GENSEL_PATT_IMM:
+ case GENSEL_PATT_IMMZERO:
case GENSEL_PATT_IMMS8:
case GENSEL_PATT_IMMU8:
case GENSEL_PATT_IMMS16:
flag1 = "VALUE1";
flag2 = "VALUE2";
flag3 = "??";
- destroy1 = 1;
+ if((options & (GENSEL_OPT_BINARY_BRANCH |
+ GENSEL_OPT_UNARY_BRANCH)) != 0)
+ {
+ destroy1 = 0;
+ }
+ else
+ {
+ destroy1 = 1;
+ }
destroy2 = 0;
destroy3 = 0;
}
/* If all of the clauses start with a register, then load the first
value into a register before we start checking cases */
check_index = 0;
- if((options & (GENSEL_OPT_BINARY | GENSEL_OPT_UNARY)) != 0 &&
+ if((options & (GENSEL_OPT_BINARY | GENSEL_OPT_UNARY |
+ GENSEL_OPT_BINARY_BRANCH | GENSEL_OPT_UNARY_BRANCH)) != 0 &&
(options & GENSEL_OPT_STACK) == 0)
{
clause = clauses;
}
if(!clause)
{
- printf("\treg = _jit_regs_load_value(gen, %s, 1, ", arg1);
+ printf("\treg = _jit_regs_load_value(gen, %s, %d, ",
+ arg1, destroy1);
printf("(insn->flags & (JIT_INSN_%s_NEXT_USE | "
"JIT_INSN_%s_LIVE)));\n", flag1, flag1);
check_index = 1;
}
break;
+ case GENSEL_PATT_IMMZERO:
+ {
+ printf("%s->is_nint_constant && ", arg);
+ printf("%s->address == 0", arg);
+ }
+ break;
+
case GENSEL_PATT_IMMS8:
{
printf("%s->is_nint_constant && ", arg);
}
break;
+ case GENSEL_PATT_IMMZERO: break;
+
case GENSEL_PATT_IMM:
case GENSEL_PATT_IMMS8:
case GENSEL_PATT_IMMU8:
gensel_first_stack_reg);
}
}
+ if((options & (GENSEL_OPT_BINARY_BRANCH |
+ GENSEL_OPT_UNARY_BRANCH)) != 0)
+ {
+ /* Spill all registers back to their original positions */
+ printf("\t\t_jit_gen_spill_all(gen);\n");
+ }
gensel_output_clause(clause);
printf("\t}\n");
first = 0;
%token K_LREG "long register"
%token K_FREG "float register"
%token K_IMM "immediate value"
+%token K_IMMZERO "immediate zero value"
%token K_IMMS8 "immediate signed 8-bit value"
%token K_IMMU8 "immediate unsigned 8-bit value"
%token K_IMMS16 "immediate signed 16-bit value"
%token K_SPILL_BEFORE "`spill_before'"
%token K_BINARY "`binary'"
%token K_UNARY "`unary'"
+%token K_UNARY_BRANCH "`unary_branch'"
+%token K_BINARY_BRANCH "`binary_branch'"
%token K_TERNARY "`ternary'"
%token K_STACK "`stack'"
%token K_INST_TYPE "`%inst_type'"
%type <code> CODE_BLOCK
%type <options> Options OptionList Option PatternElement
%type <clauses> Clauses Clause
-%type <pattern> Pattern
+%type <pattern> Pattern Pattern2
%expect 0
: K_SPILL_BEFORE { $$ = GENSEL_OPT_SPILL_BEFORE; }
| K_BINARY { $$ = GENSEL_OPT_BINARY; }
| K_UNARY { $$ = GENSEL_OPT_UNARY; }
+ | K_UNARY_BRANCH { $$ = GENSEL_OPT_UNARY_BRANCH; }
+ | K_BINARY_BRANCH { $$ = GENSEL_OPT_BINARY_BRANCH; }
| K_TERNARY { $$ = GENSEL_OPT_TERNARY; }
| K_STACK { $$ = GENSEL_OPT_STACK; }
;
;
Pattern
+ : /* empty */ {
+ $$.elem[0] = GENSEL_PATT_END;
+ $$.size = 0;
+ }
+ | Pattern2 { $$ = $1; }
+ ;
+
+Pattern2
: PatternElement {
$$.elem[0] = $1;
$$.elem[1] = GENSEL_PATT_END;
$$.size = 1;
}
- | Pattern ',' PatternElement {
+ | Pattern2 ',' PatternElement {
$$.elem[$1.size] = $3;
$$.elem[$1.size + 1] = GENSEL_PATT_END;
$$.size = $1.size + 1;
| K_LREG { $$ = GENSEL_PATT_LREG; }
| K_FREG { $$ = GENSEL_PATT_FREG; }
| K_IMM { $$ = GENSEL_PATT_IMM; }
+ | K_IMMZERO { $$ = GENSEL_PATT_IMMZERO; }
| K_IMMS8 { $$ = GENSEL_PATT_IMMS8; }
| K_IMMU8 { $$ = GENSEL_PATT_IMMU8; }
| K_IMMS16 { $$ = GENSEL_PATT_IMMS16; }