/*
** jit_emit.h
**
** SPARC
**
** $Id: jit_emit.h,v 1.24 2003/06/14 17:48:53 dan Exp $
**/

/*
 * SPARC JIT overview:
 *
 * The interpreter pointer is kept in i0.
 * The address of register I0 is stored in i1, with all parrot register access
 * performed relative to this register.
 * The address of the opcode - native code mapping array is kept in i3.
 *
 * See IMPORTANT SHORTCUTS below.
 */

/* Sparc register numbers */
#define emitm_g(n) (n)
#define emitm_o(n) ((n) + 8)
#define emitm_l(n) ((n) + 16)
#define emitm_i(n) ((n) + 24)
#define emitm_f(n) (n)

#if JIT_EMIT

#define emitm_FP emitm_i(6)
#define emitm_SP emitm_o(6)

#define emitm_mask(n, val) ((unsigned)(val) & ((1U << n) - 1))

#define emitm_hi30(val)   ((unsigned)(val) >> 2)
#define emitm_hi22(val)   ((unsigned)(val) >> 10)
#define emitm_lo10(val)   emitm_mask(10, val)
#define emitm_simm13(val) emitm_mask(13, val)

#define emitm_opval(val)  ((unsigned)(val) << 30)
#define emitm_op2val(val) ((unsigned)(val) << 22)
#define emitm_op3val(val) ((unsigned)(val) << 19)
#define emitm_rd(val)     ((unsigned)(val) << 25)
#define emitm_rs1(val)    ((unsigned)(val) << 14)

#define emitm_simm13_max 4095
#define emitm_simm13_min -4096

#define emitm_simm13_const(val) (((val) >= emitm_simm13_min) && ((val) < emitm_simm13_max))

#define emitm_branch_max 8388607
#define emitm_branch_min -8388608

/* format 1 - only instruction */
#define emitm_call_30(pc, disp30) { \
    *(unsigned *)(pc) = emitm_opval(1) | (disp30); \
    pc += 4; }

/* format 2a - sethi primarily */
#define emitm_2a(pc, op, rd, op2, imm22) { \
    *(unsigned *)(pc) = emitm_opval(op) | emitm_rd(rd) | emitm_op2val(op2) | \
        (imm22); \
    pc += 4; }

/* format 2b - branches */
#define emitm_2b(pc, a, cond, op2, disp22) { \
    *(unsigned *)(pc) = emitm_opval(0) | ((unsigned)(a) << 29) | \
                        ((unsigned)(cond) << 25) | emitm_op2val(op2) | \
                        emitm_mask(22, disp22); \
                        pc += 4; }

/* Generic fields of format 3 */
#define emitm_fmt3(pc, op, rd, op3, rs1, low14) { \
    *(unsigned *)pc = emitm_opval(op) |emitm_rd(rd) | emitm_op3val(op3) | \
        emitm_rs1(rs1) | (low14); \
    pc +=4 ; }

/* format 3b */
#define emitm_3a(pc, op, rd, op3, rs1, asi, rs2) \
    emitm_fmt3(pc, op, rd, op3, rs1, ((asi) << 5) | (rs2))

/* format 3b */
#define emitm_3b(pc, op, rd, op3, rs1, simm13) \
    emitm_fmt3(pc, op, rd, op3, rs1, (1L << 13) | emitm_mask(13, (simm13)))

/* format 3c */
#define emitm_3c(pc, op, rd, op3, rs1, opf, rs2) \
    emitm_fmt3(pc, op, rd, op3, rs1, (opf << 5) | (rs2))

/* Miscellaneous instructions */

/* sethi imm22, r[rd] */
#define emitm_sethi(pc, imm22, rd) emitm_2a(pc, 0, rd, 04, imm22)

/* NOP */
#define emitm_nop(pc) emitm_sethi(pc, 0, 0)

/* SAVE */

#define emitm_save_r(pc, rs1, rs2, rd) emitm_3a(pc, 2, rd, 074, rs1, 0, rs2)
#define emitm_save_i(pc, rs1, i, rd)   emitm_3b(pc, 2, rd, 074, rs1, i)

/* RESTORE */
#define emitm_restore_r(pc, rs1, rs2, rd) emitm_3a(pc, 2, rd, 075, rs1, 0, rd)
#define emitm_restore_i(pc, rs1, i, rd)   emitm_3b(pc, 2, rd, 075, rs1, i)

/* MOV */
#define emitm_mov(pc, rs, rd) emitm_or_r(pc, emitm_g(0), rs, rd)

