@@ -150,7 +150,6 @@ enum {
enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
CC_OP_FLAGS, /* all cc are back in cc_*_[NZCV] registers */
- CC_OP_DIV, /* modify N, Z and V, C = 0*/
CC_OP_ADD, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_ADDX, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_TADD, /* modify all flags, CC_DST = res, CC_SRC = src1 */
@@ -27,9 +27,9 @@ DEF_HELPER_FLAGS_2(tick_set_limit, TCG_CALL_NO_RWG, void, ptr, i64)
DEF_HELPER_1(debug, void, env)
DEF_HELPER_1(save, void, env)
DEF_HELPER_1(restore, void, env)
-DEF_HELPER_3(udiv, tl, env, tl, tl)
+DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_WG, tl, env, tl, tl)
+DEF_HELPER_FLAGS_3(sdiv, TCG_CALL_NO_WG, tl, env, tl, tl)
DEF_HELPER_3(udiv_cc, tl, env, tl, tl)
-DEF_HELPER_3(sdiv, tl, env, tl, tl)
DEF_HELPER_3(sdiv_cc, tl, env, tl, tl)
DEF_HELPER_3(taddcctv, tl, env, tl, tl)
DEF_HELPER_3(tsubcctv, tl, env, tl, tl)
@@ -47,30 +47,6 @@ static inline uint32_t get_NZ_xcc(target_long dst)
}
#endif
-static inline uint32_t get_V_div_icc(target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (src2 != 0) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_div(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_V_div_icc(CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_div(CPUSPARCState *env)
-{
- return 0;
-}
-
static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
{
uint32_t ret = 0;
@@ -402,7 +378,6 @@ typedef struct CCTable {
static const CCTable icc_table[CC_OP_NB] = {
/* CC_OP_DYNAMIC should never happen */
- [CC_OP_DIV] = { compute_all_div, compute_C_div },
[CC_OP_ADD] = { compute_all_add, compute_C_add },
[CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
[CC_OP_TADD] = { compute_all_tadd, compute_C_add },
@@ -417,7 +392,6 @@ static const CCTable icc_table[CC_OP_NB] = {
#ifdef TARGET_SPARC64
static const CCTable xcc_table[CC_OP_NB] = {
/* CC_OP_DYNAMIC should never happen */
- [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
[CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
[CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
[CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
@@ -84,29 +84,32 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
static target_ulong do_udiv(CPUSPARCState *env, target_ulong a,
target_ulong b, int cc, uintptr_t ra)
{
- int overflow = 0;
- uint64_t x0;
- uint32_t x1;
-
- x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
- x1 = (b & 0xffffffff);
+ target_ulong v, r;
+ uint64_t x0 = (uint32_t)a | ((uint64_t)env->y << 32);
+ uint32_t x1 = b;
if (x1 == 0) {
cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
}
x0 = x0 / x1;
- if (x0 > UINT32_MAX) {
- x0 = UINT32_MAX;
- overflow = 1;
+ r = x0;
+ v = 0;
+ if (unlikely(x0 > UINT32_MAX)) {
+ v = r = UINT32_MAX;
}
if (cc) {
- env->cc_dst = x0;
- env->cc_src2 = overflow;
- env->cc_op = CC_OP_DIV;
+ env->cc_N = r;
+ env->cc_V = v;
+ env->cc_icc_Z = r;
+ env->cc_icc_C = 0;
+#ifdef TARGET_SPARC64
+ env->cc_xcc_Z = r;
+ env->cc_xcc_C = 0;
+#endif
}
- return x0;
+ return r;
}
target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
@@ -122,32 +125,46 @@ target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
static target_ulong do_sdiv(CPUSPARCState *env, target_ulong a,
target_ulong b, int cc, uintptr_t ra)
{
- int overflow = 0;
- int64_t x0;
- int32_t x1;
-
- x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
- x1 = (b & 0xffffffff);
+ target_ulong v;
+ target_long r;
+ int64_t x0 = (uint32_t)a | ((uint64_t)env->y << 32);
+ int32_t x1 = b;
if (x1 == 0) {
cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
- } else if (x1 == -1 && x0 == INT64_MIN) {
- x0 = INT32_MAX;
- overflow = 1;
+ }
+ if (unlikely(x0 == INT64_MIN)) {
+ /*
+ * Special case INT64_MIN / -1 is required to avoid trap on x86 host.
+ * However, with a dividend of INT64_MIN, there is no 32-bit divisor
+ * which can yield a 32-bit result:
+ * INT64_MIN / INT32_MIN = 0x1_0000_0000
+ * INT64_MIN / INT32_MAX = -0x1_0000_0002
+ * Therefore we know we must overflow and saturate.
+ */
+ r = x1 < 0 ? INT32_MAX : INT32_MIN;
+ v = UINT32_MAX;
} else {
x0 = x0 / x1;
- if ((int32_t) x0 != x0) {
- x0 = x0 < 0 ? INT32_MIN : INT32_MAX;
- overflow = 1;
+ r = (int32_t)x0;
+ v = 0;
+ if (unlikely(r != x0)) {
+ r = x0 < 0 ? INT32_MIN : INT32_MAX;
+ v = UINT32_MAX;
}
}
if (cc) {
- env->cc_dst = x0;
- env->cc_src2 = overflow;
- env->cc_op = CC_OP_DIV;
+ env->cc_N = r;
+ env->cc_V = v;
+ env->cc_icc_Z = r;
+ env->cc_icc_C = 0;
+#ifdef TARGET_SPARC64
+ env->cc_xcc_Z = r;
+ env->cc_xcc_C = 0;
+#endif
}
- return x0;
+ return r;
}
target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
@@ -437,7 +437,6 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
TCGv carry;
switch (dc->cc_op) {
- case CC_OP_DIV:
case CC_OP_LOGIC:
/* Carry is known to be zero. Fall back to plain ADD. */
if (update_cc) {
@@ -510,7 +509,6 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
TCGv carry;
switch (dc->cc_op) {
- case CC_OP_DIV:
case CC_OP_LOGIC:
/* Carry is known to be zero. Fall back to plain SUB. */
if (update_cc) {
@@ -3759,7 +3757,7 @@ static bool do_flags_arith(DisasContext *dc, arg_r_r_ri *a, int cc_op,
void (*func)(TCGv, TCGv, TCGv))
{
if (do_arith(dc, a, func, NULL)) {
- /* Assume FUNC has set env->cc_op and all cc_foo variables. */
+ tcg_gen_movi_i32(cpu_cc_op, cc_op);
dc->cc_op = cc_op;
return true;
}
@@ -3816,8 +3814,8 @@ TRANS(ORNcc, ALL, do_cc_arith, a, CC_OP_LOGIC, tcg_gen_orc_tl, NULL)
TRANS(XORNcc, ALL, do_cc_arith, a, CC_OP_LOGIC, tcg_gen_eqv_tl, NULL)
TRANS(UMULcc, MUL, do_cc_arith, a, CC_OP_LOGIC, gen_op_umul, NULL)
TRANS(SMULcc, MUL, do_cc_arith, a, CC_OP_LOGIC, gen_op_smul, NULL)
-TRANS(UDIVcc, DIV, do_flags_arith, a, CC_OP_DIV, gen_op_udivcc)
-TRANS(SDIVcc, DIV, do_flags_arith, a, CC_OP_DIV, gen_op_sdivcc)
+TRANS(UDIVcc, DIV, do_flags_arith, a, CC_OP_FLAGS, gen_op_udivcc)
+TRANS(SDIVcc, DIV, do_flags_arith, a, CC_OP_FLAGS, gen_op_sdivcc)
TRANS(TADDcc, ALL, do_cc_arith, a, CC_OP_TADD, gen_op_add_cc, NULL)
TRANS(TSUBcc, ALL, do_cc_arith, a, CC_OP_TSUB, gen_op_sub_cc, NULL)
TRANS(TADDccTV, ALL, do_flags_arith, a, CC_OP_TADDTV, gen_op_taddcctv)
Return both result and overflow from helper_[us]div. Compute all flags explicitly in gen_op_[us]divcc. Marginally improve the INT64_MIN special case in do_sdiv. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/sparc/cpu.h | 1 - target/sparc/helper.h | 4 +-- target/sparc/cc_helper.c | 26 -------------- target/sparc/helper.c | 75 ++++++++++++++++++++++++---------------- target/sparc/translate.c | 8 ++--- 5 files changed, 51 insertions(+), 63 deletions(-)