;
; ppc/core.jit
;
;
; $Id: /mirror/trunk/src/jit/ppc/core.jit 32110 2008-10-21T20:35:06.288924Z julianalbo  $
;

# TODO complete this
#define P_ARITH ((PREV_OP == dec_i) || (PREV_OP == inc_i) || (PREV_OP == sub_i_i_i))
Parrot_end {
    jit_emit_lwz(NATIVECODE, r1, 0, r1);
    jit_emit_lwz(NATIVECODE, r0, 8, r1);

    jit_emit_call_func(NATIVECODE, (void *)Parrot_ppc_jit_restore_nonvolatile_registers);

    jit_emit_mtlr(NATIVECODE, r0);
    jit_emit_lmw(NATIVECODE, r13, -PPC_JIT_GP_REGISTER_SAVE_SPACE, r1);

    jit_emit_blr(NATIVECODE);
}

Parrot_noop {
; preferred no-op on ppc
    jit_emit_ori(NATIVECODE, r0, r0, 0);
}

Parrot_set_i_ic {
    if (MAP[1]) {
        jit_emit_mov_ri_i(NATIVECODE, MAP[1], *INT_CONST[2]);
    }
    else {
        jit_emit_mov_ri_i(NATIVECODE, ISR1, *INT_CONST[2]);
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), ISR1);
    }
}

Parrot_set_i_n {
    if (MAP[2]) {
    jit_emit_fctiwz  (NATIVECODE, FSR2, MAP[2]);
    }
    else {
        jit_emit_mov_rm_n(NATIVECODE, FSR1, ROFFS_NUM(2));
    jit_emit_fctiwz  (NATIVECODE, FSR2, FSR1);
    }
    if (MAP[1]) {
    jit_emit_add_rri_i(NATIVECODE, ISR1, 0, -4);
    jit_emit_stfiwx   (NATIVECODE, FSR2, ISR1, r1);   /* -> -4(sp) */
    jit_emit_lwz      (NATIVECODE, MAP[1], -4, r1);
    }
    else {
    jit_emit_add_rri_i(NATIVECODE, ISR1, 0, ROFFS_INT(1));
    jit_emit_stfiwx   (NATIVECODE, FSR2, ISR1, r13);   /* -> offs(base) */
    }
}

Parrot_set_n_ic {
    static double xx = 4503601774854144.0; /* 0x4330000080000000L; */
    jit_emit_mov_ri_i(NATIVECODE, ISR1, *INT_CONST[2]);
    jit_emit_xoris(   NATIVECODE, ISR1, ISR1, 0x8000);
    /* use redzone for intermediate */
    jit_emit_stw(     NATIVECODE, ISR1, -4, r1);
    jit_emit_addis(   NATIVECODE, ISR1, r31, 0x4330);
    jit_emit_stw(     NATIVECODE, ISR1, -8, r1);
    jit_emit_lfd(     NATIVECODE, FSR1, -8, r1);
    /* we should keep this magic const in a preserved eg eg. f31 */
    jit_emit_mov_ri_i(NATIVECODE, ISR2, &xx);
    jit_emit_lfd(     NATIVECODE, FSR2, 0, ISR2);
    if (MAP[1]) {
    jit_emit_fsub_rrr(NATIVECODE, MAP[1], FSR1, FSR2);
    }
    else {
    jit_emit_fsub_rrr(NATIVECODE, FSR1, FSR1, FSR2);
        jit_emit_mov_mr_n(NATIVECODE, ROFFS_NUM(1), FSR1);
    }
}

Parrot_set_n_i {
    static double xx = 4503601774854144.0; /* 0x4330000080000000L; */
    if (MAP[2]) {
    jit_emit_xoris(   NATIVECODE, ISR1, MAP[2], 0x8000);
    }
    else {
        jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(2));
    jit_emit_xoris(   NATIVECODE, ISR1, ISR1, 0x8000);
    }
    /* use redzone for intermediate */
    jit_emit_stw(     NATIVECODE, ISR1, -4, r1);
    jit_emit_addis(   NATIVECODE, ISR1, r31, 0x4330);
    jit_emit_stw(     NATIVECODE, ISR1, -8, r1);
    jit_emit_lfd(     NATIVECODE, FSR1, -8, r1);
    /* we should keep this magic const in a preserved eg  f31 */
    jit_emit_mov_ri_i(NATIVECODE, ISR2, &xx);
    jit_emit_lfd(     NATIVECODE, FSR2, 0, ISR2);
    if (MAP[1]) {
    jit_emit_fsub_rrr(NATIVECODE, MAP[1], FSR1, FSR2);
    }
    else {
    jit_emit_fsub_rrr(NATIVECODE, FSR1, FSR1, FSR2);
        jit_emit_mov_mr_n(NATIVECODE, ROFFS_NUM(1), FSR1);
    }
}

Parrot_null_i {
    if (MAP[1]) {
        jit_emit_mov_rr(NATIVECODE, MAP[1], r31);
    }
    else {
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), r31);
    }
}

TEMPLATE Parrot_set_x_x {
    if (MAP[1] && MAP[2]) {
        jit_emit_mov_rr(NATIVECODE, MAP[1], MAP[2]);
    }
    else if (MAP[1]) {
        jit_emit_mov_rm_i(NATIVECODE, MAP[1], ROFFS_INT(2));
    }
    else if (MAP[2]) {
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), MAP[2]);
    }
    else {
        jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(2));
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), ISR1);
    }
}

Parrot_set_i_i {
    Parrot_set_x_x
}

Parrot_set_s_s {
    Parrot_set_x_x s/INT/STR/`
}

Parrot_set_p_p {
    Parrot_set_x_x s/INT/PMC/
}

Parrot_set_n_n {
    if (MAP[1] && MAP[2]) {
        jit_emit_mov_rr_n(NATIVECODE, MAP[1], MAP[2]);
    }
    else if (MAP[1]) {
    jit_emit_mov_rm_n(NATIVECODE, MAP[1], ROFFS_NUM(2));
    }
    else if (MAP[2]) {
        jit_emit_mov_mr_n(NATIVECODE, ROFFS_NUM(1), MAP[2]);
    }
    else {
    jit_emit_mov_rm_n(NATIVECODE, FSR1, ROFFS_NUM(2));
        jit_emit_mov_mr_n(NATIVECODE, ROFFS_NUM(1), FSR1);
    }
}

Parrot_set_n_nc {
    if (MAP[1]) {
        jit_emit_mov_ri_i(NATIVECODE, ISR1, &NUM_CONST[2]);
        jit_emit_lfd(NATIVECODE, MAP[1], 0, ISR1);
    }
    else {
        jit_emit_mov_ri_i(NATIVECODE, ISR1, &NUM_CONST[2]);
        jit_emit_lfd(NATIVECODE, FSR1, 0, ISR1);
        jit_emit_mov_mr_n(NATIVECODE, ROFFS_NUM(1), FSR1);
    }
}

TEMPLATE unary_x_x {
    if (MAP[1] && MAP[2]) {
        jit_emit_<op>_rr<_N>(NATIVECODE, MAP[1], MAP[2]);
    }
    else if (MAP[1]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(2));
        jit_emit_<op>_rr<_N>(NATIVECODE, MAP[1], <s1>);
    }
    else if (MAP[2]) {
        jit_emit_<op>_rr<_N>(NATIVECODE, <s1>, MAP[1]);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<t>(1), <s1>);
    }
    else {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(2));
        jit_emit_<op>_rr<_N>(NATIVECODE, <s1>, <s1>);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<t>(1), <s1>);
    }
}

TEMPLATE unary_i_i {
    unary_x_x s/<_N>/_i/ s/<t>/INT/ s/<s1>/ISR1/
}

TEMPLATE unary_n_n {
    unary_x_x s/<_N>/_n/ s/<t>/NUM/ s/<s1>/FSR1/
}

Parrot_neg_i_i {
    unary_i_i s/<op>/neg/
}

Parrot_neg_n_n {
    unary_n_n s/<op>/neg/
}

Parrot_abs_n_n {
    unary_n_n s/<op>/abs/
}

TEMPLATE binop_x_xc {
    int im;
    if (MAP[1]) {
#ifdef jit_emit_<op>_rri<_N>
    im = *INT_CONST[2];
    /* *if* immediate constant is small and there is a dedicated
     * opcode, just use it
     * _n variants don't have immediates, only _i
     *
     * This could be further improved, if there exists also
     * a shifted opcode variant like 'oris'. But then this code
     * should be factored out into jit_emit.h. This OTOH needs some
     * convention about scratch register usage.
     */
    if (!(im >> 16)) {
        jit_emit_<op>_rri_i(NATIVECODE, MAP[1], MAP[1], im);
    }
    else
#endif
    {
        jit_emit_mov_ri<_N>(NATIVECODE, <s1>, <c>_CONST[2]);
        jit_emit_<op>_rrr<_N>(NATIVECODE, MAP[1], MAP[1], <s1>);
    }
    }
    else {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(1));
#ifdef jit_emit_<op>_rri<_N>
    im = *INT_CONST[2];
    if (!(im >> 16)) {
        jit_emit_<op>_rri_i(NATIVECODE, <s1>, <s1>, im);
    }
    else
#endif
    {
        jit_emit_mov_ri<_N>(NATIVECODE, <s2>, <c>_CONST[2]);
        jit_emit_<op>_rrr<_N>(NATIVECODE, <s1>, <s1>, <s2>);
    }
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<t>(1), <s1>);
    }
}

TEMPLATE binop_n_nc {
    binop_x_xc s/<_N>/_n/ s/<t>/NUM/ s/<s1>/FSR1/ s/<s2>/FSR2/ s/<c>/&NUM/
}

TEMPLATE binop_i_ic {
    binop_x_xc s/<_N>/_i/ s/<t>/INT/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<c>/*INT/
}

TEMPLATE binop_x_x {
    if (MAP[1] && MAP[2]) {
        jit_emit_<op>_rrr<_N>(NATIVECODE, MAP[1], MAP[1], MAP[2]);
    }
    else if (MAP[1]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<T>(2));
        jit_emit_<op>_rrr<_N>(NATIVECODE, MAP[1], MAP[1], <s1>);
    }
    else if (MAP[2]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<T>(1));
        jit_emit_<op>_rrr<_N>(NATIVECODE, <s1>, <s1>, MAP[2]);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<T>(1), <s1>);
    }
    else {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<T>(1));
        jit_emit_mov_rm<_N>(NATIVECODE, <s2>, ROFFS_<T>(2));
        jit_emit_<op>_rrr<_N>(NATIVECODE, <s1>, <s1>, <s2>);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<T>(1), <s1>);
    }
}

TEMPLATE binop_x_x_x {
    if (MAP[1] && MAP[2] && MAP[3]) {
        jit_emit_<op>_rrr<_N>(NATIVECODE, MAP[1], MAP[2], MAP[3]);
    }
    else if (MAP[1] && MAP[2]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<T>(3));
        jit_emit_<op>_rrr<_N>(NATIVECODE, MAP[1], MAP[2], <s1>);
    }
    else if (MAP[1] && MAP[3]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<T>(2));
        jit_emit_<op>_rrr<_N>(NATIVECODE, MAP[1], <s1>, MAP[3]);
    }
    else if (MAP[2] && MAP[3]) {
        jit_emit_<op>_rrr<_N>(NATIVECODE, <s1>, MAP[2], MAP[3]);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<T>(1), <s1>);
    }
    else if (MAP[1]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<T>(3));
        jit_emit_mov_rm<_N>(NATIVECODE, <s2>, ROFFS_<T>(2));
        jit_emit_<op>_rrr<_N>(NATIVECODE, MAP[1], <s2>, <s1>);
    }
    else if (MAP[2]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<T>(3));
        jit_emit_<op>_rrr<_N>(NATIVECODE, <s1>, MAP[2], <s1>);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<T>(1), <s1>);
    }
    else if (MAP[3]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<T>(2));
        jit_emit_<op>_rrr<_N>(NATIVECODE, <s1>, <s1>, MAP[3]);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<T>(1), <s1>);
    }
    else {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<T>(3));
        jit_emit_mov_rm<_N>(NATIVECODE, <s2>, ROFFS_<T>(2));
        jit_emit_<op>_rrr<_N>(NATIVECODE, <s1>, <s2>, <s1>);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<T>(1), <s1>);
    }
}

TEMPLATE binop_x_xc_x {
    if (MAP[1] && MAP[3]) {
        jit_emit_mov_ri<_N>(NATIVECODE, <s1>, <c>_CONST[2]);
        jit_emit_<op>_rrr<_N>(NATIVECODE, MAP[1], <s1>, MAP[3]);
    }
    else if (MAP[1]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(3));
        jit_emit_mov_ri<_N>(NATIVECODE, <s2>, <c>_CONST[2]);
        jit_emit_<op>_rrr<_N>(NATIVECODE, MAP[1], <s2>, <s1>);
    }
    else if (MAP[3]) {
        jit_emit_mov_ri<_N>(NATIVECODE, <s1>, <c>_CONST[2]);
        jit_emit_<op>_rrr<_N>(NATIVECODE, <s1>, <s1>, MAP[3]);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<t>(1), <s1>);
    }
    else {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(3));
        jit_emit_mov_ri<_N>(NATIVECODE, <s2>, <c>_CONST[2]);
        jit_emit_<op>_rrr<_N>(NATIVECODE, <s1>, <s2>, <s1>);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<t>(1), <s1>);
    }
}

TEMPLATE binop_i_ic_i {
    binop_x_xc_x  s/<_N>/_i/ s/<t>/INT/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<c>/*INT/
}
TEMPLATE binop_n_nc_n {
    binop_x_xc_x  s/<_N>/_n/ s/<t>/NUM/ s/<s1>/FSR1/ s/<s2>/FSR2/ s/<c>/&NUM/
}

TEMPLATE binop_x_x_xc {
    if (MAP[1] && MAP[2]) {
#ifdef jit_emit_<op>_rri<_N>
        /* common case - operands are MAPped */
    int im = *INT_CONST[3];
    if (!(im >> 16)) {
        jit_emit_<op>_rri_i(NATIVECODE, MAP[1], MAP[2], im);
    }
    else
#endif
    {
        jit_emit_mov_ri<_N>(NATIVECODE, <s1>, <c>_CONST[3]);
        jit_emit_<op>_rrr<_N>(NATIVECODE, MAP[1], MAP[2], <s1>);
    }
    }
    else if (MAP[1]) {
        jit_emit_mov_ri<_N>(NATIVECODE, <s1>, <c>_CONST[3]);
        jit_emit_mov_rm<_N>(NATIVECODE, <s2>, ROFFS_<t>(2));
        jit_emit_<op>_rrr<_N>(NATIVECODE, MAP[1], <s2>, <s1>);
    }
    else if (MAP[2]) {
        jit_emit_mov_ri<_N>(NATIVECODE, <s1>, <c>_CONST[3]);
        jit_emit_<op>_rrr<_N>(NATIVECODE, <s1>, MAP[2], <s1>);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<t>(1), <s1>);
    }
    else {
        jit_emit_mov_ri<_N>(NATIVECODE, <s1>, <c>_CONST[3]);
        jit_emit_mov_rm<_N>(NATIVECODE, <s2>, ROFFS_<t>(2));
        jit_emit_<op>_rrr<_N>(NATIVECODE, <s1>, <s2>, <s1>);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_<t>(1), <s1>);
    }
}

TEMPLATE binop_i_i_ic {
    binop_x_x_xc  s/<_N>/_i/ s/<t>/INT/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<c>/*INT/
}

TEMPLATE binop_n_n_nc {
    binop_x_x_xc  s/<_N>/_n/ s/<t>/NUM/ s/<s1>/FSR1/ s/<s2>/FSR2/ s/<c>/&NUM/
}

Parrot_band_i_i {
    binop_x_x s/<_N>/_i/ s/<op>/and/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_bor_i_i {
    binop_x_x s/<_N>/_i/ s/<op>/or/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_bxor_i_i {
    binop_x_x s/<_N>/_i/ s/<op>/xor/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_shr_i_i {
    binop_x_x s/<_N>/_i/ s/<op>/shr/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_shl_i_i {
    binop_x_x s/<_N>/_i/ s/<op>/shl/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_lsr_i_i {
    binop_x_x s/<_N>/_i/ s/<op>/lsr/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_add_i_i {
    binop_x_x s/<_N>/_i/ s/<op>/add/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_sub_i_i {
    binop_x_x s/<_N>/_i/ s/<op>/sub/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_mul_i_i {
    binop_x_x s/<_N>/_i/ s/<op>/mul/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_div_i_i {
    binop_x_x s/<_N>/_i/ s/<op>/div/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_cmod_i_i {
    binop_x_x s/<_N>/_i/ s/<op>/cmod/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_band_i_ic {
    binop_i_ic s/<op>/and/
}

Parrot_bor_i_ic {
    binop_i_ic s/<op>/or/
}

Parrot_bxor_i_ic {
    binop_i_ic s/<op>/xor/
}

Parrot_shr_i_ic {
    binop_i_ic s/<op>/shr/
}

Parrot_shl_i_ic {
    binop_i_ic s/<op>/shl/
}

Parrot_lsr_i_ic {
    binop_i_ic s/<op>/lsr/
}

Parrot_add_i_ic {
    binop_i_ic s/<op>/add/
}

Parrot_sub_i_ic {
    binop_i_ic s/<op>/sub/
}

Parrot_mul_i_ic {
    binop_i_ic s/<op>/mul/
}

Parrot_div_i_ic {
    binop_i_ic s/<op>/div/
}

Parrot_cmod_i_ic {
    binop_i_ic s/<op>/cmod/
}

Parrot_add_n_nc {
    binop_n_nc s/<op>/add/
}

Parrot_sub_n_nc {
    binop_n_nc s/<op>/sub/
}

Parrot_mul_n_nc {
    binop_n_nc s/<op>/mul/
}

Parrot_div_n_nc {
    binop_n_nc s/<op>/div/
}

Parrot_add_n_n {
    binop_x_x s/<_N>/_n/ s/<op>/add/ s/<s1>/FSR1/ s/<s2>/FSR2/ s/<T>/NUM/
}

Parrot_div_n_n {
    binop_x_x s/<_N>/_n/ s/<op>/div/ s/<s1>/FSR1/ s/<s2>/FSR2/ s/<T>/NUM/
}

Parrot_mul_n_n {
    binop_x_x s/<_N>/_n/ s/<op>/mul/ s/<s1>/FSR1/ s/<s2>/FSR2/ s/<T>/NUM/
}

Parrot_sub_n_n {
    binop_x_x s/<_N>/_n/ s/<op>/sub/ s/<s1>/FSR1/ s/<s2>/FSR2/ s/<T>/NUM/
}

Parrot_band_i_i_i {
    binop_x_x_x s/<_N>/_i/ s/<op>/and/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_bor_i_i_i {
    binop_x_x_x s/<_N>/_i/ s/<op>/or/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_bxor_i_i_i {
    binop_x_x_x s/<_N>/_i/ s/<op>/xor/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_add_i_i_i {
    binop_x_x_x s/<_N>/_i/ s/<op>/add/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_sub_i_i_i {
    binop_x_x_x s/<_N>/_i/ s/<op>/sub/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_mul_i_i_i {
    binop_x_x_x s/<_N>/_i/ s/<op>/mul/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_div_i_i_i {
    binop_x_x_x s/<_N>/_i/ s/<op>/div/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_cmod_i_i_i {
    binop_x_x_x s/<_N>/_i/ s/<op>/cmod/ s/<s1>/ISR1/ s/<s2>/ISR2/ s/<T>/INT/
}

Parrot_band_i_i_ic {
    binop_i_i_ic s/<op>/and/
}

Parrot_bor_i_i_ic {
    binop_i_i_ic s/<op>/or/
}

Parrot_bxor_i_i_ic {
    binop_i_i_ic s/<op>/xor/
}

Parrot_shr_i_i_ic {
    binop_i_i_ic s/<op>/shr/
}

Parrot_shl_i_i_ic {
    binop_i_i_ic s/<op>/shl/
}

Parrot_lsr_i_i_ic {
    binop_i_i_ic s/<op>/lsr/
}

Parrot_add_i_i_ic {
    binop_i_i_ic s/<op>/add/
}

Parrot_sub_i_i_ic {
    binop_i_i_ic s/<op>/sub/
}

Parrot_mul_i_i_ic {
    binop_i_i_ic s/<op>/mul/
}

Parrot_div_i_i_ic {
    binop_i_i_ic s/<op>/div/
}

Parrot_cmod_i_i_ic {
    binop_i_i_ic s/<op>/cmod/
}

Parrot_add_n_n_nc {
    binop_n_n_nc s/<op>/add/
}

Parrot_sub_n_n_nc {
    binop_n_n_nc s/<op>/sub/
}

Parrot_mul_n_n_ic {
    binop_n_n_nc s/<op>/mul/
}

Parrot_div_n_n_nc {
    binop_n_n_nc s/<op>/div/
}

Parrot_band_i_ic_i {
    binop_i_ic_i s/<op>/and/
}

Parrot_bor_i_ic_i {
    binop_i_ic_i s/<op>/or/
}

Parrot_bxor_i_ic_i {
    binop_i_ic_i s/<op>/xor/
}

Parrot_shr_i_ic_i {
    binop_i_ic_i s/<op>/shr/
}

Parrot_lsr_i_ic_i {
    binop_i_ic_i s/<op>/lsr/
}

Parrot_shl_i_ic_i {
    binop_i_ic_i s/<op>/shl/
}

Parrot_add_i_ic_i {
    binop_i_ic_i s/<op>/add/
}

Parrot_sub_i_ic_i {
    binop_i_ic_i s/<op>/sub/
}

Parrot_mul_i_ic_i {
    binop_i_ic_i s/<op>/mul/
}

Parrot_div_i_ic_i {
    binop_i_ic_i s/<op>/div/
}

Parrot_cmod_i_ic_i {
    binop_i_ic_i s/<op>/cmod/
}

Parrot_add_n_nc_n {
    binop_n_nc_n s/<op>/add/
}

Parrot_sub_n_nc_n {
    binop_n_nc_n s/<op>/sub/
}

Parrot_mul_n_nc_n {
    binop_n_nc_n s/<op>/mul/
}

Parrot_div_n_nc_n {
    binop_n_nc_n s/<op>/div/
}

Parrot_add_n_n_n {
    binop_x_x_x s/<_N>/_n/ s/<op>/add/ s/<s1>/FSR1/ s/<s2>/FSR2/ s/<T>/NUM/
}

Parrot_sub_n_n_n {
    binop_x_x_x s/<_N>/_n/ s/<op>/sub/ s/<s1>/FSR1/ s/<s2>/FSR2/ s/<T>/NUM/
}

Parrot_mul_n_n_n {
    binop_x_x_x s/<_N>/_n/ s/<op>/mul/ s/<s1>/FSR1/ s/<s2>/FSR2/ s/<T>/NUM/
}

Parrot_div_n_n_n {
    binop_x_x_x s/<_N>/_n/ s/<op>/div/ s/<s1>/FSR1/ s/<s2>/FSR2/ s/<T>/NUM/
}

Parrot_rot_i_i_ic_ic {
    int rc = *INT_CONST[3];
    int bw = *INT_CONST[4];
    if (rc < 0)
    rc = bw + rc;
    if (MAP[1] && MAP[2]) {
    jit_emit_rot_rri(NATIVECODE, MAP[1], MAP[2], rc);
    }
    else if (MAP[1]) {
        jit_emit_mov_rm_i(NATIVECODE, ISR2, ROFFS_INT(2));
    jit_emit_rot_rri(NATIVECODE, MAP[1], ISR2, rc);
    }
    else if (MAP[2]) {
        jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(1));
    jit_emit_rot_rri(NATIVECODE, ISR1, MAP[2], rc);
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), ISR1);
    }
    else {
        jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(1));
        jit_emit_mov_rm_i(NATIVECODE, ISR2, ROFFS_INT(2));
    jit_emit_rot_rri(NATIVECODE, ISR1, ISR2, rc);
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), ISR1);
    }

}

; actually this covers islt too, by passing the bit
TEMPLATE iseq_i_x_x {
    if (MAP[2] && MAP[3]) {
        jit_emit_cmp_rr<_N>(NATIVECODE, MAP[2], MAP[3]);
    }
    else if (MAP[2]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(3));
        jit_emit_cmp_rr<_N>(NATIVECODE, MAP[2], <s1>);
    }
    else if (MAP[3]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(2));
        jit_emit_cmp_rr<_N>(NATIVECODE, <s1>, MAP[3]);
    }
    else {
        jit_emit_mov_rm<_N>(NATIVECODE, <s2>, ROFFS_<t>(2));
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(3));
        jit_emit_cmp_rr<_N>(NATIVECODE, <s2>, <s1>);
    }
    jit_emit_mfcr(NATIVECODE, ISR1);
    /* bits 0 LT, 1 GT, 2 EQ */
    /* see also extrwi */
    if (MAP[1]) {
    jit_emit_rlwinm(NATIVECODE, MAP[1], ISR1, <b>, 31, 31);
    }
    else {
    jit_emit_rlwinm(NATIVECODE, ISR1, ISR1, <b>, 31, 31);
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), ISR1);
    }
}

TEMPLATE isle_i_x_x {
    if (MAP[2] && MAP[3]) {
        jit_emit_cmp_rr<_N>(NATIVECODE, MAP[2], MAP[3]);
    }
    else if (MAP[2]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(3));
        jit_emit_cmp_rr<_N>(NATIVECODE, MAP[2], <s1>);
    }
    else if (MAP[3]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(2));
        jit_emit_cmp_rr<_N>(NATIVECODE, <s1>, MAP[3]);
    }
    else {
        jit_emit_mov_rm<_N>(NATIVECODE, <s2>, ROFFS_<t>(2));
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(3));
        jit_emit_cmp_rr<_N>(NATIVECODE, <s2>, <s1>);
    }
    jit_emit_mfcr(NATIVECODE, ISR1);
    /* bits 0 LT, 1 GT, 2 EQ */
    /* this is LT or LE - get LT */
    jit_emit_rlwinm(NATIVECODE, ISR2, ISR1, 1, 31, 31);
    /* get EQ and or the bits into destination */
    jit_emit_rlwinm(NATIVECODE, ISR1, ISR1, 3, 31, 31);
    if (MAP[1]) {
    jit_emit_or_rrr(NATIVECODE, MAP[1], ISR1, ISR2);
    }
    else {
    jit_emit_or_rrr(NATIVECODE, ISR1, ISR1, ISR2);
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), ISR1);
    }
}

TEMPLATE cmp_i_x_x {
    if (MAP[2] && MAP[3]) {
        jit_emit_cmp_rr<_N>(NATIVECODE, MAP[2], MAP[3]);
    }
    else if (MAP[2]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(3));
        jit_emit_cmp_rr<_N>(NATIVECODE, MAP[2], <s1>);
    }
    else if (MAP[3]) {
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(2));
        jit_emit_cmp_rr<_N>(NATIVECODE, <s1>, MAP[3]);
    }
    else {
        jit_emit_mov_rm<_N>(NATIVECODE, <s2>, ROFFS_<t>(2));
        jit_emit_mov_rm<_N>(NATIVECODE, <s1>, ROFFS_<t>(3));
        jit_emit_cmp_rr<_N>(NATIVECODE, <s2>, <s1>);
    }
    jit_emit_mfcr(NATIVECODE, ISR1);
    /* bits 0 LT, 1 GT, 2 EQ */
    /* get LT -> 0/1 */
    jit_emit_rlwinm(NATIVECODE, ISR2, ISR1, 1, 31, 31);
    /* reverse bit */
    jit_emit_xori  (NATIVECODE, ISR2, ISR2, 1);
    /* sub 1 -> -1 / 0 */
    jit_emit_subi  (NATIVECODE, ISR2, ISR2, 1);
    /* get GT  or the bits into destination */
    jit_emit_rlwinm(NATIVECODE, ISR1, ISR1, 2, 31, 31);
    if (MAP[1]) {
    jit_emit_or_rrr(NATIVECODE, MAP[1], ISR1, ISR2);
    }
    else {
    jit_emit_or_rrr(NATIVECODE, ISR1, ISR1, ISR2);
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), ISR1);
    }
}
Parrot_iseq_i_i_i {
    iseq_i_x_x  s/<s1>/ISR1/ s/<s2>/ISR2/ s/<t>/INT/ s/<_N>/_i/ s/<b>/3/
}

Parrot_iseq_i_n_n {
    iseq_i_x_x  s/<s1>/FSR1/ s/<s2>/FSR2/ s/<t>/NUM/ s/<_N>/_n/ s/<b>/3/
}

Parrot_islt_i_i_i {
    iseq_i_x_x  s/<s1>/ISR1/ s/<s2>/ISR2/ s/<t>/INT/ s/<_N>/_i/ s/<b>/1/
}

Parrot_islt_i_n_n {
    iseq_i_x_x  s/<s1>/FSR1/ s/<s2>/FSR2/ s/<t>/NUM/ s/<_N>/_n/ s/<b>/1/
}

Parrot_isle_i_i_i {
    isle_i_x_x  s/<s1>/ISR1/ s/<s2>/ISR2/ s/<t>/INT/ s/<_N>/_i/
}

Parrot_isle_i_n_n {
    isle_i_x_x  s/<s1>/FSR1/ s/<s2>/FSR2/ s/<t>/NUM/ s/<_N>/_n/
}

Parrot_cmp_i_i_i {
    cmp_i_x_x  s/<s1>/ISR1/ s/<s2>/ISR2/ s/<t>/INT/ s/<_N>/_i/
}

Parrot_cmp_i_n_n {
    cmp_i_x_x  s/<s1>/FSR1/ s/<s2>/FSR2/ s/<t>/NUM/ s/<_N>/_n/
}

Parrot_inc_i {
    if (MAP[1]) {
        jit_emit_add_rri_i (NATIVECODE, MAP[1], MAP[1], 1);
    }
    else {
        jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(1));
        jit_emit_add_rri_i (NATIVECODE, ISR1, ISR1, 1);
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), ISR1);
    }
}

Parrot_dec_i {
    if (MAP[1]) {
        jit_emit_add_rri_i (NATIVECODE, MAP[1], MAP[1], -1);
    }
    else {
        jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(1));
        jit_emit_add_rri_i (NATIVECODE, ISR1, ISR1, -1);
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), ISR1);
    }
}

Parrot_inc_n {
    static const double one = 1.0;
    jit_emit_mov_ri_i(NATIVECODE, ISR1, &one);
    jit_emit_lfd(NATIVECODE, FSR1, 0, ISR1);
    if (MAP[1]) {
        jit_emit_fadd_rrr(NATIVECODE, MAP[1], MAP[1], FSR1);
    }
    else {
    jit_emit_mov_rm_n(NATIVECODE, FSR2, ROFFS_NUM(1));
        jit_emit_fadd_rrr(NATIVECODE, FSR2, FSR2, FSR1);
        jit_emit_mov_mr_n(NATIVECODE, ROFFS_NUM(1), FSR2);
    }
}

Parrot_dec_n {
    static const double one = 1.0;
    jit_emit_mov_ri_i(NATIVECODE, ISR1, &one);
    jit_emit_lfd(NATIVECODE, FSR1, 0, ISR1);
    if (MAP[1]) {
        jit_emit_fsub_rrr(NATIVECODE, MAP[1], MAP[1], FSR1);
    }
    else {
    jit_emit_mov_rm_n(NATIVECODE, FSR2, ROFFS_NUM(1));
        jit_emit_fsub_rrr(NATIVECODE, FSR2, FSR2, FSR1);
        jit_emit_mov_mr_n(NATIVECODE, ROFFS_NUM(1), FSR2);
    }
}


TEMPLATE Parrot_unaryop_x {
    if (MAP[1]) {
        jit_emit_<op>_rr<_N>(NATIVECODE, MAP[1], MAP[1]);
    }
    else {
        jit_emit_mov_rm<_N>(NATIVECODE, SCRATCH1, ROFFS_INT(1));
        jit_emit_<op>_rr<_N>(NATIVECODE, SCRATCH1, SCRATCH1);
        jit_emit_mov_mr<_N>(NATIVECODE, ROFFS_INT(1), SCRATCH1);
    }
}

; a recursive template
TEMPLATE Parrot_unaryop_i {
    Parrot_unaryop_x s/<_N>/_i/  s/SCRATCH1/ISR1/
}

TEMPLATE Parrot_unaryop_n {
    Parrot_unaryop_x s/<_N>/_n/ s/INT/NUM/ s/SCRATCH1/FSR1/
}

Parrot_neg_i {
    Parrot_unaryop_i s/<op>/neg/
}

Parrot_neg_n {
    Parrot_unaryop_n s/<op>/neg/
}

Parrot_abs_n {
    Parrot_unaryop_n s/<op>/abs/
}

Parrot_abs_i {
    if (MAP[1]) {
        jit_emit_srawi(NATIVECODE, ISR1, MAP[1], 31);
        jit_emit_add_rrr(NATIVECODE, ISR2, ISR1, MAP[1]);
        jit_emit_xor_rrr(NATIVECODE, MAP[1], ISR2, ISR1);
    }
    else {
        jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(1));
        jit_emit_srawi(NATIVECODE, ISR2, ISR1, 31);
        jit_emit_add_rrr(NATIVECODE, ISR1, ISR2, ISR1);
        jit_emit_xor_rrr(NATIVECODE, ISR1, ISR1, ISR2);
        jit_emit_mov_mr_i(NATIVECODE, ROFFS_INT(1), ISR1);
    }
}


TEMPLATE Parrot_ifunless_i_ic {
    if (P_ARITH && MAP[1]) {
        /* set the Rc bit of prev for the sake of +50% more MOPS  */
        NATIVECODE[-1] |= 1;
    }
    else if (MAP[1]) {
        jit_emit_cmp_ri(NATIVECODE, MAP[1], 0);
    }
    else {
        jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(1));
        jit_emit_cmp_ri(NATIVECODE, ISR1, 0);
    }
    jit_emit_bc(jit_info, <COND>, *INT_CONST[2]);
}

Parrot_if_i_ic {
    Parrot_ifunless_i_ic s/<COND>/BNE/
}

Parrot_unless_i_ic {
    Parrot_ifunless_i_ic s/<COND>/BEQ/
}

TEMPLATE Parrot_ifunless_n_ic {
    static const double zero = 0.0;
    jit_emit_mov_ri_i(NATIVECODE, ISR1, &zero);
    jit_emit_lfd(NATIVECODE, FSR1, 0, ISR1);
    if (MAP[1]) {
        jit_emit_cmp_rr_n(NATIVECODE, MAP[1], FSR1);
    }
    else {
    jit_emit_mov_rm_n(NATIVECODE, FSR2, ROFFS_NUM(1));
        jit_emit_cmp_rr_n(NATIVECODE, FSR2, FSR1);
    }
    jit_emit_bc(jit_info, <COND>, *INT_CONST[2]);
}

Parrot_if_n_ic {
    Parrot_ifunless_n_ic s/<COND>/BNE/
}

Parrot_unless_n_ic {
    Parrot_ifunless_n_ic s/<COND>/BEQ/
}

TEMPLATE Parrot_branch_i_i_ic {
; First, emit the compare op:
    if (MAP[1] && MAP[2]) {
        jit_emit_cmp_rr_i(NATIVECODE, MAP[1], MAP[2]);
    }
    else if (MAP[1]) {
        jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(2));
        jit_emit_cmp_rr_i(NATIVECODE, MAP[1], ISR1);
    }
    else if (MAP[2]) {
        jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(1));
        jit_emit_cmp_rr_i(NATIVECODE, ISR1, MAP[2]);
    }
    else {
        jit_emit_mov_rm_i(NATIVECODE, ISR2, ROFFS_INT(1));
        jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(2));
        jit_emit_cmp_rr_i(NATIVECODE, ISR2, ISR1);
    }
; Now the branch. XXX: need to handle large displacements.
    jit_emit_bc(jit_info, <CON>, *INT_CONST[3]);
}

TEMPLATE Parrot_branch_i_ic_ic {
    jit_emit_mov_ri_i(NATIVECODE, ISR1, *INT_CONST[2]);

    if (MAP[1]) {
        jit_emit_cmp_rr_i(NATIVECODE, MAP[1], ISR1);
    }
    else {
        jit_emit_mov_rm_i(NATIVECODE, ISR2, ROFFS_INT(1));
        jit_emit_cmp_rr_i(NATIVECODE, ISR2, ISR1);
    }
; Now the branch. XXX: need to handle large displacements.
    jit_emit_bc(jit_info, <CON>, *INT_CONST[3]);

}

TEMPLATE Parrot_branch_ic_i_ic {
    jit_emit_mov_ri_i(NATIVECODE, ISR1, *INT_CONST[1]);

    if (MAP[2]) {
        jit_emit_cmp_rr_i(NATIVECODE, ISR1, MAP[2]);
    }
    else {
        jit_emit_mov_rm_i(NATIVECODE, ISR2, ROFFS_INT(2));
        jit_emit_cmp_rr_i(NATIVECODE, ISR1, ISR2);
    }
; Now the branch. XXX: need to handle large displacements.
    jit_emit_bc(jit_info, <CON>, *INT_CONST[3]);
}

Parrot_eq_i_i_ic {
    Parrot_branch_i_i_ic s/<CON>/BEQ/
}

Parrot_eq_i_ic_ic {
    Parrot_branch_i_ic_ic s/<CON>/BEQ/
}

Parrot_eq_ic_i_ic {
    Parrot_branch_ic_i_ic s/<CON>/BEQ/
}


Parrot_lt_i_i_ic {
    Parrot_branch_i_i_ic s/<CON>/BLT/
}

Parrot_lt_i_ic_ic {
    Parrot_branch_i_ic_ic s/<CON>/BLT/
}

Parrot_lt_ic_i_ic {
    Parrot_branch_ic_i_ic s/<CON>/BLT/
}

Parrot_le_i_i_ic {
    Parrot_branch_i_i_ic s/<CON>/BLE/
}

Parrot_le_i_ic_ic {
    Parrot_branch_i_ic_ic s/<CON>/BLE/
}

Parrot_le_ic_i_ic {
    Parrot_branch_ic_i_ic s/<CON>/BLE/
}


Parrot_ne_i_i_ic {
    Parrot_branch_i_i_ic s/<CON>/BNE/
}

Parrot_ne_i_ic_ic {
    Parrot_branch_i_ic_ic s/<CON>/BNE/
}

Parrot_ne_ic_i_ic {
    Parrot_branch_ic_i_ic s/<CON>/BNE/
}


TEMPLATE Parrot_branch_n_n_ic {
    if (MAP[1] && MAP[2]) {
        jit_emit_cmp_rr_n(NATIVECODE, MAP[1], MAP[2]);
    }
    else if (MAP[1]) {
        jit_emit_mov_rm_n(NATIVECODE, FSR1, ROFFS_NUM(2));
        jit_emit_cmp_rr_n(NATIVECODE, MAP[1], FSR1);
    }
    else if (MAP[2]) {
        jit_emit_mov_rm_n(NATIVECODE, FSR1, ROFFS_NUM(1));
        jit_emit_cmp_rr_n(NATIVECODE, FSR1, MAP[2]);
    }
    else {
        jit_emit_mov_rm_n(NATIVECODE, FSR2, ROFFS_NUM(1));
        jit_emit_mov_rm_n(NATIVECODE, FSR1, ROFFS_NUM(2));
        jit_emit_cmp_rr_n(NATIVECODE, FSR2, FSR1);
    }
    jit_emit_bc(jit_info, <CON>, *INT_CONST[3]);
}

TEMPLATE Parrot_branch_n_nc_ic {
    jit_emit_mov_ri_n(NATIVECODE, FSR1, &NUM_CONST[2]);
    if (MAP[1]) {
        jit_emit_cmp_rr_n(NATIVECODE, MAP[1], FSR1);
    }
    else {
        jit_emit_mov_rm_n(NATIVECODE, FSR2, ROFFS_NUM(1));
        jit_emit_cmp_rr_n(NATIVECODE, FSR2, FSR1);
    }
    jit_emit_bc(jit_info, <CON>, *INT_CONST[3]);
}

TEMPLATE Parrot_branch_nc_n_ic {
    if (MAP[2]) {
        jit_emit_mov_ri_i(NATIVECODE, ISR1, &NUM_CONST[1]);
        jit_emit_lfd(NATIVECODE, FSR1, 0, ISR1);
        jit_emit_cmp_rr_n(NATIVECODE, FSR1, MAP[2]);
    }
    else {
        jit_emit_mov_rm_n(NATIVECODE, FSR2, ROFFS_NUM(2));
        jit_emit_mov_ri_i(NATIVECODE, ISR1, &NUM_CONST[1]);
        jit_emit_lfd(NATIVECODE, FSR1, 0, ISR1);
        jit_emit_cmp_rr_n(NATIVECODE, FSR1, FSR2);
    }
    jit_emit_bc(jit_info, <CON>, *INT_CONST[3]);
}

Parrot_eq_n_n_ic {
        Parrot_branch_n_n_ic s/<CON>/BEQ/
}

Parrot_eq_n_nc_ic {
    Parrot_branch_n_nc_ic s/<CON>/BEQ/
}

Parrot_eq_nc_n_ic {
    Parrot_branch_nc_n_ic s/<CON>/BEQ/
}


Parrot_lt_n_n_ic {
    Parrot_branch_n_n_ic s/<CON>/BLT/
}

Parrot_lt_n_nc_ic {
    Parrot_branch_n_nc_ic s/<CON>/BLT/
}

Parrot_lt_nc_n_ic {
    Parrot_branch_nc_n_ic s/<CON>/BLT/
}


Parrot_le_n_n_ic {
    Parrot_branch_n_n_ic s/<CON>/BLE/
}

Parrot_le_n_nc_ic {
    Parrot_branch_n_nc_ic s/<CON>/BLE/
}

Parrot_le_nc_n_ic {
    Parrot_branch_nc_n_ic s/<CON>/BLE/
}

Parrot_ne_n_n_ic {
    Parrot_branch_n_n_ic s/<CON>/BNE/
}

Parrot_ne_n_nc_ic {
    Parrot_branch_n_nc_ic s/<CON>/BNE/
}

Parrot_ne_nc_n_ic {
    Parrot_branch_nc_n_ic s/<CON>/BLE/
}


Parrot_branch_ic {
    jit_emit_bx(jit_info, 0, *INT_CONST[1]);
}

Parrot_branch_i {
    jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_INT(1));
    jit_emit_mtlr(NATIVECODE, ISR1);
    jit_emit_blr(NATIVECODE);
}

TEMPLATE Parrot_set_or_clone_s_sc {
; string_copy(Interp *interp, STRING *s)
    jit_emit_mov_rr(NATIVECODE, r3, r16);
    jit_emit_mov_ri_i(NATIVECODE, r4, CONST(2)->u.string);

    jit_emit_call_func(NATIVECODE, (void*) string_copy);

    jit_emit_mov_mr_i(NATIVECODE, ROFFS_STR(1), r3);
}

Parrot_set_s_sc {
    Parrot_set_or_clone_s_sc
}

Parrot_clone_s_sc {
    Parrot_set_or_clone_s_sc
}

Parrot_set_s_s {
    jit_emit_mov_rm_i(NATIVECODE, ISR1, ROFFS_STR(2));
    jit_emit_mov_mr_i(NATIVECODE, ROFFS_STR(1), ISR1);
}

Parrot_clone_s_s {
    jit_emit_mov_rr(NATIVECODE, r3, r16);
    jit_emit_mov_rm_i(NATIVECODE, r4, ROFFS_STR(2));

    jit_emit_call_func(NATIVECODE, (void*) string_copy);

    jit_emit_mov_mr_i(NATIVECODE,ROFFS_STR(1), r3);
}

Parrot_set_p_pc {
    jit_emit_mov_ri_i(NATIVECODE, ISR1, CONST(2)->u.key);
    jit_emit_mov_mr_i(NATIVECODE, ROFFS_PMC(1), ISR1);
}

; the following 4 ops don't branch but are translated as cpfp
; which adds unneeded overhead - convert to normal ops
; or just JIT (TODO)  the 2 easy ones
Parrot_set_args_pc {
    if (jit_info->code_type == JIT_CODE_FILE) {
    jit_emit_mov_ri_i(NATIVECODE, ISR1, jit_info->cur_op);
    jit_emit_stw(NATIVECODE, ISR1, offsetof(Interp, current_args), r16);
    }
    else  {
        jit_set_args_pc(jit_info, interp,
            jit_info->flags & JIT_CODE_RECURSIVE);
    }
}

extern Parrot_set_returns_pc {
    if (jit_info->code_type == JIT_CODE_FILE)
    Parrot_jit_normal_op(jit_info, interp);
    else {
        jit_set_returns_pc(jit_info, interp,
            jit_info->flags & JIT_CODE_RECURSIVE);
    }
}

extern Parrot_returncc {
    if (jit_info->code_type == JIT_CODE_FILE)
    Parrot_jit_restart_op(jit_info, interp);
    else {
    /* fetch args[n+1] -> retval */
        if (!(jit_info->flags & JIT_CODE_RECURSIVE)) {
        jit_emit_lwz(jit_info->native_ptr, r1, 0, r1);
        jit_emit_lwz(jit_info->native_ptr, r3, 4 + jit_info->n_args * 4, r5);
        jit_emit_lwz(jit_info->native_ptr, r31, -4, r1);
        jit_emit_lwz(jit_info->native_ptr, r0, 8, r1);   /* get link reg */
        jit_emit_mtlr(jit_info->native_ptr, r0);   /* move to link reg */
    }
    jit_emit_blr(jit_info->native_ptr);
    }
}

Parrot_pic_callr___pc {
    PackFile_Constant **constants  = CONTEXT(interp)->constants;
    PMC                *sig_result = constants[CUR_OPCODE[1]]->u.key;
    opcode_t           *params     = jit_info->optimizer->sections->begin;
    PMC                *sig_params = constants[params[1]]->u.key;
    int                 op_i       = SIG_ELEMS(sig_params) + 2;
    int                 offset     = jit_info->arena.op_map[op_i].offset;
    int                 here       = NATIVECODE - jit_info->arena.start;
    int                 skip;

    /* TODO preserve necessary regs */
    assert(*CUR_OPCODE == PARROT_OP_get_results_pc);

    if (!SIG_ELEMS(sig_result))
        skip = -1;
    /* skip result - save rest */
    else
        skip = MAP(2);

    offset -= here;

    /* bl */
    _emit_bx(NATIVECODE, 1, offset);

    jit_restore_regs_call(jit_info, interp, skip);
}

extern Parrot_get_params_pc {
    if (jit_info->code_type == JIT_CODE_FILE)
    Parrot_jit_normal_op(jit_info, interp);
    else if (!(jit_info->flags & JIT_CODE_RECURSIVE)) {
        jit_get_params_pc(jit_info, interp);
    }
}

Parrot_get_results_pc {
    if (jit_info->code_type == JIT_CODE_FILE) {
    jit_emit_mov_ri_i(NATIVECODE, ISR1, jit_info->cur_op);
    jit_emit_lwz(NATIVECODE, ISR2, offsetof(Interp, ctx.state), r16);
    jit_emit_stw(NATIVECODE, ISR1,
        offsetof(Parrot_Context, current_results), ISR2);
    }
    else {
    PackFile_Constant **constants  = CONTEXT(interp)->constants;
    PMC                *sig_result = constants[CUR_OPCODE[1]]->u.key;

    if (!SIG_ELEMS(sig_result))
        return;

    /* result is r3 TODO Nums */
    jit_emit_mov_rr(NATIVECODE, MAP(2), r3);
    }
}
