target/s390x: Use a single return for helper_divs64/u64
Pack the quotient and remainder into a single Int128. Use the divu128 primitive to remove the cpu_abort on 32-bit hosts. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Acked-by: Ilya Leoshkevich <iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- v2: Extended div test case to cover these insns.
This commit is contained in:
parent
6d28ff406c
commit
4e5712f903
|
@ -12,8 +12,8 @@ DEF_HELPER_3(clcl, i32, env, i32, i32)
|
||||||
DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64)
|
DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64)
|
||||||
DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, i64, env, s64, s64)
|
DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, i64, env, s64, s64)
|
||||||
DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64)
|
DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64)
|
||||||
DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64)
|
DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, i128, env, s64, s64)
|
||||||
DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
|
DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i128, env, i64, i64, i64)
|
||||||
DEF_HELPER_3(srst, void, env, i32, i32)
|
DEF_HELPER_3(srst, void, env, i32, i32)
|
||||||
DEF_HELPER_3(srstu, void, env, i32, i32)
|
DEF_HELPER_3(srstu, void, env, i32, i32)
|
||||||
DEF_HELPER_4(clst, i64, env, i64, i64, i64)
|
DEF_HELPER_4(clst, i64, env, i64, i64, i64)
|
||||||
|
|
|
@ -76,46 +76,26 @@ uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 64/64 -> 64 signed division */
|
/* 64/64 -> 64 signed division */
|
||||||
int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b)
|
Int128 HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b)
|
||||||
{
|
{
|
||||||
/* Catch divide by zero, and non-representable quotient (MIN / -1). */
|
/* Catch divide by zero, and non-representable quotient (MIN / -1). */
|
||||||
if (b == 0 || (b == -1 && a == (1ll << 63))) {
|
if (b == 0 || (b == -1 && a == (1ll << 63))) {
|
||||||
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
|
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
|
||||||
}
|
}
|
||||||
env->retxl = a % b;
|
return int128_make128(a / b, a % b);
|
||||||
return a / b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 128 -> 64/64 unsigned division */
|
/* 128 -> 64/64 unsigned division */
|
||||||
uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
|
Int128 HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t b)
|
||||||
uint64_t b)
|
|
||||||
{
|
{
|
||||||
uint64_t ret;
|
if (b != 0) {
|
||||||
/* Signal divide by zero. */
|
uint64_t r = divu128(&al, &ah, b);
|
||||||
if (b == 0) {
|
if (ah == 0) {
|
||||||
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
|
return int128_make128(al, r);
|
||||||
}
|
|
||||||
if (ah == 0) {
|
|
||||||
/* 64 -> 64/64 case */
|
|
||||||
env->retxl = al % b;
|
|
||||||
ret = al / b;
|
|
||||||
} else {
|
|
||||||
/* ??? Move i386 idivq helper to host-utils. */
|
|
||||||
#ifdef CONFIG_INT128
|
|
||||||
__uint128_t a = ((__uint128_t)ah << 64) | al;
|
|
||||||
__uint128_t q = a / b;
|
|
||||||
env->retxl = a % b;
|
|
||||||
ret = q;
|
|
||||||
if (ret != q) {
|
|
||||||
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
/* 32-bit hosts would need special wrapper functionality - just abort if
|
|
||||||
we encounter such a case; it's very unlikely anyways. */
|
|
||||||
cpu_abort(env_cpu(env), "128 -> 64/64 division not implemented\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return ret;
|
/* divide by zero or overflow */
|
||||||
|
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t HELPER(cvd)(int32_t reg)
|
uint64_t HELPER(cvd)(int32_t reg)
|
||||||
|
|
|
@ -2409,15 +2409,21 @@ static DisasJumpType op_divu32(DisasContext *s, DisasOps *o)
|
||||||
|
|
||||||
static DisasJumpType op_divs64(DisasContext *s, DisasOps *o)
|
static DisasJumpType op_divs64(DisasContext *s, DisasOps *o)
|
||||||
{
|
{
|
||||||
gen_helper_divs64(o->out2, cpu_env, o->in1, o->in2);
|
TCGv_i128 t = tcg_temp_new_i128();
|
||||||
return_low128(o->out);
|
|
||||||
|
gen_helper_divs64(t, cpu_env, o->in1, o->in2);
|
||||||
|
tcg_gen_extr_i128_i64(o->out2, o->out, t);
|
||||||
|
tcg_temp_free_i128(t);
|
||||||
return DISAS_NEXT;
|
return DISAS_NEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DisasJumpType op_divu64(DisasContext *s, DisasOps *o)
|
static DisasJumpType op_divu64(DisasContext *s, DisasOps *o)
|
||||||
{
|
{
|
||||||
gen_helper_divu64(o->out2, cpu_env, o->out, o->out2, o->in2);
|
TCGv_i128 t = tcg_temp_new_i128();
|
||||||
return_low128(o->out);
|
|
||||||
|
gen_helper_divu64(t, cpu_env, o->out, o->out2, o->in2);
|
||||||
|
tcg_gen_extr_i128_i64(o->out2, o->out, t);
|
||||||
|
tcg_temp_free_i128(t);
|
||||||
return DISAS_NEXT;
|
return DISAS_NEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,43 @@ static void test_dlr(void)
|
||||||
assert(r == 1);
|
assert(r == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_dsgr(void)
|
||||||
|
{
|
||||||
|
register int64_t r0 asm("r0") = -1;
|
||||||
|
register int64_t r1 asm("r1") = -4241;
|
||||||
|
int64_t b = 101, q, r;
|
||||||
|
|
||||||
|
asm("dsgr %[r0],%[b]"
|
||||||
|
: [r0] "+r" (r0), [r1] "+r" (r1)
|
||||||
|
: [b] "r" (b)
|
||||||
|
: "cc");
|
||||||
|
q = r1;
|
||||||
|
r = r0;
|
||||||
|
assert(q == -41);
|
||||||
|
assert(r == -100);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_dlgr(void)
|
||||||
|
{
|
||||||
|
register uint64_t r0 asm("r0") = 0;
|
||||||
|
register uint64_t r1 asm("r1") = 4243;
|
||||||
|
uint64_t b = 101, q, r;
|
||||||
|
|
||||||
|
asm("dlgr %[r0],%[b]"
|
||||||
|
: [r0] "+r" (r0), [r1] "+r" (r1)
|
||||||
|
: [b] "r" (b)
|
||||||
|
: "cc");
|
||||||
|
q = r1;
|
||||||
|
r = r0;
|
||||||
|
assert(q == 42);
|
||||||
|
assert(r == 1);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
test_dr();
|
test_dr();
|
||||||
test_dlr();
|
test_dlr();
|
||||||
|
test_dsgr();
|
||||||
|
test_dlgr();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue