This adds support for most of double precision arithmetic. The only
missing things are conversions which will be added in the following
patches.

Operations on doubles are made using SSE2 instructions.  We want to
emulate those operations when current system is not equiped with SSE2
capable processor.  This needs fixing.

Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 arch/x86/insn-selector.brg    |  297 +++++++++++++++++++++++++++++++++--------
 include/jit/emulate.h         |    2 +
 include/jit/expression.h      |    7 +
 include/vm/system.h           |   15 ++
 jit/arithmetic-bc.c           |   12 +-
 jit/emulate.c                 |   29 ++++
 jit/invoke-bc.c               |    6 +-
 jit/tree-printer.c            |    6 +
 jit/typeconv-bc.c             |    4 +-
 test/jit/arithmetic-bc-test.c |   10 +-
 10 files changed, 316 insertions(+), 72 deletions(-)

diff --git a/arch/x86/insn-selector.brg b/arch/x86/insn-selector.brg
index 39aaf6e..204b5d5 100644
--- a/arch/x86/insn-selector.brg
+++ b/arch/x86/insn-selector.brg
@@ -167,8 +167,17 @@ freg:      EXPR_FVALUE     0
        result = get_var(s->b_parent, expr->vm_type);
        state->reg1 = result;
 
-       select_insn(s, tree, imm_membase_insn(INSN_MOV_IMM_MEMBASE, 
float_to_uint32(expr->fvalue), esp, -4));
-       select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_XMM, esp, -4, 
result));
+       if (expr->vm_type == J_FLOAT) {
+               select_insn(s, tree, imm_membase_insn(INSN_MOV_IMM_MEMBASE, 
float_to_uint32(expr->fvalue), esp, -4));
+               select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_XMM, 
esp, -4, result));
+       } else {
+               uint32_t high_byte, low_byte;
+
+               double_to_uint64(expr->fvalue, &low_byte, &high_byte);
+               select_insn(s, tree, imm_membase_insn(INSN_MOV_IMM_MEMBASE, 
high_byte, esp, -4));
+               select_insn(s, tree, imm_membase_insn(INSN_MOV_IMM_MEMBASE, 
low_byte, esp, -8));
+               select_insn(s, tree, membase_reg_insn(INSN_MOV_64_MEMBASE_XMM, 
esp, -8, result));
+       }
 }
 
 reg:   EXPR_VALUE      0
@@ -252,12 +261,17 @@ freg:     EXPR_LOCAL 0
        struct var_info *result;
 
        expr = to_expr(tree);
-       slot = get_local_slot(cu->stack_frame, expr->local_index);
 
        result = get_var(s->b_parent, expr->vm_type);
        state->reg1 = result;
 
-       select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_XMM, slot, 
result));
+       if (expr->vm_type == J_FLOAT) {
+               slot = get_local_slot(cu->stack_frame, expr->local_index);
+               select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_XMM, 
slot, result));
+       } else {
+               slot = get_local_slot_64(cu->stack_frame, expr->local_index);
+               select_insn(s, tree, 
memlocal_reg_insn(INSN_MOV_64_MEMLOCAL_XMM, slot, result));
+       }
 }
 
 reg:   EXPR_TEMPORARY 0
@@ -300,6 +314,11 @@ reg:       OP_ADD(reg, reg) 1
        binop_reg_reg_high(state, s, tree, INSN_ADC_REG_REG);
 }
 
+freg:  OP_DADD(freg, freg) 1
+{
+       binop_reg_reg_low(state, s, tree, INSN_FADD_64_REG_REG);
+}
+
 freg:  OP_FADD(freg, freg) 1
 {
        binop_reg_reg_low(state, s, tree, INSN_FADD_REG_REG);
@@ -323,6 +342,11 @@ reg:       OP_SUB(reg, reg) 1
        binop_reg_reg_high(state, s, tree, INSN_SBB_REG_REG);
 }
 
+freg:  OP_DSUB(freg, freg) 1
+{
+       binop_reg_reg_low(state, s, tree, INSN_FSUB_64_REG_REG);
+}
+
 freg:  OP_FSUB(freg, freg) 1
 {
        binop_reg_reg_low(state, s, tree, INSN_FSUB_REG_REG);
@@ -347,6 +371,13 @@ reg:       OP_MUL(reg, reg) 1
        select_insn(s, tree, reg_reg_insn(INSN_MUL_REG_REG, state->left->reg1, 
state->right->reg1));
 }
 
+freg:  OP_DMUL(freg, freg) 1
+{
+       state->reg1 = state->left->reg1;
+
+       select_insn(s, tree, reg_reg_insn(INSN_FMUL_64_REG_REG, 
state->right->reg1, state->left->reg1));
+}
+
 freg:  OP_FMUL(freg, freg) 1
 {
        state->reg1 = state->left->reg1;
@@ -398,6 +429,13 @@ reg:       OP_DIV(reg, reg) 1
        select_insn(s, tree, reg_reg_insn(INSN_DIV_REG_REG, state->right->reg1, 
result));
 }
 
+freg:  OP_DDIV(freg, freg) 1
+{
+       state->reg1 = state->left->reg1;
+
+       select_insn(s, tree, reg_reg_insn(INSN_FDIV_64_REG_REG, 
state->right->reg1, state->left->reg1));
+}
+
 freg:  OP_FDIV(freg, freg) 1
 {
        state->reg1 = state->left->reg1;
@@ -437,18 +475,38 @@ reg:      OP_REM(reg, reg) 1
        select_insn(s, tree, reg_reg_insn(INSN_DIV_REG_REG, state->right->reg1, 
eax));
 }
 
+freg:  OP_DREM(freg, freg) 1
+{
+       struct var_info *esp, *eax;
+
+       state->reg1 = get_var(s->b_parent, J_DOUBLE);
+
+       esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
+       eax = get_fixed_var(s->b_parent, MACH_REG_xAX);
+
+       select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG, 16, esp));
+       select_insn(s, tree, reg_membase_insn(INSN_MOV_64_XMM_MEMBASE, 
state->left->reg1, esp, 0));
+       select_insn(s, tree, reg_membase_insn(INSN_MOV_64_XMM_MEMBASE, 
state->right->reg1, esp, 8));
+
+       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long)fmod));
+       method_args_cleanup(s, tree, 4);
+
+       select_insn(s, tree, membase_insn(INSN_FSTP_64_MEMBASE, esp, -8));
+       select_insn(s, tree, membase_reg_insn(INSN_MOV_64_MEMBASE_XMM, esp, -8, 
state->reg1));
+}
+
 freg:  OP_FREM(freg, freg) 1
 {
        struct var_info *esp, *eax;
 
-       state->reg1 = get_var(s->b_parent, state->left->reg1->vm_type);
+       state->reg1 = get_var(s->b_parent, J_FLOAT);
 
        esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
        eax = get_fixed_var(s->b_parent, MACH_REG_xAX);
 
-       select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->left->reg1, esp, -8));
-       select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->right->reg1, esp, -4));
        select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG, 8, esp));
+       select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->left->reg1, esp, 0));
+       select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->right->reg1, esp, 4));
 
        select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long)fmodf));
        method_args_cleanup(s, tree, 2);
@@ -483,17 +541,32 @@ reg:      OP_NEG(reg) 1
        }
 }
 
+freg:  OP_DNEG(freg) 1
+{
+       struct var_info *result, *esp;
+
+       esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
+
+       result = get_var(s->b_parent, J_DOUBLE);
+
+       select_insn(s, tree, imm_membase_insn(INSN_MOV_IMM_MEMBASE, 0x80000000, 
esp, -4));
+       select_insn(s, tree, imm_membase_insn(INSN_MOV_IMM_MEMBASE, 0x00000000, 
esp, -8));
+       select_insn(s, tree, membase_reg_insn(INSN_MOV_64_MEMBASE_XMM, esp, -8, 
result));
+       select_insn(s, tree, reg_reg_insn(INSN_XOR_64_XMM_REG_REG, 
state->left->reg1, result));
+
+       state->reg1 = result;
+}
+
 freg:  OP_FNEG(freg) 1
 {
        struct var_info *result, *esp;
 
        esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
 
-       result = get_var(s->b_parent, state->left->reg1->vm_type);
+       result = get_var(s->b_parent, J_FLOAT);
 
        select_insn(s, tree, imm_membase_insn(INSN_MOV_IMM_MEMBASE, 0x80000000, 
esp, -4));
        select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_XMM, esp, -4, 
result));
-
        select_insn(s, tree, reg_reg_insn(INSN_XOR_XMM_REG_REG, 
state->left->reg1, result));
 
        state->reg1 = result;
@@ -706,8 +779,14 @@ freg:      EXPR_FINVOKE(arg) 1
        invoke(s, tree, cu, method);
 
        esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
-       select_insn(s, tree, membase_insn(INSN_FSTP_MEMBASE, esp, -4));
-       select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_XMM, esp, -4, 
state->reg1));
+
+       if (ret_vm_type == J_FLOAT) {
+               select_insn(s, tree, membase_insn(INSN_FSTP_MEMBASE, esp, -4));
+               select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_XMM, 
esp, -4, state->reg1));
+       } else {
+               select_insn(s, tree, membase_insn(INSN_FSTP_64_MEMBASE, esp, 
-8));
+               select_insn(s, tree, membase_reg_insn(INSN_MOV_64_MEMBASE_XMM, 
esp, -8, state->reg1));
+       }
 }
 
 reg:   EXPR_INVOKEVIRTUAL(arg) 1
@@ -750,26 +829,44 @@ freg:     EXPR_FINVOKEVIRTUAL(arg) 1
        invokevirtual(state, s, tree);
 
        esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
-       select_insn(s, tree, membase_insn(INSN_FSTP_MEMBASE, esp, -4));
-       select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_XMM, esp, -4, 
state->reg1));
+
+       if (ret_vm_type == J_FLOAT) {
+               select_insn(s, tree, membase_insn(INSN_FSTP_MEMBASE, esp, -4));
+               select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_XMM, 
esp, -4, state->reg1));
+       } else {
+               select_insn(s, tree, membase_insn(INSN_FSTP_64_MEMBASE, esp, 
-8));
+               select_insn(s, tree, membase_reg_insn(INSN_MOV_64_MEMBASE_XMM, 
esp, -8, state->reg1));
+       }
 }
 
 reg:   OP_CMPL(freg, freg) 1
 {
        struct var_info *esp, *eax;
+       enum vm_type type;
+
+       assert(state->left->reg1->vm_type == state->right->reg1->vm_type);
 
+       type = state->left->reg1->vm_type;
        state->reg1 = get_var(s->b_parent, J_INT);
 
        esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
        eax = get_fixed_var(s->b_parent, MACH_REG_xAX);
 
-       select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->left->reg1, esp, -8));
-       select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->right->reg1, esp, -4));
+       if (type == J_FLOAT) {
+               select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG, 8, esp));
+               select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->left->reg1, esp, 0));
+               select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->right->reg1, esp, 4));
 
-       select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG, 8, esp));
+               select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
emulate_fcmpl));
+               method_args_cleanup(s, tree, 2);
+       } else {
+               select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG, 16, esp));
+               select_insn(s, tree, reg_membase_insn(INSN_MOV_64_XMM_MEMBASE, 
state->left->reg1, esp, 0));
+               select_insn(s, tree, reg_membase_insn(INSN_MOV_64_XMM_MEMBASE, 
state->right->reg1, esp, 8));
 
-       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
emulate_fcmpl));
-       method_args_cleanup(s, tree, 2);
+               select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
emulate_dcmpl));
+               method_args_cleanup(s, tree, 4);
+       }
 
        select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, eax, state->reg1));
 }
@@ -777,19 +874,31 @@ reg:      OP_CMPL(freg, freg) 1
 reg:   OP_CMPG(freg, freg) 1
 {
        struct var_info *esp, *eax;
+       enum vm_type type;
 
+       assert(state->left->reg1->vm_type == state->right->reg1->vm_type);
+
+       type = state->left->reg1->vm_type;
        state->reg1 = get_var(s->b_parent, J_INT);
 
        esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
        eax = get_fixed_var(s->b_parent, MACH_REG_xAX);
 
-       select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->left->reg1, esp, -8));
-       select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->right->reg1, esp, -4));
+       if (type == J_FLOAT) {
+               select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG, 8, esp));
+               select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->left->reg1, esp, 0));
+               select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
state->right->reg1, esp, 4));
 
-       select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG, 8, esp));
+               select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
emulate_fcmpg));
+               method_args_cleanup(s, tree, 2);
+       } else {
+               select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG, 16, esp));
+               select_insn(s, tree, reg_membase_insn(INSN_MOV_64_XMM_MEMBASE, 
state->left->reg1, esp, 0));
+               select_insn(s, tree, reg_membase_insn(INSN_MOV_64_XMM_MEMBASE, 
state->right->reg1, esp, 8));
 
-       select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
emulate_fcmpg));
-       method_args_cleanup(s, tree, 2);
+               select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
emulate_dcmpg));
+               method_args_cleanup(s, tree, 4);
+       }
 
        select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, eax, state->reg1));
 }
@@ -989,11 +1098,19 @@ freg:    EXPR_FLOAT_CLASS_FIELD 1
                /* Class is already initialized; no need for fix-up. We also
                 * don't want the fixup if we're already inside the
                 * initializer. */
-               mov_insn = memdisp_reg_insn(INSN_MOV_MEMDISP_XMM,
-                       (unsigned long) vmc->static_values + vmf->offset, out);
+               if (expr->vm_type == J_FLOAT)
+                       mov_insn = memdisp_reg_insn(INSN_MOV_MEMDISP_XMM,
+                               (unsigned long) vmc->static_values + 
vmf->offset, out);
+               else
+                       mov_insn = memdisp_reg_insn(INSN_MOV_64_MEMDISP_XMM,
+                               (unsigned long) vmc->static_values + 
vmf->offset, out);
        } else {
-               mov_insn = memdisp_reg_insn(INSN_MOV_MEMDISP_XMM,
-                       (unsigned long) static_guard_page, out);
+               if (expr->vm_type == J_FLOAT)
+                       mov_insn = memdisp_reg_insn(INSN_MOV_MEMDISP_XMM,
+                                       (unsigned long) static_guard_page, out);
+               else
+                       mov_insn = memdisp_reg_insn(INSN_MOV_64_MEMDISP_XMM,
+                                       (unsigned long) static_guard_page, out);
 
                /* XXX: Check return value */
                add_getstatic_fixup_site(mov_insn, vmf, s->b_parent);
@@ -1034,7 +1151,11 @@ freg:    EXPR_FLOAT_INSTANCE_FIELD(reg) 1
        state->reg1 = get_var(s->b_parent, expr->vm_type);
 
        offset = sizeof(struct vm_object) + expr->instance_field->offset;
-       select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_XMM, base, 
offset, state->reg1));
+
+       if (expr->vm_type == J_FLOAT)
+               select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_XMM, 
base, offset, state->reg1));
+       else
+               select_insn(s, tree, membase_reg_insn(INSN_MOV_64_MEMBASE_XMM, 
base, offset, state->reg1));
 }
 
 %ifdef CONFIG_X86_32
@@ -1433,16 +1554,25 @@ arg:    EXPR_ARG(EXPR_VALUE) 1
 }
 %endif
 
-arg:   EXPR_ARG(EXPR_FVALUE) 1
+arg:   EXPR_ARG(EXPR_FVALUE) 2
 {
        struct expression *expr, *arg_expr;
-       unsigned long long imm;
 
        expr = to_expr(tree);
        arg_expr = to_expr(expr->arg_expression);
-       imm  = float_to_uint32(arg_expr->fvalue);
 
-       select_insn(s, tree, imm_insn(INSN_PUSH_IMM, imm & ~0UL));
+       if (arg_expr->vm_type == J_FLOAT) {
+               uint32_t imm;
+
+               imm  = float_to_uint32(arg_expr->fvalue);
+               select_insn(s, tree, imm_insn(INSN_PUSH_IMM, imm & ~0UL));
+       } else {
+               uint32_t high_byte, low_byte;
+
+               double_to_uint64(expr->fvalue, &low_byte, &high_byte);
+               select_insn(s, tree, imm_insn(INSN_PUSH_IMM, low_byte));
+               select_insn(s, tree, imm_insn(INSN_PUSH_IMM, high_byte));
+       }
 
        state->reg1 = NULL;
 }
@@ -1481,8 +1611,14 @@ arg:     EXPR_ARG(freg)
 
        size = get_vmtype_size(arg_expr->vm_type);
 
-       select_insn(s, tree,
+       if (arg_expr->vm_type == J_FLOAT) {
+               select_insn(s, tree,
                    reg_membase_insn(INSN_MOV_XMM_MEMBASE, src, esp, -size));
+       } else {
+               select_insn(s, tree,
+                   reg_membase_insn(INSN_MOV_64_XMM_MEMBASE, src, esp, -size));
+       }
+
        select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG, size, esp));
 
        state->reg1 = NULL;
@@ -1521,11 +1657,19 @@ arg:    EXPR_ARG(freg)
 
        if (expr->arg_reg != REG_UNASSIGNED) {
                dst = get_fixed_var(s->b_parent, expr->arg_reg);
-               select_insn(s, tree, reg_reg_insn(INSN_MOV_XMM_XMM, src, dst));
+
+               if (arg_expr->vm_type == J_FLOAT)
+                       select_insn(s, tree, reg_reg_insn(INSN_MOV_XMM_XMM, 
src, dst));
+               else
+                       select_insn(s, tree, reg_reg_insn(INSN_MOV_64_XMM_XMM, 
src, dst));
        } else {
                int size = get_vmtype_size(arg_expr->vm_type);
-               select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE,
-                                                     src, esp, -size));
+
+               if (arg_expr->vm_type == J_FLOAT)
+                       select_insn(s, tree, 
reg_membase_insn(INSN_MOV_XMM_MEMBASE, src, esp, -size));
+               else
+                       select_insn(s, tree, 
reg_membase_insn(INSN_MOV_64_XMM_MEMBASE, src, esp, -size));
+
                select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG, size, esp));
        }
 
@@ -1606,8 +1750,13 @@ stmt:    STMT_RETURN(freg) 1
        src = state->left->reg1;
        esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
 
-       select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, src, esp, 
-4));
-       select_insn(s, tree, membase_insn(INSN_FLD_MEMBASE, esp, -4));
+       if (expr->vm_type == J_FLOAT) {
+               select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, 
src, esp, -4));
+               select_insn(s, tree, membase_insn(INSN_FLD_MEMBASE, esp, -4));
+       } else {
+               select_insn(s, tree, reg_membase_insn(INSN_MOV_64_XMM_MEMBASE, 
src, esp, -8));
+               select_insn(s, tree, membase_insn(INSN_FLD_64_MEMBASE, esp, 
-8));
+       }
 
        select_insn(s, tree, branch_insn(INSN_JMP_BRANCH, 
s->b_parent->exit_bb));
 }
@@ -1703,11 +1852,19 @@ stmt:   STMT_STORE(EXPR_FLOAT_CLASS_FIELD, freg)
                /* Class is already initialized; no need for fix-up. We also
                 * don't want the fixup if we're already inside the
                 * initializer. */
-               mov_insn = reg_memdisp_insn(INSN_MOV_XMM_MEMDISP,
-                       src, (unsigned long) vmc->static_values + vmf->offset);
+               if (store_dest->vm_type == J_FLOAT)
+                       mov_insn = reg_memdisp_insn(INSN_MOV_XMM_MEMDISP,
+                               src, (unsigned long) vmc->static_values + 
vmf->offset);
+               else
+                       mov_insn = reg_memdisp_insn(INSN_MOV_64_XMM_MEMDISP,
+                               src, (unsigned long) vmc->static_values + 
vmf->offset);
        } else {
-               mov_insn = reg_memdisp_insn(INSN_MOV_XMM_MEMDISP,
-                       src, (unsigned long) static_guard_page);
+               if (store_dest->vm_type == J_FLOAT)
+                       mov_insn = reg_memdisp_insn(INSN_MOV_XMM_MEMDISP,
+                               src, (unsigned long) static_guard_page);
+               else
+                       mov_insn = reg_memdisp_insn(INSN_MOV_64_XMM_MEMDISP,
+                               src, (unsigned long) static_guard_page);
 
                /* XXX: Check return value */
                add_putstatic_fixup_site(mov_insn, vmf, s->b_parent);
@@ -1772,8 +1929,12 @@ stmt:    STMT_STORE(float_inst_field, freg)
        base = state->left->reg1;
        offset = (unsigned long)state->left->reg2;
 
-       select_insn(s, tree,
+       if (store_src->vm_type == J_FLOAT)
+               select_insn(s, tree,
                    reg_membase_insn(INSN_MOV_XMM_MEMBASE, src, base, offset));
+       else
+               select_insn(s, tree,
+                   reg_membase_insn(INSN_MOV_64_XMM_MEMBASE, src, base, 
offset));
 }
 
 stmt:  STMT_STORE(EXPR_LOCAL, reg)
@@ -1813,9 +1974,14 @@ stmt:    STMT_STORE(EXPR_FLOAT_LOCAL, freg)
 
        stmt = to_stmt(tree);
        local = to_expr(stmt->store_dest);
-       slot = get_local_slot(cu->stack_frame, local->local_index);
 
-       select_insn(s, tree, reg_memlocal_insn(INSN_MOV_XMM_MEMLOCAL, src, 
slot));
+       if (local->vm_type == J_FLOAT) {
+               slot = get_local_slot(cu->stack_frame, local->local_index);
+               select_insn(s, tree, reg_memlocal_insn(INSN_MOV_XMM_MEMLOCAL, 
src, slot));
+       } else {
+               slot = get_local_slot_64(cu->stack_frame, local->local_index);
+               select_insn(s, tree, 
reg_memlocal_insn(INSN_MOV_64_XMM_MEMLOCAL, src, slot));
+       }
 }
 
 %ifdef CONFIG_X86_32
@@ -1855,11 +2021,15 @@ stmt:  STMT_STORE(EXPR_FLOAT_TEMPORARY, 
EXPR_FLOAT_LOCAL) 1
        exprsrc = to_expr(stmt->store_src);
        exprdest = to_expr(stmt->store_dest);
 
-       slot = get_local_slot(s->b_parent->stack_frame, exprsrc->local_index);
-
        dest = exprdest->tmp_low;
 
-       select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_XMM, slot, 
dest));
+       if (exprsrc->vm_type == J_FLOAT) {
+               slot = get_local_slot(s->b_parent->stack_frame, 
exprsrc->local_index);
+               select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_XMM, 
slot, dest));
+       } else {
+               slot = get_local_slot_64(s->b_parent->stack_frame, 
exprsrc->local_index);
+               select_insn(s, tree, 
memlocal_reg_insn(INSN_MOV_64_MEMLOCAL_XMM, slot, dest));
+       }
 }
 %else
 stmt:  STMT_STORE(EXPR_TEMPORARY, EXPR_LOCAL) 1
@@ -1905,19 +2075,24 @@ stmt:  STMT_STORE(EXPR_FLOAT_TEMPORARY, 
EXPR_FLOAT_LOCAL) 1
        exprsrc = to_expr(stmt->store_src);
        exprdest = to_expr(stmt->store_dest);
 
-       slot = get_local_slot(s->b_parent->stack_frame, exprsrc->local_index);
-
        dest = exprdest->tmp_low;
 
        reg = method->args_map[exprsrc->local_index].reg;
        if (reg == REG_UNASSIGNED) {
                index = method->args_map[exprsrc->local_index].stack_index;
                slot = get_local_slot(s->b_parent->stack_frame, index);
-               select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_XMM,
-                                                      slot, dest));
+
+               if (exprsrc->vm_type == J_FLOAT)
+                       select_insn(s, tree, 
memlocal_reg_insn(INSN_MOV_MEMLOCAL_XMM, slot, dest));
+               else
+                       select_insn(s, tree, 
memlocal_reg_insn(INSN_MOV_64_MEMLOCAL_XMM, slot, dest));
        } else {
                src = get_fixed_var(s->b_parent, reg);
-               select_insn(s, tree, reg_reg_insn(INSN_MOV_XMM_XMM, src, dest));
+
+               if (exprsrc->vm_type == J_FLOAT)
+                       select_insn(s, tree, reg_reg_insn(INSN_MOV_XMM_XMM, 
src, dest));
+               else
+                       select_insn(s, tree, reg_reg_insn(INSN_MOV_64_XMM_XMM, 
src, dest));
        }
 }
 %endif
@@ -1955,7 +2130,11 @@ stmt:  STMT_STORE(EXPR_FLOAT_TEMPORARY, freg) 1
 
        dest = temp->tmp_low;
        src = state->right->reg1;
-       select_insn(s, tree, reg_reg_insn(INSN_MOV_XMM_XMM, src, dest));
+
+       if (temp->vm_type == J_FLOAT)
+               select_insn(s, tree, reg_reg_insn(INSN_MOV_XMM_XMM, src, dest));
+       else
+               select_insn(s, tree, reg_reg_insn(INSN_MOV_64_XMM_XMM, src, 
dest));
 }
 
 array_deref:   EXPR_ARRAY_DEREF(reg, reg) 2
@@ -2011,7 +2190,10 @@ stmt:    STMT_STORE(array_deref, freg)
        index = state->left->reg2;
        src = state->right->reg1;
 
-       select_insn(s, tree, reg_memindex_insn(INSN_MOV_XMM_MEMINDEX, src, 
base, index, scale));
+       if (src->vm_type == J_FLOAT)
+               select_insn(s, tree, reg_memindex_insn(INSN_MOV_XMM_MEMINDEX, 
src, base, index, scale));
+       else
+               select_insn(s, tree, 
reg_memindex_insn(INSN_MOV_64_XMM_MEMINDEX, src, base, index, scale));
 }
 
 stmt:  STMT_STORE(reg, array_deref)
@@ -2053,7 +2235,10 @@ stmt:    STMT_STORE(freg, array_deref)
 
        state->reg1 = dest;
 
-       select_insn(s, tree, memindex_reg_insn(INSN_MOV_MEMINDEX_XMM, base, 
index, scale, dest));
+       if (dest->vm_type == J_FLOAT)
+               select_insn(s, tree, memindex_reg_insn(INSN_MOV_MEMINDEX_XMM, 
base, index, scale, dest));
+       else
+               select_insn(s, tree, 
memindex_reg_insn(INSN_MOV_64_MEMINDEX_XMM, base, index, scale, dest));
 }
 
 stmt:  STMT_ARRAY_STORE_CHECK(reg, reg) 1
diff --git a/include/jit/emulate.h b/include/jit/emulate.h
index da6c260..9d75d1f 100644
--- a/include/jit/emulate.h
+++ b/include/jit/emulate.h
@@ -11,5 +11,7 @@ int64_t emulate_lshr(int64_t value1, int32_t value2);
 int64_t emulate_lushr(int64_t value1, int32_t value2);
 int emulate_fcmpl(float value1, float value2);
 int emulate_fcmpg(float value1, float value2);
+int emulate_dcmpl(double value1, double value2);
+int emulate_dcmpg(double value1, double value2);
 
 #endif /* __JIT_EMULATE_H */
diff --git a/include/jit/expression.h b/include/jit/expression.h
index 209f5c5..70a459b 100644
--- a/include/jit/expression.h
+++ b/include/jit/expression.h
@@ -91,12 +91,19 @@ enum binary_operator {
        OP_FDIV,
        OP_FREM,
 
+       OP_DADD,
+       OP_DSUB,
+       OP_DMUL,
+       OP_DDIV,
+       OP_DREM,
+
        BINOP_LAST,     /* Not a real operator. Keep this last. */
 };
 
 enum unary_operator {
        OP_NEG  = BINOP_LAST,
        OP_FNEG,
+       OP_DNEG,
        OP_LAST,        /* Not a real operator. Keep this last. */
 };
 
diff --git a/include/vm/system.h b/include/vm/system.h
index 50a55cc..2ce6012 100644
--- a/include/vm/system.h
+++ b/include/vm/system.h
@@ -53,6 +53,21 @@ static inline int float_to_uint32(float value)
        return a.iv;
 }
 
+static inline void double_to_uint64(double value, uint32_t *low, uint32_t 
*high)
+{
+       union {
+               struct {
+                       uint32_t low;
+                       uint32_t high;
+               };
+               double val;
+       } a;
+
+       a.val = value;
+       *low = a.low;
+       *high = a.high;
+}
+
 static inline double uint64_to_double(uint32_t lowv, uint32_t highv)
 {
        union {
diff --git a/jit/arithmetic-bc.c b/jit/arithmetic-bc.c
index da4ca35..e15de42 100644
--- a/jit/arithmetic-bc.c
+++ b/jit/arithmetic-bc.c
@@ -52,7 +52,7 @@ int convert_fadd(struct parse_context *ctx)
 
 int convert_dadd(struct parse_context *ctx)
 {
-       return convert_binop(ctx, J_DOUBLE, OP_ADD);
+       return convert_binop(ctx, J_DOUBLE, OP_DADD);
 }
 
 int convert_isub(struct parse_context *ctx)
@@ -72,7 +72,7 @@ int convert_fsub(struct parse_context *ctx)
 
 int convert_dsub(struct parse_context *ctx)
 {
-       return convert_binop(ctx, J_DOUBLE, OP_SUB);
+       return convert_binop(ctx, J_DOUBLE, OP_DSUB);
 }
 
 int convert_imul(struct parse_context *ctx)
@@ -92,7 +92,7 @@ int convert_fmul(struct parse_context *ctx)
 
 int convert_dmul(struct parse_context *ctx)
 {
-       return convert_binop(ctx, J_DOUBLE, OP_MUL);
+       return convert_binop(ctx, J_DOUBLE, OP_DMUL);
 }
 
 int convert_idiv(struct parse_context *ctx)
@@ -112,7 +112,7 @@ int convert_fdiv(struct parse_context *ctx)
 
 int convert_ddiv(struct parse_context *ctx)
 {
-       return convert_binop(ctx, J_DOUBLE, OP_DIV);
+       return convert_binop(ctx, J_DOUBLE, OP_DDIV);
 }
 
 int convert_irem(struct parse_context *ctx)
@@ -132,7 +132,7 @@ int convert_frem(struct parse_context *ctx)
 
 int convert_drem(struct parse_context *ctx)
 {
-       return convert_binop(ctx, J_DOUBLE, OP_REM);
+       return convert_binop(ctx, J_DOUBLE, OP_DREM);
 }
 
 static int convert_unary_op(struct parse_context *ctx, enum vm_type vm_type,
@@ -167,7 +167,7 @@ int convert_fneg(struct parse_context *ctx)
 
 int convert_dneg(struct parse_context *ctx)
 {
-       return convert_unary_op(ctx, J_DOUBLE, OP_FNEG);
+       return convert_unary_op(ctx, J_DOUBLE, OP_DNEG);
 }
 
 int convert_ishl(struct parse_context *ctx)
diff --git a/jit/emulate.c b/jit/emulate.c
index 67b6873..21af9ff 100644
--- a/jit/emulate.c
+++ b/jit/emulate.c
@@ -54,6 +54,19 @@ static int __emulate_fcmpx(float value1, float value2)
        return 0;
 }
 
+static int __emulate_dcmpx(double value1, double value2)
+{
+       double tmp;
+       tmp     = value1 - value2;
+
+       if (tmp < 0)
+               return -1;
+       else if (tmp > 0)
+               return 1;
+
+       return 0;
+}
+
 int emulate_fcmpl(float value1, float value2)
 {
        if (isnan(value1) || isnan(value2))
@@ -70,6 +83,22 @@ int emulate_fcmpg(float value1, float value2)
        return __emulate_fcmpx(value1, value2);
 }
 
+int emulate_dcmpl(double value1, double value2)
+{
+       if (isnan(value1) || isnan(value2))
+               return -1;
+
+       return __emulate_dcmpx(value1, value2);
+}
+
+int emulate_dcmpg(double value1, double value2)
+{
+       if (isnan(value1) || isnan(value2))
+               return 1;
+
+       return __emulate_dcmpx(value1, value2);
+}
+
 long long emulate_ldiv(long long value1, long long value2)
 {
        if (value2 == 0) {
diff --git a/jit/invoke-bc.c b/jit/invoke-bc.c
index dd48c42..e65de6c 100644
--- a/jit/invoke-bc.c
+++ b/jit/invoke-bc.c
@@ -201,7 +201,7 @@ int convert_invokevirtual(struct parse_context *ctx)
        if (!invoke_target)
                return warn("unable to resolve invocation target"), -EINVAL;
 
-       if (method_return_type(invoke_target) == J_FLOAT)
+       if (vm_type_is_float(method_return_type(invoke_target)))
                expr = finvokevirtual_expr(invoke_target);
        else
                expr = invokevirtual_expr(invoke_target);
@@ -233,7 +233,7 @@ int convert_invokespecial(struct parse_context *ctx)
        if (!invoke_target)
                return warn("unable to resolve invocation target"), -EINVAL;
 
-       if (method_return_type(invoke_target) == J_FLOAT)
+       if (vm_type_is_float(method_return_type(invoke_target)))
                expr = finvoke_expr(invoke_target);
        else
                expr = invoke_expr(invoke_target);
@@ -267,7 +267,7 @@ int convert_invokestatic(struct parse_context *ctx)
        if (!invoke_target)
                return warn("unable to resolve invocation target"), -EINVAL;
 
-       if (method_return_type(invoke_target) == J_FLOAT)
+       if (vm_type_is_float(method_return_type(invoke_target)))
                expr = finvoke_expr(invoke_target);
        else
                expr = invoke_expr(invoke_target);
diff --git a/jit/tree-printer.c b/jit/tree-printer.c
index f88a56a..8b1b0fe 100644
--- a/jit/tree-printer.c
+++ b/jit/tree-printer.c
@@ -485,6 +485,12 @@ static const char *op_names[] = {
        [OP_FNEG] = "fneg",
        [OP_FDIV] = "fdiv",
        [OP_FREM] = "frem",
+       [OP_DADD] = "dadd",
+       [OP_DSUB] = "dsub",
+       [OP_DMUL] = "mul",
+       [OP_DNEG] = "dneg",
+       [OP_DDIV] = "ddiv",
+       [OP_DREM] = "drem",
        [OP_SHL] = "shl",
        [OP_SHL_64] = "shl64",
        [OP_SHR] = "shr",
diff --git a/jit/typeconv-bc.c b/jit/typeconv-bc.c
index 8e3dfcc..ca3300f 100644
--- a/jit/typeconv-bc.c
+++ b/jit/typeconv-bc.c
@@ -24,9 +24,9 @@ static int convert_conversion(struct parse_context *ctx, enum 
vm_type to_type)
 
        from_expression = stack_pop(ctx->bb->mimic_stack);
 
-       if (to_type == J_FLOAT)
+       if (vm_type_is_float(to_type))
                conversion_expression = conversion_to_float_expr(to_type, 
from_expression);
-       else if (from_expression->vm_type == J_FLOAT)
+       else if (vm_type_is_float(from_expression->vm_type))
                conversion_expression = conversion_from_float_expr(to_type, 
from_expression);
        else
                conversion_expression = conversion_expr(to_type, 
from_expression);
diff --git a/test/jit/arithmetic-bc-test.c b/test/jit/arithmetic-bc-test.c
index 6767056..325695f 100644
--- a/test/jit/arithmetic-bc-test.c
+++ b/test/jit/arithmetic-bc-test.c
@@ -65,7 +65,7 @@ void test_convert_add(void)
        assert_convert_binop(J_INT, OP_ADD, OPC_IADD);
        assert_convert_binop(J_LONG, OP_ADD, OPC_LADD);
        assert_convert_binop(J_FLOAT, OP_FADD, OPC_FADD);
-       assert_convert_binop(J_DOUBLE, OP_ADD, OPC_DADD);
+       assert_convert_binop(J_DOUBLE, OP_DADD, OPC_DADD);
 }
 
 void test_convert_sub(void)
@@ -73,7 +73,7 @@ void test_convert_sub(void)
        assert_convert_binop(J_INT, OP_SUB, OPC_ISUB);
        assert_convert_binop(J_LONG, OP_SUB, OPC_LSUB);
        assert_convert_binop(J_FLOAT, OP_FSUB, OPC_FSUB);
-       assert_convert_binop(J_DOUBLE, OP_SUB, OPC_DSUB);
+       assert_convert_binop(J_DOUBLE, OP_DSUB, OPC_DSUB);
 }
 
 void test_convert_mul(void)
@@ -81,7 +81,7 @@ void test_convert_mul(void)
        assert_convert_binop(J_INT, OP_MUL, OPC_IMUL);
        assert_convert_binop(J_LONG, OP_MUL_64, OPC_LMUL);
        assert_convert_binop(J_FLOAT, OP_FMUL, OPC_FMUL);
-       assert_convert_binop(J_DOUBLE, OP_MUL, OPC_DMUL);
+       assert_convert_binop(J_DOUBLE, OP_DMUL, OPC_DMUL);
 }
 
 void test_convert_div(void)
@@ -89,7 +89,7 @@ void test_convert_div(void)
        assert_convert_binop(J_INT, OP_DIV, OPC_IDIV);
        assert_convert_binop(J_LONG, OP_DIV_64, OPC_LDIV);
        assert_convert_binop(J_FLOAT, OP_FDIV, OPC_FDIV);
-       assert_convert_binop(J_DOUBLE, OP_DIV, OPC_DDIV);
+       assert_convert_binop(J_DOUBLE, OP_DDIV, OPC_DDIV);
 }
 
 void test_convert_rem(void)
@@ -97,7 +97,7 @@ void test_convert_rem(void)
        assert_convert_binop(J_INT, OP_REM, OPC_IREM);
        assert_convert_binop(J_LONG, OP_REM_64, OPC_LREM);
        assert_convert_binop(J_FLOAT, OP_FREM, OPC_FREM);
-       assert_convert_binop(J_DOUBLE, OP_REM, OPC_DREM);
+       assert_convert_binop(J_DOUBLE, OP_DREM, OPC_DREM);
 }
 
 static void assert_convert_unop(enum vm_type vm_type,
-- 
1.6.0.6


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to