target/riscv: Remove manual decoding of RV32/64M insn

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
Signed-off-by: Peer Adelt <peer.adelt@hni.uni-paderborn.de>
This commit is contained in:
Bastian Koppelmann 2019-02-13 07:54:06 -08:00
parent 34446e8458
commit 1288701682
2 changed files with 152 additions and 199 deletions

View File

@ -22,92 +22,99 @@
static bool trans_mul(DisasContext *ctx, arg_mul *a) static bool trans_mul(DisasContext *ctx, arg_mul *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_MUL, a->rd, a->rs1, a->rs2); return trans_arith(ctx, a, &tcg_gen_mul_tl);
return true;
} }
static bool trans_mulh(DisasContext *ctx, arg_mulh *a) static bool trans_mulh(DisasContext *ctx, arg_mulh *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_MULH, a->rd, a->rs1, a->rs2); TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
tcg_gen_muls2_tl(source2, source1, source1, source2);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
return true; return true;
} }
static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a) static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_MULHSU, a->rd, a->rs1, a->rs2); return trans_arith(ctx, a, &gen_mulhsu);
return true;
} }
static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a) static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_MULHU, a->rd, a->rs1, a->rs2); TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
tcg_gen_mulu2_tl(source2, source1, source1, source2);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
return true; return true;
} }
static bool trans_div(DisasContext *ctx, arg_div *a) static bool trans_div(DisasContext *ctx, arg_div *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_DIV, a->rd, a->rs1, a->rs2); return trans_arith(ctx, a, &gen_div);
return true;
} }
static bool trans_divu(DisasContext *ctx, arg_divu *a) static bool trans_divu(DisasContext *ctx, arg_divu *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_DIVU, a->rd, a->rs1, a->rs2); return trans_arith(ctx, a, &gen_divu);
return true;
} }
static bool trans_rem(DisasContext *ctx, arg_rem *a) static bool trans_rem(DisasContext *ctx, arg_rem *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_REM, a->rd, a->rs1, a->rs2); return trans_arith(ctx, a, &gen_rem);
return true;
} }
static bool trans_remu(DisasContext *ctx, arg_remu *a) static bool trans_remu(DisasContext *ctx, arg_remu *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_REMU, a->rd, a->rs1, a->rs2); return trans_arith(ctx, a, &gen_remu);
return true;
} }
#ifdef TARGET_RISCV64 #ifdef TARGET_RISCV64
static bool trans_mulw(DisasContext *ctx, arg_mulw *a) static bool trans_mulw(DisasContext *ctx, arg_mulw *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_MULW, a->rd, a->rs1, a->rs2); return trans_arith(ctx, a, &gen_mulw);
return true;
} }
static bool trans_divw(DisasContext *ctx, arg_divw *a) static bool trans_divw(DisasContext *ctx, arg_divw *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_DIVW, a->rd, a->rs1, a->rs2); return gen_arith_div_w(ctx, a, &gen_div);
return true;
} }
static bool trans_divuw(DisasContext *ctx, arg_divuw *a) static bool trans_divuw(DisasContext *ctx, arg_divuw *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_DIVUW, a->rd, a->rs1, a->rs2); return gen_arith_div_w(ctx, a, &gen_divu);
return true;
} }
static bool trans_remw(DisasContext *ctx, arg_remw *a) static bool trans_remw(DisasContext *ctx, arg_remw *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_REMW, a->rd, a->rs1, a->rs2); return gen_arith_div_w(ctx, a, &gen_rem);
return true;
} }
static bool trans_remuw(DisasContext *ctx, arg_remuw *a) static bool trans_remuw(DisasContext *ctx, arg_remuw *a)
{ {
REQUIRE_EXT(ctx, RVM); REQUIRE_EXT(ctx, RVM);
gen_arith(ctx, OPC_RISC_REMUW, a->rd, a->rs1, a->rs2); return gen_arith_div_w(ctx, a, &gen_remu);
return true;
} }
#endif #endif

View File

