Skip to content

Commit 1326010

Browse files
committed
target/sparc: Remove CC_OP_DIV
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 helper_sdiv. Tested-by: Mark Cave-Ayland <[email protected]> Acked-by: Mark Cave-Ayland <[email protected]> Signed-off-by: Richard Henderson <[email protected]>
1 parent 2a45b73 commit 1326010

File tree

5 files changed

+93
-110
lines changed

5 files changed

+93
-110
lines changed

target/sparc/cc_helper.c

-33
Original file line numberDiff line numberDiff line change
@@ -47,30 +47,6 @@ static inline uint32_t get_NZ_xcc(target_long dst)
4747
}
4848
#endif
4949

50-
static inline uint32_t get_V_div_icc(target_ulong src2)
51-
{
52-
uint32_t ret = 0;
53-
54-
if (src2 != 0) {
55-
ret = PSR_OVF;
56-
}
57-
return ret;
58-
}
59-
60-
static uint32_t compute_all_div(CPUSPARCState *env)
61-
{
62-
uint32_t ret;
63-
64-
ret = get_NZ_icc(CC_DST);
65-
ret |= get_V_div_icc(CC_SRC2);
66-
return ret;
67-
}
68-
69-
static uint32_t compute_C_div(CPUSPARCState *env)
70-
{
71-
return 0;
72-
}
73-
7450
static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
7551
{
7652
uint32_t ret = 0;
@@ -378,21 +354,13 @@ static uint32_t compute_all_tsubtv(CPUSPARCState *env)
378354
return ret;
379355
}
380356

381-
#ifdef TARGET_SPARC64
382-
static uint32_t compute_all_logic_xcc(CPUSPARCState *env)
383-
{
384-
return get_NZ_xcc(CC_DST);
385-
}
386-
#endif
387-
388357
typedef struct CCTable {
389358
uint32_t (*compute_all)(CPUSPARCState *env); /* return all the flags */
390359
uint32_t (*compute_c)(CPUSPARCState *env); /* return the C flag */
391360
} CCTable;
392361

393362
static const CCTable icc_table[CC_OP_NB] = {
394363
/* CC_OP_DYNAMIC should never happen */
395-
[CC_OP_DIV] = { compute_all_div, compute_C_div },
396364
[CC_OP_ADD] = { compute_all_add, compute_C_add },
397365
[CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
398366
[CC_OP_TADD] = { compute_all_tadd, compute_C_add },
@@ -406,7 +374,6 @@ static const CCTable icc_table[CC_OP_NB] = {
406374
#ifdef TARGET_SPARC64
407375
static const CCTable xcc_table[CC_OP_NB] = {
408376
/* CC_OP_DYNAMIC should never happen */
409-
[CC_OP_DIV] = { compute_all_logic_xcc, compute_C_div },
410377
[CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
411378
[CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
412379
[CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },

target/sparc/cpu.h

-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ enum {
150150
enum {
151151
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
152152
CC_OP_FLAGS, /* all cc are back in cc_*_[NZCV] registers */
153-
CC_OP_DIV, /* modify N, Z and V, C = 0*/
154153
CC_OP_ADD, /* modify all flags, CC_DST = res, CC_SRC = src1 */
155154
CC_OP_ADDX, /* modify all flags, CC_DST = res, CC_SRC = src1 */
156155
CC_OP_TADD, /* modify all flags, CC_DST = res, CC_SRC = src1 */

target/sparc/helper.c

+33-60
Original file line numberDiff line numberDiff line change
@@ -81,79 +81,52 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
8181
}
8282
#endif
8383

84-
static target_ulong do_udiv(CPUSPARCState *env, target_ulong a,
85-
target_ulong b, int cc, uintptr_t ra)
84+
uint64_t helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
8685
{
87-
int overflow = 0;
88-
uint64_t x0;
89-
uint32_t x1;
86+
uint64_t a64 = (uint32_t)a | ((uint64_t)env->y << 32);
87+
uint32_t b32 = b;
88+
uint32_t r;
9089

91-
x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
92-
x1 = (b & 0xffffffff);
93-
94-
if (x1 == 0) {
95-
cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
96-
}
97-
98-
x0 = x0 / x1;
99-
if (x0 > UINT32_MAX) {
100-
x0 = UINT32_MAX;
101-
overflow = 1;
90+
if (b32 == 0) {
91+
cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
10292
}
10393

104-
if (cc) {
105-
env->cc_src2 = overflow;
94+
a64 /= b32;
95+
r = a64;
96+
if (unlikely(a64 > UINT32_MAX)) {
97+
return -1; /* r = UINT32_MAX, v = 1 */
10698
}
107-
return x0;
99+
return r;
108100
}
109101

110-
target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
102+
uint64_t helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
111103
{
112-
return do_udiv(env, a, b, 0, GETPC());
113-
}
104+
int64_t a64 = (uint32_t)a | ((uint64_t)env->y << 32);
105+
int32_t b32 = b;
106+
int32_t r;
114107

115-
target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
116-
{
117-
return do_udiv(env, a, b, 1, GETPC());
118-
}
119-
120-
static target_ulong do_sdiv(CPUSPARCState *env, target_ulong a,
121-
target_ulong b, int cc, uintptr_t ra)
122-
{
123-
int overflow = 0;
124-
int64_t x0;
125-
int32_t x1;
126-
127-
x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
128-
x1 = (b & 0xffffffff);
129-
130-
if (x1 == 0) {
131-
cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
132-
} else if (x1 == -1 && x0 == INT64_MIN) {
133-
x0 = INT32_MAX;
134-
overflow = 1;
135-
} else {
136-
x0 = x0 / x1;
137-
if ((int32_t) x0 != x0) {
138-
x0 = x0 < 0 ? INT32_MIN : INT32_MAX;
139-
overflow = 1;
140-
}
108+
if (b32 == 0) {
109+
cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
141110
}
142111

143-
if (cc) {
144-
env->cc_src2 = overflow;
112+
if (unlikely(a64 == INT64_MIN)) {
113+
/*
114+
* Special case INT64_MIN / -1 is required to avoid trap on x86 host.
115+
* However, with a dividend of INT64_MIN, there is no 32-bit divisor
116+
* which can yield a 32-bit result:
117+
* INT64_MIN / INT32_MIN = 0x1_0000_0000
118+
* INT64_MIN / INT32_MAX = -0x1_0000_0002
119+
* Therefore we know we must overflow and saturate.
120+
*/
121+
return (uint32_t)(b32 < 0 ? INT32_MAX : INT32_MIN) | (-1ull << 32);
145122
}
146-
return x0;
147-
}
148-
149-
target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
150-
{
151-
return do_sdiv(env, a, b, 0, GETPC());
152-
}
153123

154-
target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
155-
{
156-
return do_sdiv(env, a, b, 1, GETPC());
124+
a64 /= b;
125+
r = a64;
126+
if (unlikely(r != a64)) {
127+
return (uint32_t)(a64 < 0 ? INT32_MIN : INT32_MAX) | (-1ull << 32);
128+
}
129+
return (uint32_t)r;
157130
}
158131

159132
#ifdef TARGET_SPARC64

target/sparc/helper.h

+2-4
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,8 @@ DEF_HELPER_FLAGS_2(tick_set_limit, TCG_CALL_NO_RWG, void, ptr, i64)
2727
DEF_HELPER_1(debug, void, env)
2828
DEF_HELPER_1(save, void, env)
2929
DEF_HELPER_1(restore, void, env)
30-
DEF_HELPER_3(udiv, tl, env, tl, tl)
31-
DEF_HELPER_3(udiv_cc, tl, env, tl, tl)
32-
DEF_HELPER_3(sdiv, tl, env, tl, tl)
33-
DEF_HELPER_3(sdiv_cc, tl, env, tl, tl)
30+
DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_WG, i64, env, tl, tl)
31+
DEF_HELPER_FLAGS_3(sdiv, TCG_CALL_NO_WG, i64, env, tl, tl)
3432
DEF_HELPER_3(taddcctv, tl, env, tl, tl)
3533
DEF_HELPER_3(tsubcctv, tl, env, tl, tl)
3634
#ifdef TARGET_SPARC64

target/sparc/translate.c

+58-12
Original file line numberDiff line numberDiff line change
@@ -693,22 +693,76 @@ static void gen_op_sdivx(TCGv dst, TCGv src1, TCGv src2)
693693

694694
static void gen_op_udiv(TCGv dst, TCGv src1, TCGv src2)
695695
{
696+
#ifdef TARGET_SPARC64
696697
gen_helper_udiv(dst, tcg_env, src1, src2);
698+
tcg_gen_ext32u_tl(dst, dst);
699+
#else
700+
TCGv_i64 t64 = tcg_temp_new_i64();
701+
gen_helper_udiv(t64, tcg_env, src1, src2);
702+
tcg_gen_trunc_i64_tl(dst, t64);
703+
#endif
697704
}
698705

699706
static void gen_op_sdiv(TCGv dst, TCGv src1, TCGv src2)
700707
{
708+
#ifdef TARGET_SPARC64
701709
gen_helper_sdiv(dst, tcg_env, src1, src2);
710+
tcg_gen_ext32s_tl(dst, dst);
711+
#else
712+
TCGv_i64 t64 = tcg_temp_new_i64();
713+
gen_helper_sdiv(t64, tcg_env, src1, src2);
714+
tcg_gen_trunc_i64_tl(dst, t64);
715+
#endif
702716
}
703717

704718
static void gen_op_udivcc(TCGv dst, TCGv src1, TCGv src2)
705719
{
706-
gen_helper_udiv_cc(dst, tcg_env, src1, src2);
720+
TCGv_i64 t64;
721+
722+
#ifdef TARGET_SPARC64
723+
t64 = cpu_cc_V;
724+
#else
725+
t64 = tcg_temp_new_i64();
726+
#endif
727+
728+
gen_helper_udiv(t64, tcg_env, src1, src2);
729+
730+
#ifdef TARGET_SPARC64
731+
tcg_gen_ext32u_tl(cpu_cc_N, t64);
732+
tcg_gen_shri_tl(cpu_cc_V, t64, 32);
733+
tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
734+
tcg_gen_movi_tl(cpu_icc_C, 0);
735+
#else
736+
tcg_gen_extr_i64_tl(cpu_cc_N, cpu_cc_V, t64);
737+
#endif
738+
tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
739+
tcg_gen_movi_tl(cpu_cc_C, 0);
740+
tcg_gen_mov_tl(dst, cpu_cc_N);
707741
}
708742

709743
static void gen_op_sdivcc(TCGv dst, TCGv src1, TCGv src2)
710744
{
711-
gen_helper_sdiv_cc(dst, tcg_env, src1, src2);
745+
TCGv_i64 t64;
746+
747+
#ifdef TARGET_SPARC64
748+
t64 = cpu_cc_V;
749+
#else
750+
t64 = tcg_temp_new_i64();
751+
#endif
752+
753+
gen_helper_sdiv(t64, tcg_env, src1, src2);
754+
755+
#ifdef TARGET_SPARC64
756+
tcg_gen_ext32s_tl(cpu_cc_N, t64);
757+
tcg_gen_shri_tl(cpu_cc_V, t64, 32);
758+
tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
759+
tcg_gen_movi_tl(cpu_icc_C, 0);
760+
#else
761+
tcg_gen_extr_i64_tl(cpu_cc_N, cpu_cc_V, t64);
762+
#endif
763+
tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
764+
tcg_gen_movi_tl(cpu_cc_C, 0);
765+
tcg_gen_mov_tl(dst, cpu_cc_N);
712766
}
713767

714768
static void gen_op_taddcctv(TCGv dst, TCGv src1, TCGv src2)
@@ -3717,8 +3771,8 @@ TRANS(SMUL, MUL, do_logic, a, gen_op_smul, NULL)
37173771

37183772
TRANS(UDIVX, 64, do_arith, a, -1, gen_op_udivx, NULL, NULL)
37193773
TRANS(SDIVX, 64, do_arith, a, -1, gen_op_sdivx, NULL, NULL)
3720-
TRANS(UDIV, DIV, do_arith, a, CC_OP_DIV, gen_op_udiv, NULL, gen_op_udivcc)
3721-
TRANS(SDIV, DIV, do_arith, a, CC_OP_DIV, gen_op_sdiv, NULL, gen_op_sdivcc)
3774+
TRANS(UDIV, DIV, do_arith, a, CC_OP_FLAGS, gen_op_udiv, NULL, gen_op_udivcc)
3775+
TRANS(SDIV, DIV, do_arith, a, CC_OP_FLAGS, gen_op_sdiv, NULL, gen_op_sdivcc)
37223776

37233777
/* TODO: Should have feature bit -- comes in with UltraSparc T2. */
37243778
TRANS(POPC, 64, do_arith, a, -1, gen_op_popc, NULL, NULL)
@@ -3743,10 +3797,6 @@ static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a)
37433797
static bool trans_ADDC(DisasContext *dc, arg_r_r_ri_cc *a)
37443798
{
37453799
switch (dc->cc_op) {
3746-
case CC_OP_DIV:
3747-
/* Carry is known to be zero. Fall back to plain ADD. */
3748-
return do_arith(dc, a, CC_OP_ADD,
3749-
tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_add_cc);
37503800
case CC_OP_ADD:
37513801
case CC_OP_TADD:
37523802
case CC_OP_TADDTV:
@@ -3766,10 +3816,6 @@ static bool trans_ADDC(DisasContext *dc, arg_r_r_ri_cc *a)
37663816
static bool trans_SUBC(DisasContext *dc, arg_r_r_ri_cc *a)
37673817
{
37683818
switch (dc->cc_op) {
3769-
case CC_OP_DIV:
3770-
/* Carry is known to be zero. Fall back to plain SUB. */
3771-
return do_arith(dc, a, CC_OP_SUB,
3772-
tcg_gen_sub_tl, tcg_gen_subi_tl, gen_op_sub_cc);
37733819
case CC_OP_ADD:
37743820
case CC_OP_TADD:
37753821
case CC_OP_TADDTV:

0 commit comments

Comments
 (0)