target-alpha: Fix integer overflow checking insns

We need to write the result to the destination register before
raising any exception.  Thus inline the code for each insn, and
check for any exception after we're done.

Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2014-07-03 13:18:26 -07:00
parent 7b4dde839e
commit 4d1628e832
3 changed files with 56 additions and 70 deletions

View File

@ -1,12 +1,7 @@
DEF_HELPER_3(excp, noreturn, env, int, int) DEF_HELPER_3(excp, noreturn, env, int, int)
DEF_HELPER_FLAGS_1(load_pcc, TCG_CALL_NO_RWG_SE, i64, env) DEF_HELPER_FLAGS_1(load_pcc, TCG_CALL_NO_RWG_SE, i64, env)
DEF_HELPER_FLAGS_3(addqv, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(check_overflow, TCG_CALL_NO_WG, void, env, i64, i64)
DEF_HELPER_FLAGS_3(addlv, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(subqv, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(sublv, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(mullv, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(mulqv, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_FLAGS_1(ctlz, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_1(ctlz, TCG_CALL_NO_RWG_SE, i64, i64)

View File

@ -249,64 +249,9 @@ uint64_t helper_unpkbw(uint64_t op1)
| ((op1 & 0xff000000) << 24)); | ((op1 & 0xff000000) << 24));
} }
uint64_t helper_addqv(CPUAlphaState *env, uint64_t op1, uint64_t op2) void helper_check_overflow(CPUAlphaState *env, uint64_t op1, uint64_t op2)
{ {
uint64_t tmp = op1; if (unlikely(op1 != op2)) {
op1 += op2;
if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
arith_excp(env, GETPC(), EXC_M_IOV, 0); arith_excp(env, GETPC(), EXC_M_IOV, 0);
} }
return op1;
}
uint64_t helper_addlv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
{
uint64_t tmp = op1;
op1 = (uint32_t)(op1 + op2);
if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
arith_excp(env, GETPC(), EXC_M_IOV, 0);
}
return op1;
}
uint64_t helper_subqv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
{
uint64_t res;
res = op1 - op2;
if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
arith_excp(env, GETPC(), EXC_M_IOV, 0);
}
return res;
}
uint64_t helper_sublv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
{
uint32_t res;
res = op1 - op2;
if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
arith_excp(env, GETPC(), EXC_M_IOV, 0);
}
return res;
}
uint64_t helper_mullv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
{
int64_t res = (int64_t)op1 * (int64_t)op2;
if (unlikely((int32_t)res != res)) {
arith_excp(env, GETPC(), EXC_M_IOV, 0);
}
return (int64_t)((int32_t)res);
}
uint64_t helper_mulqv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
{
uint64_t tl, th;
muls64(&tl, &th, op1, op2);
/* If th != 0 && th != -1, then we had an overflow */
if (unlikely((th + 1) > 1)) {
arith_excp(env, GETPC(), EXC_M_IOV, 0);
}
return tl;
} }

View File

@ -1362,7 +1362,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
uint16_t fn11; uint16_t fn11;
uint8_t opc, ra, rb, rc, fpfn, fn7, lit; uint8_t opc, ra, rb, rc, fpfn, fn7, lit;
bool islit; bool islit;
TCGv va, vb, vc, tmp; TCGv va, vb, vc, tmp, tmp2;
TCGv_i32 t32; TCGv_i32 t32;
ExitStatus ret; ExitStatus ret;
@ -1574,11 +1574,23 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break; break;
case 0x40: case 0x40:
/* ADDL/V */ /* ADDL/V */
gen_helper_addlv(vc, cpu_env, va, vb); tmp = tcg_temp_new();
tcg_gen_ext32s_i64(tmp, va);
tcg_gen_ext32s_i64(vc, vb);
tcg_gen_add_i64(tmp, tmp, vc);
tcg_gen_ext32s_i64(vc, tmp);
gen_helper_check_overflow(cpu_env, vc, tmp);
tcg_temp_free(tmp);
break; break;
case 0x49: case 0x49:
/* SUBL/V */ /* SUBL/V */
gen_helper_sublv(vc, cpu_env, va, vb); tmp = tcg_temp_new();
tcg_gen_ext32s_i64(tmp, va);
tcg_gen_ext32s_i64(vc, vb);
tcg_gen_sub_i64(tmp, tmp, vc);
tcg_gen_ext32s_i64(vc, tmp);
gen_helper_check_overflow(cpu_env, vc, tmp);
tcg_temp_free(tmp);
break; break;
case 0x4D: case 0x4D:
/* CMPLT */ /* CMPLT */
@ -1586,11 +1598,33 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break; break;
case 0x60: case 0x60:
/* ADDQ/V */ /* ADDQ/V */
gen_helper_addqv(vc, cpu_env, va, vb); tmp = tcg_temp_new();
tmp2 = tcg_temp_new();
tcg_gen_eqv_i64(tmp, va, vb);
tcg_gen_mov_i64(tmp2, va);
tcg_gen_add_i64(vc, va, vb);
tcg_gen_xor_i64(tmp2, tmp2, vc);
tcg_gen_and_i64(tmp, tmp, tmp2);
tcg_gen_shri_i64(tmp, tmp, 63);
tcg_gen_movi_i64(tmp2, 0);
gen_helper_check_overflow(cpu_env, tmp, tmp2);
tcg_temp_free(tmp);
tcg_temp_free(tmp2);
break; break;
case 0x69: case 0x69:
/* SUBQ/V */ /* SUBQ/V */
gen_helper_subqv(vc, cpu_env, va, vb); tmp = tcg_temp_new();
tmp2 = tcg_temp_new();
tcg_gen_xor_i64(tmp, va, vb);
tcg_gen_mov_i64(tmp2, va);
tcg_gen_sub_i64(vc, va, vb);
tcg_gen_xor_i64(tmp2, tmp2, vc);
tcg_gen_and_i64(tmp, tmp, tmp2);
tcg_gen_shri_i64(tmp, tmp, 63);
tcg_gen_movi_i64(tmp2, 0);
gen_helper_check_overflow(cpu_env, tmp, tmp2);
tcg_temp_free(tmp);
tcg_temp_free(tmp2);
break; break;
case 0x6D: case 0x6D:
/* CMPLE */ /* CMPLE */
@ -1885,11 +1919,23 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break; break;
case 0x40: case 0x40:
/* MULL/V */ /* MULL/V */
gen_helper_mullv(vc, cpu_env, va, vb); tmp = tcg_temp_new();
tcg_gen_ext32s_i64(tmp, va);
tcg_gen_ext32s_i64(vc, vb);
tcg_gen_mul_i64(tmp, tmp, vc);
tcg_gen_ext32s_i64(vc, tmp);
gen_helper_check_overflow(cpu_env, vc, tmp);
tcg_temp_free(tmp);
break; break;
case 0x60: case 0x60:
/* MULQ/V */ /* MULQ/V */
gen_helper_mulqv(vc, cpu_env, va, vb); tmp = tcg_temp_new();
tmp2 = tcg_temp_new();
tcg_gen_muls2_i64(vc, tmp, va, vb);
tcg_gen_sari_i64(tmp2, vc, 63);
gen_helper_check_overflow(cpu_env, tmp, tmp2);
tcg_temp_free(tmp);
tcg_temp_free(tmp2);
break; break;
default: default:
goto invalid_opc; goto invalid_opc;