/* Integer Register Loads */

/* ldX[rs1 + simm13], rd */
#define emitm_ldsb_i(pc, rs1, i, rd) emitm_3b(pc, 3, rd, 011, rs1, i)
#define emitm_ldub_i(pc, rs1, i, rd) emitm_3b(pc, 3, rd, 001, rs1, i)
#define emitm_ldsh_i(pc, rs1, i, rd) emitm_3b(pc, 3, rd, 012, rs1, i)
#define emitm_lduh_i(pc, rs1, i, rd) emitm_3b(pc, 3, rd, 002, rs1, i)
#define emitm_ld_i(pc, rs1, i, rd)   emitm_3b(pc, 3, rd, 000, rs1, i)
#define emitm_ldd_i(pc, rs1, i, rd)  emitm_3b(pc, 3, rd, 003, rs1, i)

/* ldX[rs1 + rs2], rd */
#define emitm_ldsb_r(pc, rs1, rs2, rd) emitm_3a(pc, 3, rd, 011, rs1, 0, rs2)
#define emitm_ldub_r(pc, rs1, rs2, rd) emitm_3a(pc, 3, rd, 001, rs1, 0, rs2)
#define emitm_ldsh_r(pc, rs1, rs2, rd) emitm_3a(pc, 3, rd, 012, rs1, 0, rs2)
#define emitm_lduh_r(pc, rs1, rs2, rd) emitm_3a(pc, 3, rd, 002, rs1, 0, rs2)
#define emitm_ld_r(pc, rs1, rs2, rd)   emitm_3a(pc, 3, rd, 000, rs1, 0, rs2)
#define emitm_ldd_r(pc, rs1, rs2, rd)  emitm_3a(pc, 3, rd, 003, rs1, 0, rs2)

/* Integer Register Stores */

/* stX rd, [rs1 + simm13] */
#define emitm_stb_i(pc, rd, rs1, i) emitm_3b(pc, 3, rd, 005, rs1, i)
#define emitm_sth_i(pc, rd, rs1, i) emitm_3b(pc, 3, rd, 006, rs1, i)
#define emitm_st_i(pc, rd, rs1, i)  emitm_3b(pc, 3, rd, 004, rs1, i)
#define emitm_std_i(pc, rd, rs1, i) emitm_3b(pc, 3, rd, 007, rs1, i)

/* stX rd, [rs1 + rs2] */
#define emitm_stb_r(pc, rd, rs1, rs2) emitm_3a(pc, 3, rd, 005, rs1, 0, rs2)
#define emitm_sth_r(pc, rd, rs1, rs2) emitm_3a(pc, 3, rd, 006, rs1, 0, rs2)
#define emitm_st_r(pc, rd, rs1, rs2)  emitm_3a(pc, 3, rd, 004, rs1, 0, rs2)
#define emitm_std_r(pc, rd, rs1, rs2) emitm_3a(pc, 3, rd, 007, rs1, 0, rs2)

/* Floating Point Register Loads */

/* ldX[rs1 + simm13], freg[rd] */
#define emitm_ldf_i(pc, rs1, i, rd)   emitm_3b(pc, 3, rd, 040, rs1, i)
#define emitm_lddf_i(pc, rs1, i, rd)  emitm_3b(pc, 3, rd, 043, rs1, i)

#define emitm_ldfsr_i(pc, rs1, i, rd) emitm_3b(pc, 3, rd, 041, rs1, i)

/* ldX[rs1 + rs2], freg[rd] */
#define emitm_ldf_r(pc, rs1, rs2, rd)   emitm_3a(pc, 3, rd, 040, rs1, 0, rs2)
#define emitm_lddf_r(pc, rs1, rs2, rd)  emitm_3a(pc, 3, rd, 043, rs1, 0, rs2)

#define emitm_ldfsr_r(pc, rs1, rs2, rd) emitm_3a(pc, 3, rd, 041, rs1, 0, rs2)

/* Floating Point Register Stores */

/* stX freg[rd], [rs1 + simm13] */
#define emitm_stf_i(pc, rd, rs1, i)   emitm_3b(pc, 3, rd, 044, rs1, i)
#define emitm_stdf_i(pc, rd, rs1, i)  emitm_3b(pc, 3, rd, 047, rs1, i)

#define emitm_stfsr_i(pc, rd, rs1, i) emitm_3b(pc, 3, rd, 045, rs1, i)

/* stX freg[rd], [rs1 + rs2] */
#define emitm_stf_r_r(pc, rd, rs1, rs2)   emitm_3a(pc, 3, rd, 044, rs1, 0, rs2)
#define emitm_stdf_r_r(pc, rd, rs1, rs2)  emitm_3a(pc, 3, rd, 047, rs1, 0, rs2)
#define emitm_stfsr_r_r(pc, rd, rs1, rs2) emitm_3a(pc, 3, rd, 045, rs1, 0, rs2)

/* Logical instructions */

/* op r[rs1], r[rs2], r[rd] */
#define emitm_logic_r(pc, op3, rs1, rs2, rd) \
    emitm_3a(pc, 2, rd, op3, rs1, 0, rs2)

/* op r[rs1], simm13, r[rd] */
#define emitm_logic_i(pc, op3, rs1, simm13, rd) \
    emitm_3b(pc, 2, rd, op3, rs1, simm13)

#define emitm_and_r(pc, rs1, rs2, rd)    emitm_logic_r(pc, 001, rs1, rs2, rd)
#define emitm_andcc_r(pc, rs1, rs2, rd)  emitm_logic_r(pc, 021, rs1, rs2, rd)
#define emitm_andn_r(pc, rs1, rs2, rd)   emitm_logic_r(pc, 005, rs1, rs2, rd)
#define emitm_andncc_r(pc, rs1, rs2, rd) emitm_logic_r(pc, 025, rs1, rs2, rd)
#define emitm_and_i(pc, rs1, i, rd)      emitm_logic_i(pc, 001, rs1, i, rd)
#define emitm_andcc_i(pc, rs1, i, rd)    emitm_logic_i(pc, 021, rs1, i, rd)
#define emitm_andn_i(pc, rs1, i, rd)     emitm_logic_i(pc, 005, rs1, i, rd)
#define emitm_andncc_i(pc, rs1, i, rd)   emitm_logic_i(pc, 025, rs1, i, rd)
#define emitm_or_r(pc, rs1, rs2, rd)     emitm_logic_r(pc, 002, rs1, rs2, rd)
#define emitm_orcc_r(pc, rs1, rs2, rd)   emitm_logic_r(pc, 022, rs1, rs2, rd)
#define emitm_orn_r(pc, rs1, rs2, rd)    emitm_logic_r(pc, 006, rs1, rs2, rd)
#define emitm_orncc_r(pc, rs1, rs2, rd)  emitm_logic_r(pc, 026, rs1, rs2, rd)
#define emitm_or_i(pc, rs1, i, rd)       emitm_logic_i(pc, 002, rs1, i, rd)
#define emitm_orcc_i(pc, rs1, i, rd)     emitm_logic_i(pc, 022, rs1, i, rd)
#define emitm_orn_i(pc, rs1, i, rd)      emitm_logic_i(pc, 006, rs1, i, rd)
#define emitm_orncc_i(pc, rs1, i, rd)    emitm_logic_i(pc, 026, rs1, i, rd)
#define emitm_xor_r(pc, rs1, rs2, rd)    emitm_logic_r(pc, 003, rs1, rs2, rd)
#define emitm_xorcc_r(pc, rs1, rs2, rd)  emitm_logic_r(pc, 023, rs1, rs2, rd)
#define emitm_xorn_r(pc, rs1, rs2, rd)   emitm_logic_r(pc, 007, rs1, rs2, rd)
#define emitm_xorncc_r(pc, rs1, rs2, rd) emitm_logic_r(pc, 027, rs1, rs2, rd)
#define emitm_xor_i(pc, rs1, i, rd)      emitm_logic_i(pc, 003, rs1, i, rd)
#define emitm_xorcc_i(pc, rs1, i, rd)    emitm_logic_i(pc, 023, rs1, i, rd)
#define emitm_xorn_i(pc, rs1, i, rd)     emitm_logic_i(pc, 007, rs1, i, rd)
#define emitm_xorncc_i(pc, rs1, i, rd)   emitm_logic_i(pc, 027, rs1, i, rd)

/* Shift Left Logical */
#define emitm_sll_r(pc, rs1, rs2, rd) emitm_3a(pc, 2, rd, 045, rs1, 0, rs2)
#define emitm_sll_i(pc, rs1, i, rd)   emitm_3b(pc, 2, rd, 045, rs1, i)

/* Shift Right Logical */
#define emitm_srl_r(pc, rs1, rs2, rd) emitm_3a(pc, 2, rd, 046, rs1, 0, rs2)
#define emitm_srl_i(pc, rs1, i, rd)   emitm_3b(pc, 2, rd, 046, rs1, i)

/* Shift Right Arithmetic */
#define emitm_sra_r(pc, rs1, rs2, rd) emitm_3a(pc, 2, rd, 047, rs1, 0, rs2)
#define emitm_sra_i(pc, rs1, i, rd)   emitm_3a(pc, 2, rd, 047, rs1, i)

/* Arithmetic ops */
#define emitm_add_r(pc, rs1, rs2, rd)    emitm_3a(pc, 2, rd, 0, rs1, 0, rs2)
#define emitm_addcc_r(pc, rs1, rs2, rd)  emitm_3a(pc, 2, rd, 020, rs1, 0, rs2)
#define emitm_addX_r(pc, rs1, rs2, rd)   emitm_3a(pc, 2, rd, 010, rs1, 0, rs2)
#define emitm_addXcc_r(pc, rs1, rs2, rd) emitm_3a(pc, 2, rd, 030, rs1, 0, rs2)
#define emitm_add_i(pc, rs1, i, rd)      emitm_3b(pc, 2, rd, 0, rs1, i)
#define emitm_addcc_i(pc, rs1, i, rd)    emitm_3b(pc, 2, rd, 020, rs1, i)
#define emitm_addX_i(pc, rs1, i, rd)     emitm_3b(pc, 2, rd, 010, rs1, i)
#define emitm_addXcc_i(pc, rs1, i, rd)   emitm_3b(pc, 2, rd, 030, rs1, i)

/* Arithmetic ops */
#define emitm_sub_r(pc, rs1, rs2, rd)    emitm_3a(pc, 2, rd, 004, rs1, 0, rs2)
#define emitm_subcc_r(pc, rs1, rs2, rd)  emitm_3a(pc, 2, rd, 024, rs1, 0, rs2)
#define emitm_subX_r(pc, rs1, rs2, rd)   emitm_3a(pc, 2, rd, 014, rs1, 0, rs2)
#define emitm_subXcc_r(pc, rs1, rs2, rd) emitm_3a(pc, 2, rd, 034, rs1, 0, rs2)
#define emitm_sub_i(pc, rs1, i, rd)      emitm_3b(pc, 2, rd, 004, rs1, i)
#define emitm_subcc_i(pc, rs1, i, rd)    emitm_3b(pc, 2, rd, 024, rs1, i)
#define emitm_subX_i(pc, rs1, i, rd)     emitm_3b(pc, 2, rd, 014, rs1, i)
#define emitm_subXcc_i(pc, rs1, i, rd)   emitm_3b(pc, 2, rd, 034, rs1, i)

/* Floating point operations */

/* MOV */
#define emitm_fmovs(pc, rs, rd) emitm_3c(pc, 2, rd, 064, 0, 0001, rs)

/* Arithmetic operations */
#define emitm_faddd(pc, rs1, rs2, rd) emitm_3c(pc, 2, rd, 064, rs1, 0102, rs2)
#define emitm_fsubd(pc, rs1, rs2, rd) emitm_3c(pc, 2, rd, 064, rs1, 0106, rs2)
#define emitm_fmuld(pc, rs1, rs2, rd) emitm_3c(pc, 2, rd, 064, rs1, 0112, rs2)
#define emitm_fdivd(pc, rs1, rs2, rd) emitm_3c(pc, 2, rd, 064, rs1, 0116, rs2)
#define emitm_fabss(pc, rs, rd) emitm_3c(pc, 2, rd, 064, 0, 0011, rs)
#define emitm_fnegs(pc, rs, rd) emitm_3c(pc, 2, rd, 064, 0, 0005, rs)

/* Floating <-> Integer Conversion */
#define emitm_fitod(pc, rs, rd) emitm_3c(pc, 2, rd, 064, 0, 0310, rs)
#define emitm_fdtoi(pc, rs, rd) emitm_3c(pc, 2, rd, 064, 0, 0322, rs)

/* Floating point tests */
#define emitm_fcmpd(pc, rs1, rs2, rd) emitm_3c(pc, 2, rd, 064, rs1, 0112, rs2)

/* Jump and Link */

#define emitm_jumpl_r(pc, rs1, rs2, rd) emitm_3a(pc, 2, rd, 070, rs1, 0, rs2)
#define emitm_jumpl_i(pc, rs1, i, rd)   emitm_3b(pc, 2, rd, 070, rs1, i)

/* RET */
#define emitm_ret(pc) emitm_jumpl_i(pc, emitm_i(7), 8, emitm_g(0))

#define emitm_ba   010
#define emitm_bn   000
#define emitm_bne  011
#define emitm_be   001
#define emitm_bg   012
#define emitm_ble  002
#define emitm_bge  013
#define emitm_bl   003
#define emitm_bgu  014
#define emitm_bleu 004
#define emitm_bcc  015
#define emitm_bcs  005
#define emitm_bpos 016
#define emitm_bneg 006
#define emitm_bvc  017
#define emitm_bvs  007

/* Branch */
#define emitm_bicc(pc, a, cond, disp22) emitm_2b(pc, a, cond, 02, disp22)

#define jit_emit_mov_rr_i(pc, dst, src) emitm_mov(pc, src, dst)
#define jit_emit_mov_rr_n(pc, dst, src) { \
    emitm_fmovs(pc, src, dst); \
    emitm_fmovs(pc, (src)+1, (dst)+1); }

/*
void main(){
    char ar[1024];
    char *ar2;

    ar2 = &ar[0];
    emitm_ld_r(ar2, emitm_g(0), emitm_i(1), emitm_o(7));
    emitm_ldub_r(ar2, emitm_g(0), emitm_i(1), emitm_o(7));
    emitm_ldsh_r(ar2, emitm_g(0), emitm_i(1), emitm_o(7));
}
*/

/* Fixup types */
enum  {JIT_BRANCH, JIT_CALL30 };

/*
 *
 * IMPORTANT SHORTCUTS
 *
 * */

/* The register holding the interpreter pointer */
#define Parrot_jit_intrp emitm_i(0)

/* The register holding the address of I0 */
#define Parrot_jit_regbase emitm_i(2)

/* The register containing the address of the opmap */
#define Parrot_jit_opmap emitm_i(3)

/* These registers should be used only in .jit ops and not helper routines
 *   in jit_emit.h
 */
#define ISR1 emitm_i(4)
#define ISR2 emitm_i(5)
#define FSR1 emitm_f(0)
#define FSR2 emitm_f(2)

/* This register can be used only in jit_emit.h calculations */
#define XSR1 emitm_l(0)

#define Parrot_jit_regbase_ptr(i) &((i)->int_reg.registers[0])

/* The offset of a Parrot register from the base register */
#define Parrot_jit_regoff(a, i) (unsigned)(a) - (unsigned)(Parrot_jit_regbase_ptr(i))

/* Generate a jump to a bytecode address in reg_num
 *  - uses the temporary register
 */
static void
Parrot_jit_bytejump(Parrot_jit_info_t *jit_info,
                    struct Parrot_Interp *interpreter, int reg_num)
{

    /* Construct the starting address of the byte code */
    emitm_sethi(jit_info->native_ptr, emitm_hi22(interpreter->code->byte_code),
        XSR1);
    emitm_or_i(jit_info->native_ptr, XSR1,
        emitm_lo10(interpreter->code->byte_code), XSR1);

    /* Calculates the offset into op_map shadow array
     * assuming sizeof(opcode_t) == sizeof(opmap array entry) */
    emitm_sub_r(jit_info->native_ptr, reg_num, XSR1,
                XSR1);

    /* Load the address of the native code from op_map */
    emitm_ld_r(jit_info->native_ptr, Parrot_jit_opmap, XSR1,
               XSR1);

    /* This jumps to the address from op_map */
    emitm_jumpl_i(jit_info->native_ptr, XSR1, 0, XSR1);
    emitm_nop(jit_info->native_ptr);
}

/* Generate conditional branch to offset from current parrot op */
static void Parrot_jit_bicc(Parrot_jit_info_t *jit_info, int cond, int annul,
                            opcode_t disp)
{
    int offset;
    opcode_t opcode;

    opcode = jit_info->op_i + disp;
    if(opcode <= jit_info->op_i){
        offset = jit_info->arena.op_map[opcode].offset -
                    (jit_info->native_ptr - jit_info->arena.start);

        if((offset > emitm_branch_max) || (offset < emitm_branch_min))
            internal_exception(JIT_ERROR,
                           "Branches beyond 8 Megabytes not yet supported\n");
        offset /= 4;
        emitm_bicc(jit_info->native_ptr, annul, cond, offset);
        return;
    }

    Parrot_jit_newfixup(jit_info);
    jit_info->arena.fixups->type = JIT_BRANCH;
    jit_info->arena.fixups->param.opcode = opcode;
    emitm_bicc(jit_info->native_ptr, annul, cond, 0);
}

/* This function loads a value */
static void jit_emit_load_i(Parrot_jit_info_t *jit_info,
                             struct Parrot_Interp *interpreter,
                             int param,
                             int hwreg)
{
    opcode_t op_type;
    int val;

    op_type = interpreter->op_info_table[*jit_info->cur_op].types[param];
    val = jit_info->cur_op[param];

    switch(op_type){
        case PARROT_ARG_IC:
            if((val < emitm_simm13_min) || (val > emitm_simm13_max)){
                emitm_sethi(jit_info->native_ptr, emitm_hi22(val), hwreg);
                emitm_or_i(jit_info->native_ptr, hwreg, emitm_lo10(val),
                           hwreg);
            }
            else {
                emitm_or_i(jit_info->native_ptr, emitm_g(0), val, hwreg);
            }

            break;
        case PARROT_ARG_NC:
            val = (int)&interpreter->code->const_table->
                    constants[val]->u.number;

            /* Load double into integer registers */
            emitm_sethi(jit_info->native_ptr, emitm_hi22(val), XSR1);
            emitm_ldd_i(jit_info->native_ptr, XSR1, emitm_lo10(val),
                        hwreg);
            break;

        case PARROT_ARG_I:
            val = (int)&interpreter->int_reg.registers[val];
            emitm_ld_i(jit_info->native_ptr, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interpreter), hwreg);
            break;

        case PARROT_ARG_P:
            val = (int)&interpreter->pmc_reg.registers[val];
            emitm_ld_i(jit_info->native_ptr, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interpreter), hwreg);
            break;

        case PARROT_ARG_S:
            val = (int)&interpreter->string_reg.registers[val];
            emitm_ld_i(jit_info->native_ptr, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interpreter), hwreg);
            break;

        case PARROT_ARG_N:
            val = (int)&interpreter->num_reg.registers[val];
            emitm_ldd_i(jit_info->native_ptr, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interpreter), hwreg);
            break;

        default:
            internal_exception(JIT_ERROR,
                               "Unsupported op parameter type %d\n",
                               op_type);
    }
}

static void jit_emit_store_i(Parrot_jit_info_t *jit_info,
                             struct Parrot_Interp *interpreter,
                             int param,
                             int hwreg)
{
    opcode_t op_type;
    int val;

    op_type = interpreter->op_info_table[*jit_info->cur_op].types[param];
    val = jit_info->cur_op[param];

    switch(op_type){
        case PARROT_ARG_I:
            val = (int)&interpreter->int_reg.registers[val];
            emitm_st_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interpreter));
            break;

        case PARROT_ARG_P:
            val = (int)&interpreter->pmc_reg.registers[val];
            emitm_st_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interpreter));
            break;

        case PARROT_ARG_S:
            val = (int)&interpreter->string_reg.registers[val];
            emitm_st_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interpreter));
            break;

        case PARROT_ARG_N:
            val = (int)&interpreter->num_reg.registers[val];
            emitm_std_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interpreter));
            break;

        default:
            internal_exception(JIT_ERROR,
                            "Unsupported op parameter type %d\n", op_type);
    }
}

static void jit_emit_load_n(Parrot_jit_info_t *jit_info,
                             struct Parrot_Interp *interpreter,
                             int param,
                             int hwreg)
{
    opcode_t op_type;
    long val;

    op_type = interpreter->op_info_table[*jit_info->cur_op].types[param];
    val = jit_info->cur_op[param];

    switch(op_type){
        case PARROT_ARG_IC:
            /* Load integer into floating point registers - should use 
               constant pool */
            val = &jit_info->cur_op[param];
            emitm_sethi(jit_info->native_ptr, emitm_hi22(val), XSR1);
            emitm_ldf_i(jit_info->native_ptr, XSR1, emitm_lo10(val), hwreg);
            break;

        case PARROT_ARG_NC:
            val = (int)&interpreter->code->const_table->
                    constants[val]->u.number;

            /* Load double into floating point registers */
            emitm_sethi(jit_info->native_ptr, emitm_hi22(val), XSR1);
            emitm_lddf_i(jit_info->native_ptr, XSR1, emitm_lo10(val),
                        hwreg);
            break;

        case PARROT_ARG_I:
            val = (int)&interpreter->int_reg.registers[val];
            emitm_ldf_i(jit_info->native_ptr, Parrot_jit_regbase,
                        Parrot_jit_regoff(val, interpreter), hwreg);
            break;

        case PARROT_ARG_N:
            val = (int)&interpreter->num_reg.registers[val];
            emitm_lddf_i(jit_info->native_ptr, Parrot_jit_regbase,
                         Parrot_jit_regoff(val, interpreter), hwreg);
            break;

        default:
            internal_exception(JIT_ERROR,
                            "Unsupported op parameter type %d\n", op_type);
    }
}

