qemu/target/hppa/translate.c
/* Emit an unconditional branch to an indirect target.  This handles
   nullification of the branch itself.  */
Emit an unconditional branch to an indirect target.  This handles
nullification of the branch itself.
Emit an unconditional branch to an indirect target . This handles nullification of the branch itself .
static DisasJumpType do_ibranch(DisasContext *ctx, TCGv_reg dest,
                                unsigned link, bool is_n)
{
    TCGv_reg a0, a1, next, tmp;
    TCGCond c;
    assert(ctx->null_lab == NULL);
    if (ctx->null_cond.c == TCG_COND_NEVER) {
        if (link != 0) {
            copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
        }
        next = get_temp(ctx);
        tcg_gen_mov_reg(next, dest);
        if (is_n) {
            if (use_nullify_skip(ctx)) {
                tcg_gen_mov_reg(cpu_iaoq_f, next);
                tcg_gen_addi_reg(cpu_iaoq_b, next, 4);
                nullify_set(ctx, 0);
                return DISAS_IAQ_N_UPDATED;
            }
            ctx->null_cond.c = TCG_COND_ALWAYS;
        }
        ctx->iaoq_n = -1;
        ctx->iaoq_n_var = next;
    } else if (is_n && use_nullify_skip(ctx)) {
        tcg_debug_assert(ctx->iaoq_b != -1);
        tcg_debug_assert(ctx->iaoq_n != -1);
        tcg_gen_mov_reg(cpu_iaoq_f, dest);
        tcg_gen_addi_reg(cpu_iaoq_b, dest, 4);
        nullify_over(ctx);
        if (link != 0) {
            tcg_gen_movi_reg(cpu_gr[link], ctx->iaoq_n);
        }
        tcg_gen_lookup_and_goto_ptr();
        return nullify_end(ctx, DISAS_NEXT);
    } else {
        cond_prep(&ctx->null_cond);
        c = ctx->null_cond.c;
        a0 = ctx->null_cond.a0;
        a1 = ctx->null_cond.a1;
        tmp = tcg_temp_new();
        next = get_temp(ctx);
        copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
        tcg_gen_movcond_reg(c, next, a0, a1, tmp, dest);
        ctx->iaoq_n = -1;
        ctx->iaoq_n_var = next;
        if (link != 0) {
            tcg_gen_movcond_reg(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
        }
        if (is_n) {
            tcg_gen_setcond_reg(tcg_invert_cond(c), cpu_psw_n, a0, a1);
            cond_free(&ctx->null_cond);
            ctx->null_cond = cond_make_n();
            ctx->psw_n_nonzero = true;
        } else {
            cond_free(&ctx->null_cond);
        }
    }
    return DISAS_NEXT;
}
static DisasJumpType do_ibranch ( DisasContext * ctx , TCGv_reg dest , unsigned link , bool is_n ) { TCGv_reg a0 , a1 , next , tmp ; TCGCond c ; assert ( ctx -> null_lab == NULL ) ; if ( ctx -> null_cond . c == TCG_COND_NEVER ) { if ( link != 0 ) { copy_iaoq_entry ( cpu_gr [ link ] , ctx -> iaoq_n , ctx -> iaoq_n_var ) ; } next = get_temp ( ctx ) ; tcg_gen_mov_reg ( next , dest ) ; if ( is_n ) { if ( use_nullify_skip ( ctx ) ) { tcg_gen_mov_reg ( cpu_iaoq_f , next ) ; tcg_gen_addi_reg ( cpu_iaoq_b , next , 4 ) ; nullify_set ( ctx , 0 ) ; return DISAS_IAQ_N_UPDATED ; } ctx -> null_cond . c = TCG_COND_ALWAYS ; } ctx -> iaoq_n = -1 ; ctx -> iaoq_n_var = next ; } else if ( is_n && use_nullify_skip ( ctx ) ) { tcg_debug_assert ( ctx -> iaoq_b != -1 ) ; tcg_debug_assert ( ctx -> iaoq_n != -1 ) ; tcg_gen_mov_reg ( cpu_iaoq_f , dest ) ; tcg_gen_addi_reg ( cpu_iaoq_b , dest , 4 ) ; nullify_over ( ctx ) ; if ( link != 0 ) { tcg_gen_movi_reg ( cpu_gr [ link ] , ctx -> iaoq_n ) ; } tcg_gen_lookup_and_goto_ptr ( ) ; return nullify_end ( ctx , DISAS_NEXT ) ; } else { cond_prep ( & ctx -> null_cond ) ; c = ctx -> null_cond . c ; a0 = ctx -> null_cond . a0 ; a1 = ctx -> null_cond . a1 ; tmp = tcg_temp_new ( ) ; next = get_temp ( ctx ) ; copy_iaoq_entry ( tmp , ctx -> iaoq_n , ctx -> iaoq_n_var ) ; tcg_gen_movcond_reg ( c , next , a0 , a1 , tmp , dest ) ; ctx -> iaoq_n = -1 ; ctx -> iaoq_n_var = next ; if ( link != 0 ) { tcg_gen_movcond_reg ( c , cpu_gr [ link ] , a0 , a1 , cpu_gr [ link ] , tmp ) ; } if ( is_n ) { tcg_gen_setcond_reg ( tcg_invert_cond ( c ) , cpu_psw_n , a0 , a1 ) ; cond_free ( & ctx -> null_cond ) ; ctx -> null_cond = cond_make_n ( ) ; ctx -> psw_n_nonzero = true ; } else { cond_free ( & ctx -> null_cond ) ; } } return DISAS_NEXT ; }
Emit an unconditional branch to an indirect target.
Emit an unconditional branch to an indirect target .
/* The (conditional) branch, B, nullifies the next insn, N,
           and we're allowed to skip execution N (no single-step or
           tracepoint in effect).  Since the goto_ptr that we must use
           for the indirect branch consumes no special resources, we
           can (conditionally) skip B and continue execution.  */ /* The use_nullify_skip test implies we have a known control path.  */ /* We do have to handle the non-local temporary, DEST, before
           branching.  Since IOAQ_F is not really live at this point, we
           can simply store DEST optimistically.  Similarly with IAOQ_B.  */ /* The branch nullifies the next insn, which means the state of N
               after the branch is the inverse of the state of N that applied
               to the branch.  */