/*
** jit_emit.h
**
** SPARC
**
** $Id: jit_emit.h 16313 2006-12-28 23:35:03Z particle $
**/

#if !defined(PARROT_SUN4_JIT_EMIT_H_GUARD)
#  define PARROT_SUN4_JIT_EMIT_H_GUARD

/*
 * 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 3a */
#  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_r(pc, rs, rd) emitm_or_r(pc, emitm_g(0), rs, rd)
#  define emitm_mov_i(pc, i, rd)  emitm_or_i(pc, emitm_g(0), i, 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)

#  define emitm_fsqrtd(pc, rs, rd) emitm_3c(pc, 2, rd, 064, 0, 0052, 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) emitm_3c(pc, 2, 0, 065, rs1, 0122, 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))

/* integer conditions */
#  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

/* floating-point conditions */
#  define emitm_fba   010
#  define emitm_fbn   000
#  define emitm_fbu   007
#  define emitm_fbg   006
#  define emitm_fbug  005
#  define emitm_fbl   004
#  define emitm_fbul  003
#  define emitm_fblg  002
#  define emitm_fbne  001
#  define emitm_fbe   011
#  define emitm_fbue  012
#  define emitm_fbge  013
#  define emitm_fbuge 014
#  define emitm_fble  015
#  define emitm_fbule 016
#  define emitm_fbo   017

#  define emitm_icc   02
#  define emitm_fcc   06

/* Branch on integer condition codes */
#  define emitm_bicc(pc, a, cond, disp22) emitm_2b(pc, a, cond, 02, disp22)

/* Branch on floating-point condition codes */
#  define emitm_fbfcc(pc, a, cond, disp22) emitm_2b(pc, a, cond, 06, disp22)

#  define jit_emit_mov_rr_i(pc, dst, src) emitm_mov_r(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 XSR2 emitm_g(1)

#  define Parrot_jit_regbase_ptr(interp) &REG_INT(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))

/* interp->code */
#  define jit_emit_load_coderef(pc, reg) \
    emitm_ld_i(jit_info->native_ptr, Parrot_jit_intrp, offsetof(Interp, code), reg); \

/* Load op_map address */
#  define jit_emit_load_op_map(pc, code) \
    emitm_ld_i(jit_info->native_ptr, code,                                         \
        offsetof(struct PackFile_ByteCode, jit_info), XSR1);                       \
    emitm_ld_i(jit_info->native_ptr, XSR1,                                         \
      (offsetof(Parrot_jit_arena_t, op_map) + offsetof(Parrot_jit_info_t, arena)), \
      Parrot_jit_opmap);

/* Construct the starting address of the byte code (code start) */
#  define jit_emit_load_code_start(pc, code) \
    emitm_ld_i(jit_info->native_ptr, code, offsetof(struct PackFile_Segment, data), \
               XSR1);

/* 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,
                    Interp *interp, int reg_num)
{
    jit_emit_load_coderef(jit_info->native_ptr, XSR2);

    jit_emit_load_op_map(jit_info->native_ptr, XSR2);
    jit_emit_load_code_start(jit_info->native_ptr, XSR2);

    /* 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);

    /* fixup where we have the Parrot registers - context switches */
    emitm_ld_i(jit_info->native_ptr, Parrot_jit_intrp, offsetof(Interp, ctx.bp),
        Parrot_jit_regbase);
}

/* Generate conditional branch to offset from current parrot op */
static void Parrot_jit_branch(Parrot_jit_info_t *jit_info, int branch, 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 (jit_info->optimizer->cur_section->branch_target ==
            jit_info->optimizer->cur_section)
                offset +=
                    jit_info->optimizer->cur_section->branch_target->load_size;

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

    Parrot_jit_newfixup(jit_info);
    jit_info->arena.fixups->type = JIT_BRANCH;
    jit_info->arena.fixups->param.opcode = opcode;

    /* If the branch is to the current section, skip the load instructions. */
    if (jit_info->optimizer->cur_section->branch_target ==
        jit_info->optimizer->cur_section)
            jit_info->arena.fixups->skip =
                jit_info->optimizer->cur_section->branch_target->load_size;

    emitm_2b(jit_info->native_ptr, annul, cond, branch, 0);
}

/* Generate branch on integer condition codes */
#  define Parrot_jit_bicc(jit_info, cond, annul, disp) \
        Parrot_jit_branch(jit_info, emitm_icc, cond, annul, disp)

/* Generate branch on floating-point condition codes */
#  define Parrot_jit_fbfcc(jit_info, cond, annul, disp) \
        Parrot_jit_branch(jit_info, emitm_fcc, cond, annul, disp)

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

    op_type = interp->op_info_table[*jit_info->cur_op].types[param - 1];
    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)&interp->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)&REG_INT(val);
            emitm_ld_i(jit_info->native_ptr, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interp), hwreg);
            break;

        case PARROT_ARG_P:
            val = (int)&REG_PMC(val);
            emitm_ld_i(jit_info->native_ptr, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interp), hwreg);
            break;

        case PARROT_ARG_S:
            val = (int)&REG_STR(val);
            emitm_ld_i(jit_info->native_ptr, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interp), hwreg);
            break;

        case PARROT_ARG_N:
            val = (int)&REG_NUM(val);
            emitm_ldd_i(jit_info->native_ptr, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interp), 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,
                             Interp *interp,
                             int param,
                             int hwreg)
{
    opcode_t op_type;
    int val;

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

    switch (op_type){
        case PARROT_ARG_I:
            val = (int)&REG_INT(val);
            emitm_st_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interp));
            break;

        case PARROT_ARG_P:
            val = (int)&REG_PMC(val);
            emitm_st_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interp));
            break;

        case PARROT_ARG_S:
            val = (int)&REG_STR(val);
            emitm_st_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interp));
            break;

        case PARROT_ARG_N:
            val = (int)&REG_NUM(val);
            emitm_std_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interp));
            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,
                             Interp *interp,
                             int param,
                             int hwreg)
{
    opcode_t op_type;
    long val;

    op_type = interp->op_info_table[*jit_info->cur_op].types[param - 1];
    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)&interp->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)&REG_INT(val);
            emitm_ldf_i(jit_info->native_ptr, Parrot_jit_regbase,
                        Parrot_jit_regoff(val, interp), hwreg);
            break;

        case PARROT_ARG_N:
            val = (int)&REG_NUM(val);
            emitm_lddf_i(jit_info->native_ptr, Parrot_jit_regbase,
                         Parrot_jit_regoff(val, interp), 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,
                             Interp *interp,
                             int param,
                             int hwreg)
{
    opcode_t op_type;
    int val;

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

    switch (op_type){
        case PARROT_ARG_I:
            val = (int)&REG_INT(val);
            emitm_stf_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interp));
            break;

        case PARROT_ARG_N:
            val = (int)&REG_NUM(val);
            emitm_stdf_i(jit_info->native_ptr, hwreg, Parrot_jit_regbase,
                       Parrot_jit_regoff(val, interp));
            break;

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


void Parrot_jit_dofixup(Parrot_jit_info_t *jit_info,
                        Interp *interp)
{
    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 + fixup->skip) / 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,
                      Interp *interp)
{
    /* generated code is called as jit_code(interp, 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;
    int ireg0_address;

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

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

    /* All parrot registers will be addressed relative to I0 */
    if ((ireg0_offset < emitm_simm13_min) || (ireg0_offset > emitm_simm13_max)){
        /* Store the address of I0 if its offset doesnt fit in the immediate */
        emitm_sethi(jit_info->native_ptr, emitm_hi22(ireg0_address), Parrot_jit_regbase);
        emitm_or_i(jit_info->native_ptr, Parrot_jit_regbase, emitm_lo10(ireg0_address),
                   Parrot_jit_regbase);
    }
    else {
        /* Calculate the address of I0 */
        emitm_add_i(jit_info->native_ptr, Parrot_jit_intrp, ireg0_offset,
                    Parrot_jit_regbase);
    }

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

void Parrot_jit_normal_op(Parrot_jit_info_t *jit_info,
                          Interp *interp)
{
    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))interp->op_func_table[*(jit_info->cur_op)];

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