static void jit_emit_store_n(Parrot_jit_info_t *jit_info,
                             struct Parrot_Interp *interpreter,
                             int param,
                             int hwreg)
{
    opcode_t op_type;
    int val;

    op_type = interpreter->op_info_table[*jit_info->cur_op].types[param];
    val = jit_info->cur_op[param];

    switch(op_type){
        case PARROT_ARG_I:
            val = (int)&interpreter->int_reg.registers[val];
            emitm_stf_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interpreter));
            break;

        case PARROT_ARG_N:
            val = (int)&interpreter->num_reg.registers[val];
            emitm_stdf_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interpreter));
            break;

        default:
            internal_exception(JIT_ERROR,
                            "Unsupported op parameter type %d\n", op_type);
    }
}


void Parrot_jit_dofixup(Parrot_jit_info_t *jit_info,
                        struct Parrot_Interp * interpreter)
{
    Parrot_jit_fixup_t *fixup;
    Parrot_jit_fixup_t *last_fixup;
    char *fixup_ptr;
    int fixup_val;

    fixup = jit_info->arena.fixups;

    while(fixup){
        switch(fixup->type){
        /* This fixes-up a branch to a known opcode offset */
            case JIT_BRANCH:
                fixup_ptr = Parrot_jit_fixup_target(jit_info, fixup);
                fixup_val = (jit_info->arena.op_map[fixup->param.opcode].offset
                                - fixup->native_offset) / 4;
                *(int *)(fixup_ptr) |= emitm_mask(22, fixup_val);
                break;

            case JIT_CALL30:
                fixup_ptr = jit_info->arena.start + fixup->native_offset;
                fixup_val = (int)fixup->param.fptr - (int)fixup_ptr;
                emitm_call_30(fixup_ptr, emitm_hi30(fixup_val));
                break;

            default:
                internal_exception(JIT_ERROR, "Unknown fixup type:%d\n",
                    fixup->type);
            break;
        }
        fixup = fixup->next;
    }
}

void
Parrot_jit_begin(Parrot_jit_info_t *jit_info,
                      struct Parrot_Interp * interpreter)
{
    /* generated code is called as jit_code(interpreter, pc)
     * so interpreter is in i0 and pc in i1.
     * i1 is reusable once past the jump. interpreter is preserved in i0
     */
    int ireg0_offset;

    /* Standard Prolog */
    emitm_save_i(jit_info->native_ptr, emitm_SP, -104, emitm_SP);

    /* Calculate the offset of I0 in the interpreter struct */
    ireg0_offset = (int)Parrot_jit_regbase_ptr(interpreter) -
        (int)interpreter;

    if(ireg0_offset > 4095){
        internal_exception(JIT_ERROR,
                           "Unable to support interpreter structure\n" );
    }

    /* Calculate the address of I0 */
    /* All parrot registers will be addressed relative to I0 */
    emitm_add_i(jit_info->native_ptr, Parrot_jit_intrp, ireg0_offset,
                Parrot_jit_regbase);

    /* Setup the pointer to the opcode map */
    emitm_sethi(jit_info->native_ptr,
        emitm_hi22(jit_info->arena.op_map), Parrot_jit_opmap);
    emitm_or_i(jit_info->native_ptr,
        Parrot_jit_opmap, emitm_lo10(jit_info->arena.op_map), Parrot_jit_opmap);

    /* Jump to the current pc */
    Parrot_jit_bytejump(jit_info, interpreter, emitm_i(1));
}

void Parrot_jit_normal_op(Parrot_jit_info_t *jit_info,
                          struct Parrot_Interp * interpreter)
{
    emitm_sethi(jit_info->native_ptr, emitm_hi22(jit_info->cur_op), emitm_o(0));
    emitm_or_i(jit_info->native_ptr,
        emitm_o(0), emitm_lo10(jit_info->cur_op), emitm_o(0));

    Parrot_jit_newfixup(jit_info);
    jit_info->arena.fixups->type = JIT_CALL30;
    jit_info->arena.fixups->param.fptr =
        (void (*)(void))interpreter->op_func_table[*(jit_info->cur_op)];

    emitm_call_30(jit_info->native_ptr, 0);
    emitm_mov(jit_info->native_ptr, Parrot_jit_intrp, emitm_o(1));
}

void Parrot_jit_cpcf_op(Parrot_jit_info_t *jit_info,
                        struct Parrot_Interp * interpreter)
{
    Parrot_jit_normal_op(jit_info, interpreter);
    Parrot_jit_bytejump(jit_info, interpreter, emitm_o(0));
}

#undef Parrot_jit_restart_op
void Parrot_jit_restart_op(Parrot_jit_info_t *jit_info,
                        struct Parrot_Interp * interpreter)
{
    Parrot_jit_normal_op(jit_info, interpreter);

    /* Test whether the return value is 0 */
    emitm_subcc_r(jit_info->native_ptr, emitm_o(0), emitm_g(0), emitm_g(0));

    /* If the return pc is not zero skip the next 3 instructions */
    emitm_bicc(jit_info->native_ptr, 0, emitm_bne, 4);
    emitm_nop(jit_info->native_ptr);

    /* Return if the return pc is 0 */
    emitm_ret(jit_info->native_ptr);
    emitm_restore_i(jit_info->native_ptr, emitm_g(0), emitm_g(0), emitm_g(0));

    Parrot_jit_bytejump(jit_info, interpreter, emitm_o(0));
}

/* move reg to mem (i.e. intreg) */
void
Parrot_jit_emit_mov_mr(struct Parrot_Interp * interpreter, char *mem, int reg)
{
    emitm_st_i(((Parrot_jit_info_t *)(interpreter->jit_info))->native_ptr,
               reg, Parrot_jit_regbase, Parrot_jit_regoff(mem, interpreter));
}

/* move mem (i.e. intreg) to reg */
void
Parrot_jit_emit_mov_rm(struct Parrot_Interp * interpreter, int reg, char *mem)
{
    emitm_ld_i(((Parrot_jit_info_t *)(interpreter->jit_info))->native_ptr,
               Parrot_jit_regbase, Parrot_jit_regoff(mem, interpreter), reg);
}

/* move reg to mem (i.e. numreg) */
void
Parrot_jit_emit_mov_mr_n(struct Parrot_Interp * interpreter, char *mem, int reg)
{
    emitm_stdf_i(((Parrot_jit_info_t *)(interpreter->jit_info))->native_ptr,
                 reg, Parrot_jit_regbase, Parrot_jit_regoff(mem, interpreter));
}

/* move mem (i.e. numreg) to reg */
void
Parrot_jit_emit_mov_rm_n(struct Parrot_Interp * interpreter, int reg, char *mem)
{
    emitm_lddf_i(((Parrot_jit_info_t *)(interpreter->jit_info))->native_ptr,
                 Parrot_jit_regbase, Parrot_jit_regoff(mem, interpreter), reg);
}

#  ifndef NO_JIT_VTABLE_OPS

#    undef Parrot_jit_vtable1_op
/*#    undef Parrot_jit_vtable1r_op
#    undef Parrot_jit_vtable2rk_op
#    undef Parrot_jit_vtable3k_op

#    undef Parrot_jit_vtable_112_op
#    undef Parrot_jit_vtable_221_op
#    undef Parrot_jit_vtable_1121_op
#    undef Parrot_jit_vtable_1123_op
#    undef Parrot_jit_vtable_2231_op

#    undef Parrot_jit_vtable_1r223_op
#    undef Parrot_jit_vtable_1r332_op

#    undef Parrot_jit_vtable_ifp_op
#    undef Parrot_jit_vtable_unlessp_op
#    undef Parrot_jit_vtable_newp_ic_op
*/

static void
Parrot_jit_vtable1_op(Parrot_jit_info_t *jit_info,
                      struct Parrot_Interp *interpreter)
{
}

#endif /* NO_JIT_VTABLE_OPS */

#else

#  define REQUIRES_CONSTANT_POOL 0
#  define INT_REGISTERS_TO_MAP 6
#  define FLOAT_REGISTERS_TO_MAP 6

#ifndef JIT_IMCC
char intval_map[INT_REGISTERS_TO_MAP] =
    { emitm_l(1), emitm_l(2), emitm_l(3), emitm_l(4), emitm_l(5), emitm_l(6)
    };

char floatval_map[] = 
    { emitm_f(4), emitm_f(6), emitm_f(8), emitm_f(10), emitm_f(12), emitm_f(14)
    };
#endif

#define PRESERVED_INT_REGS 6
#define PRESERVED_FLOAT_REGS 0

#endif

/*
 * Local variables:
 * c-indentation-style: bsd
 * c-basic-offset: 4
 * indent-tabs-mode: nil
 * End:
 *
 * vim: expandtab shiftwidth=4:
 */