@ -188,193 +188,112 @@ static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2)
tcg_temp_free(rh); tcg_temp_free(rh);
} }
static void gen_arith(DisasContext *ctx, uint32_t opc, int rd, int rs1, static void gen_div(TCGv ret, TCGv source1, TCGv source2)
int rs2)
{ {
TCGv source1, source2, cond1, cond2, zeroreg, resultopt1; TCGv cond1, cond2, zeroreg, resultopt1;
source1 = tcg_temp_new(); /*
source2 = tcg_temp_new(); * Handle by altering args to tcg_gen_div to produce req'd results:
gen_get_gpr(source1, rs1); * For overflow: want source1 in source1 and 1 in source2
gen_get_gpr(source2, rs2); * For div by zero: want -1 in source1 and 1 in source2 -> -1 result
*/
cond1 = tcg_temp_new();
cond2 = tcg_temp_new();
zeroreg = tcg_const_tl(0);
resultopt1 = tcg_temp_new();
switch (opc) { tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
CASE_OP_32_64(OPC_RISC_MUL): tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L));
if (!has_ext(ctx, RVM)) { tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
goto do_illegal; ((target_ulong)1) << (TARGET_LONG_BITS - 1));
} tcg_gen_and_tl(cond1, cond1, cond2); /* cond1 = overflow */
tcg_gen_mul_tl(source1, source1, source2); tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, 0); /* cond2 = div 0 */
break; /* if div by zero, set source1 to -1, otherwise don't change */
case OPC_RISC_MULH: tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond2, zeroreg, source1,
if (!has_ext(ctx, RVM)) { resultopt1);
goto do_illegal; /* if overflow or div by zero, set source2 to 1, else don't change */
} tcg_gen_or_tl(cond1, cond1, cond2);
tcg_gen_muls2_tl(source2, source1, source1, source2); tcg_gen_movi_tl(resultopt1, (target_ulong)1);
break; tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
case OPC_RISC_MULHSU: resultopt1);
if (!has_ext(ctx, RVM)) { tcg_gen_div_tl(ret, source1, source2);
goto do_illegal;
}
gen_mulhsu(source1, source1, source2);
break;
case OPC_RISC_MULHU:
if (!has_ext(ctx, RVM)) {
goto do_illegal;
}
tcg_gen_mulu2_tl(source2, source1, source1, source2);
break;
#if defined(TARGET_RISCV64)
case OPC_RISC_DIVW:
if (!has_ext(ctx, RVM)) {
goto do_illegal;
}
tcg_gen_ext32s_tl(source1, source1);
tcg_gen_ext32s_tl(source2, source2);
/* fall through to DIV */
#endif
case OPC_RISC_DIV:
if (!has_ext(ctx, RVM)) {
goto do_illegal;
}
/* Handle by altering args to tcg_gen_div to produce req'd results:
* For overflow: want source1 in source1 and 1 in source2
* For div by zero: want -1 in source1 and 1 in source2 -> -1 result */
cond1 = tcg_temp_new();
cond2 = tcg_temp_new();
zeroreg = tcg_const_tl(0);
resultopt1 = tcg_temp_new();
tcg_gen_movi_tl(resultopt1, (target_ulong)-1); tcg_temp_free(cond1);
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L)); tcg_temp_free(cond2);
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1, tcg_temp_free(zeroreg);
((target_ulong)1) << (TARGET_LONG_BITS - 1)); tcg_temp_free(resultopt1);
tcg_gen_and_tl(cond1, cond1, cond2); /* cond1 = overflow */ }
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, 0); /* cond2 = div 0 */
/* if div by zero, set source1 to -1, otherwise don't change */
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond2, zeroreg, source1,
resultopt1);
/* if overflow or div by zero, set source2 to 1, else don't change */
tcg_gen_or_tl(cond1, cond1, cond2);
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
resultopt1);
tcg_gen_div_tl(source1, source1, source2);
tcg_temp_free(cond1); static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
tcg_temp_free(cond2); {
tcg_temp_free(zeroreg); TCGv cond1, zeroreg, resultopt1;
tcg_temp_free(resultopt1); cond1 = tcg_temp_new();
break;
#if defined(TARGET_RISCV64)
case OPC_RISC_DIVUW:
if (!has_ext(ctx, RVM)) {
goto do_illegal;
}
tcg_gen_ext32u_tl(source1, source1);
tcg_gen_ext32u_tl(source2, source2);
/* fall through to DIVU */
#endif
case OPC_RISC_DIVU:
if (!has_ext(ctx, RVM)) {
goto do_illegal;
}
cond1 = tcg_temp_new();
zeroreg = tcg_const_tl(0);
resultopt1 = tcg_temp_new();
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); zeroreg = tcg_const_tl(0);
tcg_gen_movi_tl(resultopt1, (target_ulong)-1); resultopt1 = tcg_temp_new();
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, source1,
resultopt1);
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
resultopt1);
tcg_gen_divu_tl(source1, source1, source2);
tcg_temp_free(cond1); tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
tcg_temp_free(zeroreg); tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
tcg_temp_free(resultopt1); tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, source1,
break; resultopt1);
#if defined(TARGET_RISCV64) tcg_gen_movi_tl(resultopt1, (target_ulong)1);
case OPC_RISC_REMW: tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
if (!has_ext(ctx, RVM)) { resultopt1);
goto do_illegal; tcg_gen_divu_tl(ret, source1, source2);
}
tcg_gen_ext32s_tl(source1, source1);
tcg_gen_ext32s_tl(source2, source2);
/* fall through to REM */
#endif
case OPC_RISC_REM:
if (!has_ext(ctx, RVM)) {
goto do_illegal;
}
cond1 = tcg_temp_new();
cond2 = tcg_temp_new();
zeroreg = tcg_const_tl(0);
resultopt1 = tcg_temp_new();
tcg_gen_movi_tl(resultopt1, 1L); tcg_temp_free(cond1);
tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)-1); tcg_temp_free(zeroreg);
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1, tcg_temp_free(resultopt1);
(target_ulong)1 << (TARGET_LONG_BITS - 1)); }
tcg_gen_and_tl(cond2, cond1, cond2); /* cond1 = overflow */
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); /* cond2 = div 0 */
/* if overflow or div by zero, set source2 to 1, else don't change */
tcg_gen_or_tl(cond2, cond1, cond2);
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond2, zeroreg, source2,
resultopt1);
tcg_gen_rem_tl(resultopt1, source1, source2);
/* if div by zero, just return the original dividend */
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, resultopt1,
source1);
tcg_temp_free(cond1); static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
tcg_temp_free(cond2); {
tcg_temp_free(zeroreg); TCGv cond1, cond2, zeroreg, resultopt1;
tcg_temp_free(resultopt1);
break;
#if defined(TARGET_RISCV64)
case OPC_RISC_REMUW:
if (!has_ext(ctx, RVM)) {
goto do_illegal;
}
tcg_gen_ext32u_tl(source1, source1);
tcg_gen_ext32u_tl(source2, source2);
/* fall through to REMU */
#endif
case OPC_RISC_REMU:
if (!has_ext(ctx, RVM)) {
goto do_illegal;
}
cond1 = tcg_temp_new();
zeroreg = tcg_const_tl(0);
resultopt1 = tcg_temp_new();
tcg_gen_movi_tl(resultopt1, (target_ulong)1); cond1 = tcg_temp_new();
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); cond2 = tcg_temp_new();
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2, zeroreg = tcg_const_tl(0);
resultopt1); resultopt1 = tcg_temp_new();
tcg_gen_remu_tl(resultopt1, source1, source2);
/* if div by zero, just return the original dividend */
tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, resultopt1,
source1);
tcg_temp_free(cond1); tcg_gen_movi_tl(resultopt1, 1L);
tcg_temp_free(zeroreg); tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)-1);
tcg_temp_free(resultopt1); tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
break; (target_ulong)1 << (TARGET_LONG_BITS - 1));
do_illegal: tcg_gen_and_tl(cond2, cond1, cond2); /* cond1 = overflow */
default: tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); /* cond2 = div 0 */
gen_exception_illegal(ctx); /* if overflow or div by zero, set source2 to 1, else don't change */
return; tcg_gen_or_tl(cond2, cond1, cond2);
} tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond2, zeroreg, source2,
resultopt1);
tcg_gen_rem_tl(resultopt1, source1, source2);
/* if div by zero, just return the original dividend */
tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1,
source1);
if (opc & 0x8) { /* sign extend for W instructions */ tcg_temp_free(cond1);
tcg_gen_ext32s_tl(source1, source1); tcg_temp_free(cond2);
} tcg_temp_free(zeroreg);
tcg_temp_free(resultopt1);
}
gen_set_gpr(rd, source1); static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
tcg_temp_free(source1); {
tcg_temp_free(source2); TCGv cond1, zeroreg, resultopt1;
cond1 = tcg_temp_new();
zeroreg = tcg_const_tl(0);
resultopt1 = tcg_temp_new();
tcg_gen_movi_tl(resultopt1, (target_ulong)1);
tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
resultopt1);
tcg_gen_remu_tl(resultopt1, source1, source2);
/* if div by zero, just return the original dividend */
tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1,
source1);
tcg_temp_free(cond1);
tcg_temp_free(zeroreg);
tcg_temp_free(resultopt1);
} }
static void gen_jal(DisasContext *ctx, int rd, target_ulong imm) static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
@ -681,6 +600,33 @@ static void gen_subw(TCGv ret, TCGv arg1, TCGv arg2)
tcg_gen_ext32s_tl(ret, ret); tcg_gen_ext32s_tl(ret, ret);
} }
static void gen_mulw(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_mul_tl(ret, arg1, arg2);
tcg_gen_ext32s_tl(ret, ret);
}
static bool gen_arith_div_w(DisasContext *ctx, arg_r *a,
void(*func)(TCGv, TCGv, TCGv))
{
TCGv source1, source2;
source1 = tcg_temp_new();
source2 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
gen_get_gpr(source2, a->rs2);
tcg_gen_ext32s_tl(source1, source1);
tcg_gen_ext32s_tl(source2, source2);
(*func)(source1, source1, source2);
tcg_gen_ext32s_tl(source1, source1);
gen_set_gpr(a->rd, source1);
tcg_temp_free(source1);
tcg_temp_free(source2);
return true;
}
#endif #endif
static bool trans_arith(DisasContext *ctx, arg_r *a, static bool trans_arith(DisasContext *ctx, arg_r *a,