void Parrot_jit_cpcf_op(Parrot_jit_info_t *jit_info,
                        Interp *interp)
{
    Parrot_jit_normal_op(jit_info, interp);
    Parrot_jit_bytejump(jit_info, interp, emitm_o(0));
}

#  undef Parrot_jit_restart_op
void Parrot_jit_restart_op(Parrot_jit_info_t *jit_info,
                        Interp *interp)
{
    Parrot_jit_normal_op(jit_info, interp);

    /* 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, interp, emitm_o(0));
}

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

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

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

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

/* XXX Hack to fix the following bug as of 05 Dec 2005:
    Hack [perl #37819] Sun4 builds fail linking against jit.o
    These dummy definitions blindly copied from jit/mips/jit_emit.h.
    Apparently, they need to be inside a JIT_EMIT section of this
    file.
    See also the "Hack [perl #37819]" section near the bottom of this
    file.
*/
void
Parrot_jit_emit_mov_mr_offs(Interp *interp, int base, size_t offs, int reg)
{
}

void
Parrot_jit_emit_mov_rm_offs(Interp *interp, int reg, int base, size_t offs)
{
}

void
Parrot_jit_emit_mov_mr_n_offs(Interp *interp, int base, size_t offs, int reg)
{
}

void
Parrot_jit_emit_mov_rm_n_offs(Interp *interp, int reg, int base, size_t offs)
{
}
/* XXX end blind hack for [perl #37819] --but see
   additional hack section at bottom.
*/
#  ifndef NO_JIT_VTABLE_OPS

#    undef Parrot_jit_vtable1_op
#    undef Parrot_jit_vtable1r_op

#    undef Parrot_jit_vtable_111_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

/* emit a call to a vtable func
 * $X->vtable(interp, $X [, $Y...] )
 */
static void
Parrot_jit_vtable_n_op(Parrot_jit_info_t *jit_info,
                       Interp *interp, int n, int *args)
{
    int        nvtable = op_jit[*jit_info->cur_op].extcall;
    op_info_t *op_info = &interp->op_info_table[*jit_info->cur_op];

    int    pmc = 0;  /* pmc saves the left most Pi       */
    int    rdx = 1;  /* native (outgoing) register index */

    int    idx, pi, i;
    size_t offset;

    offset  = offsetof(struct _vtable, init);
    offset += nvtable * sizeof (void *);

    for (idx = 1; idx <= n; idx++) {
        i  = args[idx - 1];
        pi = *(jit_info->cur_op + i);

        switch (op_info->types[i - 1]) {
            case PARROT_ARG_S:
                emitm_ld_i(jit_info->native_ptr, Parrot_jit_regbase,
                           REG_OFFS_STR(pi), emitm_o(rdx));
                break;
            case PARROT_ARG_K:
            case PARROT_ARG_P:
                emitm_ld_i(jit_info->native_ptr, Parrot_jit_regbase,
                           REG_OFFS_PMC(pi), emitm_o(rdx));
                if (! pmc) { pmc = rdx; }
                break;
            case PARROT_ARG_KI:
            case PARROT_ARG_I:
                emitm_ld_i(jit_info->native_ptr, Parrot_jit_regbase,
                           REG_OFFS_INT(pi), emitm_o(rdx));
                break;
            case PARROT_ARG_KIC:
            case PARROT_ARG_IC:
                if (emitm_simm13_const(pi)) {
                    emitm_mov_i(jit_info->native_ptr, pi, emitm_o(rdx));
                }
                else {
                    emitm_sethi(jit_info->native_ptr, emitm_hi22(pi), emitm_o(rdx));
                    emitm_or_i(jit_info->native_ptr, emitm_o(rdx), emitm_lo10(pi), emitm_o(rdx));
                }
                break;
            case PARROT_ARG_N:
                emitm_ld_i(jit_info->native_ptr, Parrot_jit_regbase,
                           REG_OFFS_NUM(pi), emitm_o(rdx));
                emitm_ld_i(jit_info->native_ptr, Parrot_jit_regbase,
                           REG_OFFS_NUM(pi) + 4, emitm_o(++rdx));
                break;
            case PARROT_ARG_NC:
#    define NC_addr &interp->code->const_table->constants[pi]->u.number
                emitm_sethi(jit_info->native_ptr, emitm_hi22(NC_addr), XSR1);
                emitm_or_i(jit_info->native_ptr, XSR1, emitm_lo10(NC_addr), XSR1);

                emitm_ld_i(jit_info->native_ptr, XSR1, 0, emitm_o(rdx));
                emitm_ld_i(jit_info->native_ptr, XSR1, 4, emitm_o(++rdx));
                break;
            case PARROT_ARG_SC:
#    define SC_addr &interp->code->const_table->constants[pi]->u.string
                emitm_sethi(jit_info->native_ptr, emitm_hi22(SC_addr), XSR1);
                emitm_or_i(jit_info->native_ptr, XSR1, emitm_lo10(SC_addr), XSR1);

                emitm_ld_i(jit_info->native_ptr, XSR1, 0, emitm_o(rdx));
              break;
            case PARROT_ARG_KC:
            case PARROT_ARG_PC:
#    define KC_addr &interp->code->const_table->constants[pi]->u.key
                emitm_sethi(jit_info->native_ptr, emitm_hi22(KC_addr), XSR1);
                emitm_or_i(jit_info->native_ptr, XSR1, emitm_lo10(KC_addr), XSR1);

                emitm_ld_i(jit_info->native_ptr, XSR1, 0, emitm_o(rdx));
              break;
            default:
                internal_exception(1,
                        "jit_vtable_n_op: unimp type %d, arg %d vtable %d",
                        op_info->types[i - 1], i, nvtable);
                break;
        }

        rdx++;
    }

    emitm_ld_i(jit_info->native_ptr, emitm_o(pmc), offsetof(struct PMC, vtable), XSR1);
    emitm_ld_i(jit_info->native_ptr, XSR1, offset, XSR1);

    emitm_jumpl_i(jit_info->native_ptr, XSR1, 0, emitm_o(7));
    emitm_mov_r(jit_info->native_ptr, Parrot_jit_intrp, emitm_o(0));
}

static void
Parrot_jit_store_retval(Parrot_jit_info_t *jit_info,
                        Interp *interp)
{
    opcode_t op_type = interp->op_info_table[*jit_info->cur_op].types[0];
    long     val     = jit_info->cur_op[1];

    switch (op_type){
        case PARROT_ARG_I:
            emitm_st_i(jit_info->native_ptr, emitm_o(0), Parrot_jit_regbase,
                       Parrot_jit_regoff((int)&REG_INT(val), interp));
            break;
        case PARROT_ARG_P:
            emitm_st_i(jit_info->native_ptr, emitm_o(0), Parrot_jit_regbase,
                       Parrot_jit_regoff((int)&REG_PMC(val), interp));
            break;
        case PARROT_ARG_S:
            emitm_st_i(jit_info->native_ptr, emitm_o(0), Parrot_jit_regbase,
                       Parrot_jit_regoff((int)&REG_STR(val), interp));
            break;
        case PARROT_ARG_N:
            emitm_stdf_i(jit_info->native_ptr, emitm_f(0), Parrot_jit_regbase,
                       Parrot_jit_regoff((int)&REG_NUM(val), interp));
            break;
        default:
            internal_exception(JIT_ERROR, "jit_vtable1r: ill LHS");
    }
}

/* emit a call to a vtable func
 * $1->vtable(interp, $1)
 */
static void
Parrot_jit_vtable1_op(Parrot_jit_info_t *jit_info,
                     Interp *interp)
{
    int a[] = { 1 };
    Parrot_jit_vtable_n_op(jit_info, interp, 1, a);
}

/* emit a call to a vtable func
 * $1 = $2->vtable(interp, $2)
 */
static void
Parrot_jit_vtable1r_op(Parrot_jit_info_t *jit_info,
                      Interp * interp)
{
    int a[] = { 2 };
    Parrot_jit_vtable_n_op(jit_info, interp, 1, a);
    Parrot_jit_store_retval(jit_info, interp);
}

/* emit a call to a vtable func
 * $1 = $2->vtable(interp, $2, $3)
 */
static void
Parrot_jit_vtable_1r223_op(Parrot_jit_info_t *jit_info,
                      Interp *interp)
{
    int a[] = { 2, 3 };
    Parrot_jit_vtable_n_op(jit_info, interp, 2, a);
    Parrot_jit_store_retval(jit_info, interp);
}

/* emit a call to a vtable func
 * $1 = $3->vtable(interp, $3, $2)
 */
static void
Parrot_jit_vtable_1r332_op(Parrot_jit_info_t *jit_info,
                      Interp *interp)
{
    int a[] = { 3, 2 };
    Parrot_jit_vtable_n_op(jit_info, interp, 2, a);
    Parrot_jit_store_retval(jit_info, interp);
}

/* emit a call to a vtable func
 * $1->vtable(interp, $1, $2)
 */
static void
Parrot_jit_vtable_112_op(Parrot_jit_info_t *jit_info,
                     Interp *interp)
{
    int a[] = { 1, 2 };
    Parrot_jit_vtable_n_op(jit_info, interp, 2, a);
}

/* emit a call to a vtable func
 * $1->vtable(interp, $1, $1)
 */
static void
Parrot_jit_vtable_111_op(Parrot_jit_info_t *jit_info,
                     Interp *interp)
{
    int a[] = { 1, 1 };
    Parrot_jit_vtable_n_op(jit_info, interp, 2, a);
}

/* emit a call to a vtable func
 * $2->vtable(interp, $2, $1)
 */
static void
Parrot_jit_vtable_221_op(Parrot_jit_info_t *jit_info,
                     Interp *interp)
{
    int a[] = { 2, 1 };
    Parrot_jit_vtable_n_op(jit_info, interp, 2, a);
}

/* emit a call to a vtable func
 * $2->vtable(interp, $2, $3, $1)
 */
static void
Parrot_jit_vtable_2231_op(Parrot_jit_info_t *jit_info,
                     Interp *interp)
{
    int a[] = { 2, 3, 1 };
    Parrot_jit_vtable_n_op(jit_info, interp, 3, a);
}

/* emit a call to a vtable func
 * $1->vtable(interp, $1, $2, $3)
 */
static void
Parrot_jit_vtable_1123_op(Parrot_jit_info_t *jit_info,
                     Interp *interp)
{
    int a[] = { 1, 2, 3 };
    Parrot_jit_vtable_n_op(jit_info, interp, 3, a);
}

/* emit a call to a vtable func
 * $1->vtable(interp, $1, $2, $1)
 */
static void
Parrot_jit_vtable_1121_op(Parrot_jit_info_t *jit_info,
                     Interp *interp)
{
    int a[] = { 1, 2, 1 };
    Parrot_jit_vtable_n_op(jit_info, interp, 3, a);
}

/* if_p_ic, unless_p_ic */
static void
Parrot_jit_vtable_if_unless_op(Parrot_jit_info_t *jit_info,
                     Interp *interp, int unless)
{
    int ic = *(jit_info->cur_op + 2);  /* branch offset */

    /* emit call to vtable function i.e. get_bool, result in o0 */
    Parrot_jit_vtable1_op(jit_info, interp);

    /* test the result - and branch (or not) accordingly */
    emitm_subcc_r(jit_info->native_ptr, emitm_o(0), emitm_g(0), emitm_g(0));
    Parrot_jit_bicc(jit_info, unless ? emitm_be : emitm_bne, 0, ic);

    emitm_nop(jit_info->native_ptr);
}

static void
Parrot_jit_vtable_ifp_op(Parrot_jit_info_t *jit_info,
                     Interp *interp)
{
    Parrot_jit_vtable_if_unless_op(jit_info, interp, 0);
}

static void
Parrot_jit_vtable_unlessp_op(Parrot_jit_info_t *jit_info,
                     Interp *interp)
{
    Parrot_jit_vtable_if_unless_op(jit_info, interp, 1);
}

/* new_p_ic */
static void
Parrot_jit_vtable_newp_ic_op(Parrot_jit_info_t *jit_info,
                     Interp *interp)
{
    void *igniter = (void (*)(void))pmc_new_noinit;
    size_t offset = offsetof(struct _vtable, init);

    int p1 = *(jit_info->cur_op + 1);
    int i2 = *(jit_info->cur_op + 2);

    if (i2 <= 0 || i2 >= interp->n_vtable_max)
        internal_exception(1, "Illegal PMC enum (%d) in new", i2);

    /* get "a" pmc first - calling function:  pmc_new_noinit(...) */
    /* PMC* pmc_new_noinit(Interp *interp, INTVAL base_type) */
    if (emitm_simm13_const(i2)) {
        emitm_mov_i(jit_info->native_ptr, i2, emitm_o(1));
    }
    else {
        emitm_sethi(jit_info->native_ptr, emitm_hi22(i2), emitm_o(1));
        emitm_or_i(jit_info->native_ptr, emitm_o(1), emitm_lo10(i2), emitm_o(1));
    }

    Parrot_jit_newfixup(jit_info);
    jit_info->arena.fixups->type = JIT_CALL30;
    jit_info->arena.fixups->param.fptr = D2FPTR(igniter);

    emitm_call_30(jit_info->native_ptr, 0);
    emitm_mov_r(jit_info->native_ptr, Parrot_jit_intrp, emitm_o(0));

    /* got a new pmc, sync mem and prepare vtable call (regs) */
    emitm_mov_r(jit_info->native_ptr, emitm_o(0), emitm_o(1));
    emitm_st_i(jit_info->native_ptr, emitm_o(0), Parrot_jit_regbase,
               Parrot_jit_regoff((int)&REG_PMC(p1), interp));

    emitm_ld_i(jit_info->native_ptr, emitm_o(0), offsetof(struct PMC, vtable), XSR1);
    emitm_ld_i(jit_info->native_ptr, XSR1, offset, XSR1);

    emitm_jumpl_i(jit_info->native_ptr, XSR1, 0, emitm_o(7));
    emitm_mov_r(jit_info->native_ptr, Parrot_jit_intrp, emitm_o(0));
}

#  endif /* NO_JIT_VTABLE_OPS */

#else /* JIT_EMIT */

#  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 /* JIT_EMIT */

/* XXX Hack [perl #37819]  Unlike the functions above, this one apparently
    sometimes needs to be defined both in and out of the JIT_EMIT section.
    However, at this point, the Parrot_jit_regbase symbol is not
    defined, so we replace it with the integer 26 (which is what it
    expands to anyway.
*/
#  define Parrot_jit_emit_get_base_reg_no(pc) 26 /*Parrot_jit_regbase */

#endif /* PARROT_SUN4_JIT_EMIT_H_GUARD */


/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */
