target/hppa: Convert direct and indirect branches

Tested-by: Helge Deller <deller@gmx.de>
Tested-by: Sven Schnelle <svens@stackframe.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2018-02-12 09:36:07 -08:00
parent 30878590bc
commit 8340f5341e
2 changed files with 63 additions and 102 deletions

View File

@ -24,7 +24,9 @@
%assemble_sr3 13:1 14:2 %assemble_sr3 13:1 14:2
%assemble_sr3x 13:1 14:2 !function=expand_sr3x %assemble_sr3x 13:1 14:2 !function=expand_sr3x
%assemble_12 0:s1 2:1 3:10 !function=expand_shl2 %assemble_12 0:s1 2:1 3:10 !function=expand_shl2
%assemble_17 0:s1 16:5 2:1 3:10 !function=expand_shl2
%assemble_22 0:s1 16:10 2:1 3:10 !function=expand_shl2
%sm_imm 16:10 !function=expand_sm_imm %sm_imm 16:10 !function=expand_sm_imm
@ -210,3 +212,33 @@ depw_sar 110101 t:5 r:5 c:3 00 nz:1 00000 clen:5
depw_imm 110101 t:5 r:5 c:3 01 nz:1 cpos:5 clen:5 depw_imm 110101 t:5 r:5 c:3 01 nz:1 cpos:5 clen:5
depwi_sar 110101 t:5 ..... c:3 10 nz:1 00000 clen:5 i=%im5_16 depwi_sar 110101 t:5 ..... c:3 10 nz:1 00000 clen:5 i=%im5_16
depwi_imm 110101 t:5 ..... c:3 11 nz:1 cpos:5 clen:5 i=%im5_16 depwi_imm 110101 t:5 ..... c:3 11 nz:1 cpos:5 clen:5 i=%im5_16
####
# Branch External
####
&BE b l n disp sp
@be ...... b:5 ..... ... ........... n:1 . \
&BE disp=%assemble_17 sp=%assemble_sr3
be 111000 ..... ..... ... ........... . . @be l=0
be 111001 ..... ..... ... ........... . . @be l=31
####
# Branch
####
&BL l n disp
@bl ...... l:5 ..... ... ........... n:1 . &BL disp=%assemble_17
# B,L and B,L,PUSH
bl 111010 ..... ..... 000 ........... . . @bl
bl 111010 ..... ..... 100 ........... . . @bl
# B,L (long displacement)
bl 111010 ..... ..... 101 ........... n:1 . &BL l=2 \
disp=%assemble_22
b_gate 111010 ..... ..... 001 ........... . . @bl
blr 111010 l:5 x:5 010 00000000000 n:1 0
bv 111010 b:5 x:5 110 00000000000 n:1 0
bve 111010 b:5 00000 110 10000000000 n:1 - l=0
bve 111010 b:5 00000 111 10000000000 n:1 - l=2

View File

@ -895,15 +895,6 @@ static target_sreg assemble_16a(uint32_t insn)
return x << 2; return x << 2;
} }
static target_sreg assemble_17(uint32_t insn)
{
target_ureg x = -(target_ureg)(insn & 1);
x = (x << 5) | extract32(insn, 16, 5);
x = (x << 1) | extract32(insn, 2, 1);
x = (x << 10) | extract32(insn, 3, 10);
return x << 2;
}
static target_sreg assemble_21(uint32_t insn) static target_sreg assemble_21(uint32_t insn)
{ {
target_ureg x = -(target_ureg)(insn & 1); target_ureg x = -(target_ureg)(insn & 1);
@ -914,15 +905,6 @@ static target_sreg assemble_21(uint32_t insn)
return x << 11; return x << 11;
} }
static target_sreg assemble_22(uint32_t insn)
{
target_ureg x = -(target_ureg)(insn & 1);
x = (x << 10) | extract32(insn, 16, 10);
x = (x << 1) | extract32(insn, 2, 1);
x = (x << 10) | extract32(insn, 3, 10);
return x << 2;
}
/* The parisc documentation describes only the general interpretation of /* The parisc documentation describes only the general interpretation of
the conditions, without describing their exact implementation. The the conditions, without describing their exact implementation. The
interpretations do not stand up well when considering ADD,C and SUB,B. interpretations do not stand up well when considering ADD,C and SUB,B.
@ -3546,11 +3528,8 @@ static bool trans_depwi_sar(DisasContext *ctx, arg_depwi_sar *a)
return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_const(ctx, a->i)); return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_const(ctx, a->i));
} }
static bool trans_be(DisasContext *ctx, uint32_t insn, bool is_l) static bool trans_be(DisasContext *ctx, arg_be *a)
{ {
unsigned n = extract32(insn, 1, 1);
unsigned b = extract32(insn, 21, 5);
target_sreg disp = assemble_17(insn);
TCGv_reg tmp; TCGv_reg tmp;
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
@ -3562,29 +3541,28 @@ static bool trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
/* Since we don't implement spaces, just branch. Do notice the special /* Since we don't implement spaces, just branch. Do notice the special
case of "be disp(*,r0)" using a direct branch to disp, so that we can case of "be disp(*,r0)" using a direct branch to disp, so that we can
goto_tb to the TB containing the syscall. */ goto_tb to the TB containing the syscall. */
if (b == 0) { if (a->b == 0) {
return do_dbranch(ctx, disp, is_l ? 31 : 0, n); return do_dbranch(ctx, a->disp, a->l, a->n);
} }
#else #else
int sp = assemble_sr3(insn);
nullify_over(ctx); nullify_over(ctx);
#endif #endif
tmp = get_temp(ctx); tmp = get_temp(ctx);
tcg_gen_addi_reg(tmp, load_gpr(ctx, b), disp); tcg_gen_addi_reg(tmp, load_gpr(ctx, a->b), a->disp);
tmp = do_ibranch_priv(ctx, tmp); tmp = do_ibranch_priv(ctx, tmp);
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
return do_ibranch(ctx, tmp, is_l ? 31 : 0, n); return do_ibranch(ctx, tmp, a->l, a->n);
#else #else
TCGv_i64 new_spc = tcg_temp_new_i64(); TCGv_i64 new_spc = tcg_temp_new_i64();
load_spr(ctx, new_spc, sp); load_spr(ctx, new_spc, a->sp);
if (is_l) { if (a->l) {
copy_iaoq_entry(cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var); copy_iaoq_entry(cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f); tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
} }
if (n && use_nullify_skip(ctx)) { if (a->n && use_nullify_skip(ctx)) {
tcg_gen_mov_reg(cpu_iaoq_f, tmp); tcg_gen_mov_reg(cpu_iaoq_f, tmp);
tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4); tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4);
tcg_gen_mov_i64(cpu_iasq_f, new_spc); tcg_gen_mov_i64(cpu_iasq_f, new_spc);
@ -3596,7 +3574,7 @@ static bool trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
} }
tcg_gen_mov_reg(cpu_iaoq_b, tmp); tcg_gen_mov_reg(cpu_iaoq_b, tmp);
tcg_gen_mov_i64(cpu_iasq_b, new_spc); tcg_gen_mov_i64(cpu_iasq_b, new_spc);
nullify_set(ctx, n); nullify_set(ctx, a->n);
} }
tcg_temp_free_i64(new_spc); tcg_temp_free_i64(new_spc);
tcg_gen_lookup_and_goto_ptr(); tcg_gen_lookup_and_goto_ptr();
@ -3605,22 +3583,14 @@ static bool trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
#endif #endif
} }
static bool trans_bl(DisasContext *ctx, uint32_t insn, const DisasInsn *di) static bool trans_bl(DisasContext *ctx, arg_bl *a)
{ {
unsigned n = extract32(insn, 1, 1); return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
unsigned link = extract32(insn, 21, 5);
target_sreg disp = assemble_17(insn);
do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
return true;
} }
static bool trans_b_gate(DisasContext *ctx, uint32_t insn, const DisasInsn *di) static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
{ {
unsigned n = extract32(insn, 1, 1); target_ureg dest = iaoq_dest(ctx, a->disp);
unsigned link = extract32(insn, 21, 5);
target_sreg disp = assemble_17(insn);
target_ureg dest = iaoq_dest(ctx, disp);
/* Make sure the caller hasn't done something weird with the queue. /* Make sure the caller hasn't done something weird with the queue.
* ??? This is not quite the same as the PSW[B] bit, which would be * ??? This is not quite the same as the PSW[B] bit, which would be
@ -3659,65 +3629,44 @@ static bool trans_b_gate(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
} }
#endif #endif
do_dbranch(ctx, dest, link, n); return do_dbranch(ctx, dest, a->l, a->n);
return true;
} }
static bool trans_bl_long(DisasContext *ctx, uint32_t insn, const DisasInsn *di) static bool trans_blr(DisasContext *ctx, arg_blr *a)
{ {
unsigned n = extract32(insn, 1, 1);
target_sreg disp = assemble_22(insn);
do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
return true;
}
static bool trans_blr(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
{
unsigned n = extract32(insn, 1, 1);
unsigned rx = extract32(insn, 16, 5);
unsigned link = extract32(insn, 21, 5);
TCGv_reg tmp = get_temp(ctx); TCGv_reg tmp = get_temp(ctx);
tcg_gen_shli_reg(tmp, load_gpr(ctx, rx), 3); tcg_gen_shli_reg(tmp, load_gpr(ctx, a->x), 3);
tcg_gen_addi_reg(tmp, tmp, ctx->iaoq_f + 8); tcg_gen_addi_reg(tmp, tmp, ctx->iaoq_f + 8);
/* The computation here never changes privilege level. */ /* The computation here never changes privilege level. */
do_ibranch(ctx, tmp, link, n); return do_ibranch(ctx, tmp, a->l, a->n);
return true;
} }
static bool trans_bv(DisasContext *ctx, uint32_t insn, const DisasInsn *di) static bool trans_bv(DisasContext *ctx, arg_bv *a)
{ {
unsigned n = extract32(insn, 1, 1);
unsigned rx = extract32(insn, 16, 5);
unsigned rb = extract32(insn, 21, 5);
TCGv_reg dest; TCGv_reg dest;
if (rx == 0) { if (a->x == 0) {
dest = load_gpr(ctx, rb); dest = load_gpr(ctx, a->b);
} else { } else {
dest = get_temp(ctx); dest = get_temp(ctx);
tcg_gen_shli_reg(dest, load_gpr(ctx, rx), 3); tcg_gen_shli_reg(dest, load_gpr(ctx, a->x), 3);
tcg_gen_add_reg(dest, dest, load_gpr(ctx, rb)); tcg_gen_add_reg(dest, dest, load_gpr(ctx, a->b));
} }
dest = do_ibranch_priv(ctx, dest); dest = do_ibranch_priv(ctx, dest);
do_ibranch(ctx, dest, 0, n); return do_ibranch(ctx, dest, 0, a->n);
return true;
} }
static bool trans_bve(DisasContext *ctx, uint32_t insn, const DisasInsn *di) static bool trans_bve(DisasContext *ctx, arg_bve *a)
{ {
unsigned n = extract32(insn, 1, 1);
unsigned rb = extract32(insn, 21, 5);
unsigned link = extract32(insn, 13, 1) ? 2 : 0;
TCGv_reg dest; TCGv_reg dest;
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
dest = do_ibranch_priv(ctx, load_gpr(ctx, rb)); dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
do_ibranch(ctx, dest, link, n); return do_ibranch(ctx, dest, a->l, a->n);
#else #else
nullify_over(ctx); nullify_over(ctx);
dest = do_ibranch_priv(ctx, load_gpr(ctx, rb)); dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
if (ctx->iaoq_b == -1) { if (ctx->iaoq_b == -1) {
@ -3725,26 +3674,16 @@ static bool trans_bve(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
} }
copy_iaoq_entry(cpu_iaoq_b, -1, dest); copy_iaoq_entry(cpu_iaoq_b, -1, dest);
tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest)); tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
if (link) { if (a->l) {
copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); copy_iaoq_entry(cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
} }
nullify_set(ctx, n); nullify_set(ctx, a->n);
tcg_gen_lookup_and_goto_ptr(); tcg_gen_lookup_and_goto_ptr();
ctx->base.is_jmp = DISAS_NORETURN; ctx->base.is_jmp = DISAS_NORETURN;
return nullify_end(ctx); return nullify_end(ctx);
#endif #endif
return true;
} }
static const DisasInsn table_branch[] = {
{ 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
{ 0xe800a000u, 0xfc00e000u, trans_bl_long },
{ 0xe8004000u, 0xfc00fffdu, trans_blr },
{ 0xe800c000u, 0xfc00fffdu, trans_bv },
{ 0xe800d000u, 0xfc00dffcu, trans_bve },
{ 0xe8002000u, 0xfc00e000u, trans_b_gate },
};
static bool trans_fop_wew_0c(DisasContext *ctx, uint32_t insn, static bool trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
const DisasInsn *di) const DisasInsn *di)
{ {
@ -4422,16 +4361,6 @@ static void translate_one(DisasContext *ctx, uint32_t insn)
translate_table(ctx, insn, table_fp_fused); translate_table(ctx, insn, table_fp_fused);
return; return;
case 0x38:
trans_be(ctx, insn, false);
return;
case 0x39:
trans_be(ctx, insn, true);
return;
case 0x3A:
translate_table(ctx, insn, table_branch);
return;
case 0x04: /* spopn */ case 0x04: /* spopn */
case 0x05: /* diag */ case 0x05: /* diag */
case 0x0F: /* product specific */ case 0x0F: /* product specific */