* [PATCH 00/20] target/sparc: Cleanup condition codes etc
@ 2023-10-17 6:40 Richard Henderson
2023-10-17 6:40 ` [PATCH 01/20] target/sparc: Introduce cpu_put_psr_icc Richard Henderson
` (19 more replies)
0 siblings, 20 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:40 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
This was part of my guess for some of the performance problems.
I saw compute_all_sub quite high in the profile at some point,
and I believe that the test case has a partially rotated loop
such that "cmp" is in a delay slot, and so the gen_compare fast
path for CC_OP_SUB is not visible to the conditional branch
that uses the output of the compare. Which means that
helper_compute_psr gets called much more often that we'd like.
Move away from CC_OP to explicit computation of conditions.
This is modeled on target/arm for the (mostly) separate
representation of the bits. We can pack icc.[NV] and xcc.[NV]
into the same target_ulong, but Z and C cannot share.
After removing CC_OP, clean up the handling of conditions so
that we can minimize additional setcond required for env->cond.
Finally, inline some division, which can make use of the new
out-of-line exception path, which means we can expand UDIVX
and SDIVX with very few host insns. The 64/32 UDIV insn needs
only a few more. Leave UDIVcc and SDIV* out of line, as the
overflow and saturation computation in these cases is really
too large to inline.
r~
Based-on: 20231017061244.681584-1-richard.henderson@linaro.org
("[PATCH v2 00/90] target/sparc: Convert to decodetree")
Richard Henderson (20):
target/sparc: Introduce cpu_put_psr_icc
target/sparc: Split psr and xcc into components
target/sparc: Remove CC_OP_DIV
target/sparc: Remove CC_OP_LOGIC
target/sparc: Remove CC_OP_ADD, CC_OP_ADDX, CC_OP_TADD
target/sparc: Remove CC_OP_SUB, CC_OP_SUBX, CC_OP_TSUB
target/sparc: Remove CC_OP_TADDTV, CC_OP_TSUBTV
target/sparc: Remove CC_OP leftovers
target/sparc: Remove DisasCompare.is_bool
target/sparc: Change DisasCompare.c2 to int
target/sparc: Always copy conditions into a new temporary
target/sparc: Do flush_cond in advance_jump_cond
target/sparc: Merge gen_branch2 into advance_pc
target/sparc: Merge advance_jump_uncond_{never,always} into
advance_jump_cond
target/sparc: Use DISAS_EXIT in do_wrpsr
target/sparc: Merge gen_op_next_insn into only caller
target/sparc: Record entire jump condition in DisasContext
target/sparc: Discard cpu_cond at the end of each insn
target/sparc: Implement UDIVX and SDIVX inline
target/sparc: Implement UDIV inline
linux-user/sparc/target_cpu.h | 4 +-
target/sparc/cpu.h | 58 +-
target/sparc/helper.h | 9 +-
linux-user/sparc/cpu_loop.c | 23 +-
linux-user/sparc/signal.c | 2 +-
target/sparc/cc_helper.c | 471 -------------
target/sparc/cpu.c | 1 -
target/sparc/helper.c | 156 ++---
target/sparc/int32_helper.c | 5 -
target/sparc/int64_helper.c | 5 -
target/sparc/machine.c | 44 +-
target/sparc/translate.c | 1225 ++++++++++++++-------------------
target/sparc/win_helper.c | 55 +-
target/sparc/meson.build | 1 -
14 files changed, 724 insertions(+), 1335 deletions(-)
delete mode 100644 target/sparc/cc_helper.c
--
2.34.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 01/20] target/sparc: Introduce cpu_put_psr_icc
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
@ 2023-10-17 6:40 ` Richard Henderson
2023-10-19 14:11 ` Philippe Mathieu-Daudé
2023-10-17 6:40 ` [PATCH 02/20] target/sparc: Split psr and xcc into components Richard Henderson
` (18 subsequent siblings)
19 siblings, 1 reply; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:40 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Isolate linux-user from changes to icc representation.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/cpu.h | 1 +
linux-user/sparc/signal.c | 2 +-
target/sparc/win_helper.c | 7 ++++++-
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 758a4e8aaa..955329f6c9 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -619,6 +619,7 @@ void sparc_restore_state_to_opc(CPUState *cs,
/* win_helper.c */
target_ulong cpu_get_psr(CPUSPARCState *env1);
void cpu_put_psr(CPUSPARCState *env1, target_ulong val);
+void cpu_put_psr_icc(CPUSPARCState *env1, target_ulong val);
void cpu_put_psr_raw(CPUSPARCState *env1, target_ulong val);
#ifdef TARGET_SPARC64
void cpu_change_pstate(CPUSPARCState *env1, uint32_t new_pstate);
diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
index 2be9000b9e..dfcae707e0 100644
--- a/linux-user/sparc/signal.c
+++ b/linux-user/sparc/signal.c
@@ -164,7 +164,7 @@ static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
*/
uint32_t psr;
__get_user(psr, ®s->psr);
- env->psr = (psr & PSR_ICC) | (env->psr & ~PSR_ICC);
+ cpu_put_psr_icc(env, psr);
#endif
/* Note that pc and npc are handled in the caller. */
diff --git a/target/sparc/win_helper.c b/target/sparc/win_helper.c
index 3a7c0ff943..bf2c90c780 100644
--- a/target/sparc/win_helper.c
+++ b/target/sparc/win_helper.c
@@ -67,9 +67,14 @@ target_ulong cpu_get_psr(CPUSPARCState *env)
#endif
}
-void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val)
+void cpu_put_psr_icc(CPUSPARCState *env, target_ulong val)
{
env->psr = val & PSR_ICC;
+}
+
+void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val)
+{
+ cpu_put_psr_icc(env, val);
#if !defined(TARGET_SPARC64)
env->psref = (val & PSR_EF) ? 1 : 0;
env->psrpil = (val & PSR_PIL) >> 8;
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 02/20] target/sparc: Split psr and xcc into components
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
2023-10-17 6:40 ` [PATCH 01/20] target/sparc: Introduce cpu_put_psr_icc Richard Henderson
@ 2023-10-17 6:40 ` Richard Henderson
2023-10-17 6:40 ` [PATCH 03/20] target/sparc: Remove CC_OP_DIV Richard Henderson
` (17 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:40 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Step in removing CC_OP: change the representation of CC_OP_FLAGS.
The 8 bits are distributed between 6 variables, which should make
it easy to keep up to date.
The code within cc_helper.c is quite ugly but is only temporary.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/sparc/target_cpu.h | 4 +-
target/sparc/cpu.h | 30 ++-
linux-user/sparc/cpu_loop.c | 18 +-
target/sparc/cc_helper.c | 51 +++--
target/sparc/machine.c | 44 ++++-
target/sparc/translate.c | 363 +++++++++++++---------------------
target/sparc/win_helper.c | 51 ++++-
7 files changed, 292 insertions(+), 269 deletions(-)
diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h
index 1f4bed50f4..00a9fab98b 100644
--- a/linux-user/sparc/target_cpu.h
+++ b/linux-user/sparc/target_cpu.h
@@ -59,9 +59,9 @@ static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp,
*/
env->regwptr[WREG_O0] = 0;
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
- env->xcc &= ~PSR_CARRY;
+ env->cc_xcc_C = 0;
#else
- env->psr &= ~PSR_CARRY;
+ env->cc_icc_C = 0;
#endif
env->pc = env->npc;
env->npc = env->npc + 4;
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 955329f6c9..ac93658c33 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -149,7 +149,7 @@ enum {
*/
enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
- CC_OP_FLAGS, /* all cc are back in status register */
+ 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 */
@@ -458,6 +458,32 @@ struct CPUArchState {
target_ulong npc; /* next program counter */
target_ulong y; /* multiply/divide register */
+ /*
+ * Bit 31 is for icc, bit 63 for xcc.
+ * Other bits are garbage.
+ */
+ target_long cc_N;
+ target_long cc_V;
+
+ /*
+ * Z is represented as == 0; any non-zero value is !Z.
+ * For sparc64, the high 32-bits of icc.Z are garbage.
+ */
+ target_ulong cc_icc_Z;
+#ifdef TARGET_SPARC64
+ target_ulong cc_xcc_Z;
+#endif
+
+ /*
+ * For sparc32, icc.C is boolean.
+ * For sparc64, xcc.C is boolean;
+ * icc.C is bit 32 with other bits garbage.
+ */
+ target_ulong cc_icc_C;
+#ifdef TARGET_SPARC64
+ target_ulong cc_xcc_C;
+#endif
+
/* emulator internal flags handling */
target_ulong cc_src, cc_src2;
target_ulong cc_dst;
@@ -466,7 +492,6 @@ struct CPUArchState {
target_ulong cond; /* conditional branch result (XXX: save it in a
temporary register when possible) */
- uint32_t psr; /* processor state register */
target_ulong fsr; /* FPU state register */
CPU_DoubleU fpr[TARGET_DPREGS]; /* floating point registers */
uint32_t cwp; /* index of current register window (extracted
@@ -522,7 +547,6 @@ struct CPUArchState {
#define MAXTL_MAX 8
#define MAXTL_MASK (MAXTL_MAX - 1)
trap_state ts[MAXTL_MAX];
- uint32_t xcc; /* Extended integer condition codes */
uint32_t asi;
uint32_t pstate;
uint32_t tl;
diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c
index b36bb2574b..a2086afada 100644
--- a/linux-user/sparc/cpu_loop.c
+++ b/linux-user/sparc/cpu_loop.c
@@ -197,12 +197,22 @@ static uint32_t do_getpsr(CPUSPARCState *env)
/* Avoid ifdefs below for the abi32 and abi64 paths. */
#ifdef TARGET_ABI32
#define TARGET_TT_SYSCALL (TT_TRAP + 0x10) /* t_linux */
-#define syscall_cc psr
#else
#define TARGET_TT_SYSCALL (TT_TRAP + 0x6d) /* tl0_linux64 */
-#define syscall_cc xcc
#endif
+static void set_syscall_cc(CPUSPARCState *env, bool val)
+{
+#ifndef TARGET_SPARC64
+ env->cc_icc_C = val;
+#elif defined(TARGET_ABI32)
+ env->cc_icc_C = (uint64_t)val << 32;
+#else
+ env->cc_xcc_C = val;
+#endif
+}
+
+
/* Avoid ifdefs below for the v9 and pre-v9 hw traps. */
#ifdef TARGET_SPARC64
#define TARGET_TT_SPILL TT_SPILL
@@ -240,10 +250,10 @@ void cpu_loop (CPUSPARCState *env)
break;
}
if ((abi_ulong)ret >= (abi_ulong)(-515)) {
- env->syscall_cc |= PSR_CARRY;
+ set_syscall_cc(env, 1);
ret = -ret;
} else {
- env->syscall_cc &= ~PSR_CARRY;
+ set_syscall_cc(env, 0);
}
env->regwptr[0] = ret;
/* next instruction */
diff --git a/target/sparc/cc_helper.c b/target/sparc/cc_helper.c
index 7ad5b9b29e..fe4618ad34 100644
--- a/target/sparc/cc_helper.c
+++ b/target/sparc/cc_helper.c
@@ -21,16 +21,6 @@
#include "cpu.h"
#include "exec/helper-proto.h"
-static uint32_t compute_all_flags(CPUSPARCState *env)
-{
- return env->psr & PSR_ICC;
-}
-
-static uint32_t compute_C_flags(CPUSPARCState *env)
-{
- return env->psr & PSR_CARRY;
-}
-
static inline uint32_t get_NZ_icc(int32_t dst)
{
uint32_t ret = 0;
@@ -44,16 +34,6 @@ static inline uint32_t get_NZ_icc(int32_t dst)
}
#ifdef TARGET_SPARC64
-static uint32_t compute_all_flags_xcc(CPUSPARCState *env)
-{
- return env->xcc & PSR_ICC;
-}
-
-static uint32_t compute_C_flags_xcc(CPUSPARCState *env)
-{
- return env->xcc & PSR_CARRY;
-}
-
static inline uint32_t get_NZ_xcc(target_long dst)
{
uint32_t ret = 0;
@@ -422,7 +402,6 @@ typedef struct CCTable {
static const CCTable icc_table[CC_OP_NB] = {
/* CC_OP_DYNAMIC should never happen */
- [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
[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 },
@@ -438,7 +417,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_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
[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 },
@@ -454,18 +432,37 @@ static const CCTable xcc_table[CC_OP_NB] = {
void helper_compute_psr(CPUSPARCState *env)
{
- uint32_t new_psr;
+ if (CC_OP == CC_OP_FLAGS) {
+ return;
+ }
- new_psr = icc_table[CC_OP].compute_all(env);
- env->psr = new_psr;
+ uint32_t icc = icc_table[CC_OP].compute_all(env);
#ifdef TARGET_SPARC64
- new_psr = xcc_table[CC_OP].compute_all(env);
- env->xcc = new_psr;
+ uint32_t xcc = xcc_table[CC_OP].compute_all(env);
+
+ env->cc_N = deposit64(-(icc & PSR_NEG), 32, 32, -(xcc & PSR_NEG));
+ env->cc_V = deposit64(-(icc & PSR_OVF), 32, 32, -(xcc & PSR_OVF));
+ env->cc_icc_C = (uint64_t)icc << (32 - PSR_CARRY_SHIFT);
+ env->cc_xcc_C = (xcc >> PSR_CARRY_SHIFT) & 1;
+ env->cc_xcc_Z = ~xcc & PSR_ZERO;
+#else
+ env->cc_N = -(icc & PSR_NEG);
+ env->cc_V = -(icc & PSR_OVF);
+ env->cc_icc_C = (icc >> PSR_CARRY_SHIFT) & 1;
#endif
+ env->cc_icc_Z = ~icc & PSR_ZERO;
+
CC_OP = CC_OP_FLAGS;
}
uint32_t helper_compute_C_icc(CPUSPARCState *env)
{
+ if (CC_OP == CC_OP_FLAGS) {
+#ifdef TARGET_SPARC64
+ return extract64(env->cc_icc_C, 32, 1);
+#else
+ return env->cc_icc_C;
+#endif
+ }
return icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT;
}
diff --git a/target/sparc/machine.c b/target/sparc/machine.c
index 274e1217df..72f6dc8220 100644
--- a/target/sparc/machine.c
+++ b/target/sparc/machine.c
@@ -83,6 +83,41 @@ static const VMStateInfo vmstate_psr = {
.put = put_psr,
};
+#ifdef TARGET_SPARC64
+static int get_xcc(QEMUFile *f, void *opaque, size_t size,
+ const VMStateField *field)
+{
+ SPARCCPU *cpu = opaque;
+ CPUSPARCState *env = &cpu->env;
+ uint32_t val = qemu_get_be32(f);
+
+ env->cc_N = deposit64(env->cc_N, 32, 32, -(val & PSR_NEG));
+ env->cc_V = deposit64(env->cc_V, 32, 32, -(val & PSR_OVF));
+ env->cc_xcc_Z = ~val & PSR_ZERO;
+ env->cc_xcc_C = (val >> PSR_CARRY_SHIFT) & 1;
+
+ return 0;
+}
+
+static int put_xcc(QEMUFile *f, void *opaque, size_t size,
+ const VMStateField *field, JSONWriter *vmdesc)
+{
+ SPARCCPU *cpu = opaque;
+ CPUSPARCState *env = &cpu->env;
+ uint32_t val = cpu_get_ccr(env);
+
+ /* Extract just xcc out of ccr and shift into legacy position. */
+ qemu_put_be32(f, (val & 0xf0) << (20 - 4));
+ return 0;
+}
+
+static const VMStateInfo vmstate_xcc = {
+ .name = "xcc",
+ .get = get_xcc,
+ .put = put_xcc,
+};
+#endif
+
static int cpu_pre_save(void *opaque)
{
SPARCCPU *cpu = opaque;
@@ -155,7 +190,14 @@ const VMStateDescription vmstate_sparc_cpu = {
VMSTATE_UINT32(env.mmu_version, SPARCCPU),
VMSTATE_STRUCT_ARRAY(env.ts, SPARCCPU, MAXTL_MAX, 0,
vmstate_trap_state, trap_state),
- VMSTATE_UINT32(env.xcc, SPARCCPU),
+ {
+ .name = "xcc",
+ .version_id = 0,
+ .size = sizeof(uint32_t),
+ .info = &vmstate_xcc,
+ .flags = VMS_SINGLE,
+ .offset = 0,
+ },
VMSTATE_UINT32(env.asi, SPARCCPU),
VMSTATE_UINT32(env.pstate, SPARCCPU),
VMSTATE_UINT32(env.tl, SPARCCPU),
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index c458de2103..f2a2d69f91 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -118,20 +118,36 @@ static void gen_helper_array8(TCGv r, TCGv a, TCGv b)
static TCGv_ptr cpu_regwptr;
static TCGv cpu_cc_src, cpu_cc_src2, cpu_cc_dst;
static TCGv_i32 cpu_cc_op;
-static TCGv_i32 cpu_psr;
static TCGv cpu_fsr, cpu_pc, cpu_npc;
static TCGv cpu_regs[32];
static TCGv cpu_y;
static TCGv cpu_tbr;
static TCGv cpu_cond;
+static TCGv cpu_cc_N;
+static TCGv cpu_cc_V;
+static TCGv cpu_icc_Z;
+static TCGv cpu_icc_C;
#ifdef TARGET_SPARC64
-static TCGv_i32 cpu_xcc, cpu_fprs;
+static TCGv cpu_xcc_Z;
+static TCGv cpu_xcc_C;
+static TCGv_i32 cpu_fprs;
static TCGv cpu_gsr;
static TCGv cpu_tick_cmpr, cpu_stick_cmpr, cpu_hstick_cmpr;
static TCGv cpu_hintp, cpu_htba, cpu_hver, cpu_ssr, cpu_ver;
#else
static TCGv cpu_wim;
#endif
+
+#ifdef TARGET_SPARC64
+#define cpu_cc_Z cpu_xcc_Z
+#define cpu_cc_C cpu_xcc_C
+#else
+#define cpu_cc_Z cpu_icc_Z
+#define cpu_cc_C cpu_icc_C
+#define cpu_xcc_Z ({ qemu_build_not_reached(); NULL; })
+#define cpu_xcc_C ({ qemu_build_not_reached(); NULL; })
+#endif
+
/* Floating point registers */
static TCGv_i64 cpu_fpr[TARGET_DPREGS];
@@ -364,31 +380,6 @@ static void gen_goto_tb(DisasContext *s, int tb_num,
}
}
-// XXX suboptimal
-static void gen_mov_reg_N(TCGv reg, TCGv_i32 src)
-{
- tcg_gen_extu_i32_tl(reg, src);
- tcg_gen_extract_tl(reg, reg, PSR_NEG_SHIFT, 1);
-}
-
-static void gen_mov_reg_Z(TCGv reg, TCGv_i32 src)
-{
- tcg_gen_extu_i32_tl(reg, src);
- tcg_gen_extract_tl(reg, reg, PSR_ZERO_SHIFT, 1);
-}
-
-static void gen_mov_reg_V(TCGv reg, TCGv_i32 src)
-{
- tcg_gen_extu_i32_tl(reg, src);
- tcg_gen_extract_tl(reg, reg, PSR_OVF_SHIFT, 1);
-}
-
-static void gen_mov_reg_C(TCGv reg, TCGv_i32 src)
-{
- tcg_gen_extu_i32_tl(reg, src);
- tcg_gen_extract_tl(reg, reg, PSR_CARRY_SHIFT, 1);
-}
-
static void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2)
{
tcg_gen_mov_tl(cpu_cc_src, src1);
@@ -601,13 +592,11 @@ static void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
tcg_gen_deposit_tl(cpu_y, t0, cpu_cc_src, 31, 1);
// b1 = N ^ V;
- gen_mov_reg_N(t0, cpu_psr);
- gen_mov_reg_V(r_temp, cpu_psr);
- tcg_gen_xor_tl(t0, t0, r_temp);
+ tcg_gen_xor_tl(t0, cpu_cc_N, cpu_cc_V);
// T0 = (b1 << 31) | (T0 >> 1);
// src1 = T0;
- tcg_gen_shli_tl(t0, t0, 31);
+ tcg_gen_andi_tl(t0, t0, 1u << 31);
tcg_gen_shri_tl(cpu_cc_src, cpu_cc_src, 1);
tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0);
@@ -779,114 +768,12 @@ static void gen_op_eval_ba(TCGv dst)
tcg_gen_movi_tl(dst, 1);
}
-// Z
-static void gen_op_eval_be(TCGv dst, TCGv_i32 src)
-{
- gen_mov_reg_Z(dst, src);
-}
-
-// Z | (N ^ V)
-static void gen_op_eval_ble(TCGv dst, TCGv_i32 src)
-{
- TCGv t0 = tcg_temp_new();
- gen_mov_reg_N(t0, src);
- gen_mov_reg_V(dst, src);
- tcg_gen_xor_tl(dst, dst, t0);
- gen_mov_reg_Z(t0, src);
- tcg_gen_or_tl(dst, dst, t0);
-}
-
-// N ^ V
-static void gen_op_eval_bl(TCGv dst, TCGv_i32 src)
-{
- TCGv t0 = tcg_temp_new();
- gen_mov_reg_V(t0, src);
- gen_mov_reg_N(dst, src);
- tcg_gen_xor_tl(dst, dst, t0);
-}
-
-// C | Z
-static void gen_op_eval_bleu(TCGv dst, TCGv_i32 src)
-{
- TCGv t0 = tcg_temp_new();
- gen_mov_reg_Z(t0, src);
- gen_mov_reg_C(dst, src);
- tcg_gen_or_tl(dst, dst, t0);
-}
-
-// C
-static void gen_op_eval_bcs(TCGv dst, TCGv_i32 src)
-{
- gen_mov_reg_C(dst, src);
-}
-
-// V
-static void gen_op_eval_bvs(TCGv dst, TCGv_i32 src)
-{
- gen_mov_reg_V(dst, src);
-}
-
// 0
static void gen_op_eval_bn(TCGv dst)
{
tcg_gen_movi_tl(dst, 0);
}
-// N
-static void gen_op_eval_bneg(TCGv dst, TCGv_i32 src)
-{
- gen_mov_reg_N(dst, src);
-}
-
-// !Z
-static void gen_op_eval_bne(TCGv dst, TCGv_i32 src)
-{
- gen_mov_reg_Z(dst, src);
- tcg_gen_xori_tl(dst, dst, 0x1);
-}
-
-// !(Z | (N ^ V))
-static void gen_op_eval_bg(TCGv dst, TCGv_i32 src)
-{
- gen_op_eval_ble(dst, src);
- tcg_gen_xori_tl(dst, dst, 0x1);
-}
-
-// !(N ^ V)
-static void gen_op_eval_bge(TCGv dst, TCGv_i32 src)
-{
- gen_op_eval_bl(dst, src);
- tcg_gen_xori_tl(dst, dst, 0x1);
-}
-
-// !(C | Z)
-static void gen_op_eval_bgu(TCGv dst, TCGv_i32 src)
-{
- gen_op_eval_bleu(dst, src);
- tcg_gen_xori_tl(dst, dst, 0x1);
-}
-
-// !C
-static void gen_op_eval_bcc(TCGv dst, TCGv_i32 src)
-{
- gen_mov_reg_C(dst, src);
- tcg_gen_xori_tl(dst, dst, 0x1);
-}
-
-// !N
-static void gen_op_eval_bpos(TCGv dst, TCGv_i32 src)
-{
- gen_mov_reg_N(dst, src);
- tcg_gen_xori_tl(dst, dst, 0x1);
-}
-
-// !V
-static void gen_op_eval_bvc(TCGv dst, TCGv_i32 src)
-{
- gen_mov_reg_V(dst, src);
- tcg_gen_xori_tl(dst, dst, 0x1);
-}
-
/*
FPSR bit field FCC1 | FCC0:
0 =
@@ -1203,34 +1090,22 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
TCG_COND_ALWAYS, /* vc: !V -> 1 */
};
- TCGv_i32 r_src;
- TCGv r_dst;
+ TCGv t1, t2;
-#ifdef TARGET_SPARC64
- if (xcc) {
- r_src = cpu_xcc;
- } else {
- r_src = cpu_psr;
- }
-#else
- r_src = cpu_psr;
-#endif
+ cmp->is_bool = false;
switch (dc->cc_op) {
case CC_OP_LOGIC:
cmp->cond = logic_cond[cond];
do_compare_dst_0:
- cmp->is_bool = false;
cmp->c2 = tcg_constant_tl(0);
-#ifdef TARGET_SPARC64
- if (!xcc) {
- cmp->c1 = tcg_temp_new();
- tcg_gen_ext32s_tl(cmp->c1, cpu_cc_dst);
- break;
+ if (TARGET_LONG_BITS == 32 || xcc) {
+ cmp->c1 = cpu_cc_dst;
+ } else {
+ cmp->c1 = t1 = tcg_temp_new();
+ tcg_gen_ext32s_tl(t1, cpu_cc_dst);
}
-#endif
- cmp->c1 = cpu_cc_dst;
- break;
+ return;
case CC_OP_SUB:
switch (cond) {
@@ -1241,92 +1116,128 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
case 7: /* overflow */
case 15: /* !overflow */
- goto do_dynamic;
+ break;
default:
cmp->cond = subcc_cond[cond];
- cmp->is_bool = false;
-#ifdef TARGET_SPARC64
- if (!xcc) {
+ if (TARGET_LONG_BITS == 32 || xcc) {
+ cmp->c1 = cpu_cc_src;
+ cmp->c2 = cpu_cc_src2;
+ } else {
/* Note that sign-extension works for unsigned compares as
long as both operands are sign-extended. */
- cmp->c1 = tcg_temp_new();
- cmp->c2 = tcg_temp_new();
- tcg_gen_ext32s_tl(cmp->c1, cpu_cc_src);
- tcg_gen_ext32s_tl(cmp->c2, cpu_cc_src2);
- break;
+ cmp->c1 = t1 = tcg_temp_new();
+ tcg_gen_ext32s_tl(t1, cpu_cc_src);
+ cmp->c2 = t2 = tcg_temp_new();
+ tcg_gen_ext32s_tl(t2, cpu_cc_src2);
}
-#endif
- cmp->c1 = cpu_cc_src;
- cmp->c2 = cpu_cc_src2;
- break;
+ return;
}
break;
default:
- do_dynamic:
gen_helper_compute_psr(tcg_env);
dc->cc_op = CC_OP_FLAGS;
- /* FALLTHRU */
+ break;
case CC_OP_FLAGS:
- /* We're going to generate a boolean result. */
- cmp->cond = TCG_COND_NE;
- cmp->is_bool = true;
- cmp->c1 = r_dst = tcg_temp_new();
- cmp->c2 = tcg_constant_tl(0);
+ break;
+ }
- switch (cond) {
- case 0x0:
- gen_op_eval_bn(r_dst);
- break;
- case 0x1:
- gen_op_eval_be(r_dst, r_src);
- break;
- case 0x2:
- gen_op_eval_ble(r_dst, r_src);
- break;
- case 0x3:
- gen_op_eval_bl(r_dst, r_src);
- break;
- case 0x4:
- gen_op_eval_bleu(r_dst, r_src);
- break;
- case 0x5:
- gen_op_eval_bcs(r_dst, r_src);
- break;
- case 0x6:
- gen_op_eval_bneg(r_dst, r_src);
- break;
- case 0x7:
- gen_op_eval_bvs(r_dst, r_src);
- break;
- case 0x8:
- gen_op_eval_ba(r_dst);
- break;
- case 0x9:
- gen_op_eval_bne(r_dst, r_src);
- break;
- case 0xa:
- gen_op_eval_bg(r_dst, r_src);
- break;
- case 0xb:
- gen_op_eval_bge(r_dst, r_src);
- break;
- case 0xc:
- gen_op_eval_bgu(r_dst, r_src);
- break;
- case 0xd:
- gen_op_eval_bcc(r_dst, r_src);
- break;
- case 0xe:
- gen_op_eval_bpos(r_dst, r_src);
- break;
- case 0xf:
- gen_op_eval_bvc(r_dst, r_src);
- break;
+ cmp->c1 = NULL;
+ cmp->c2 = tcg_constant_tl(0);
+
+ switch (cond & 7) {
+ case 0x0: /* never */
+ cmp->cond = TCG_COND_NEVER;
+ cmp->c1 = cmp->c2;
+ break;
+
+ case 0x1: /* eq */
+ cmp->cond = TCG_COND_EQ;
+ if (TARGET_LONG_BITS == 32 || xcc) {
+ cmp->c1 = cpu_cc_Z;
+ } else {
+ cmp->c1 = t1 = tcg_temp_new();
+ tcg_gen_ext32u_tl(t1, cpu_icc_Z);
}
break;
+
+ case 0x2: /* le: Z | (N ^ V) */
+ cmp->cond = TCG_COND_LT;
+ cmp->c1 = t1 = tcg_temp_new();
+ if (TARGET_LONG_BITS == 32 || xcc) {
+ tcg_gen_negsetcond_tl(TCG_COND_EQ, t1, cpu_cc_Z, cmp->c2);
+ } else {
+ tcg_gen_ext32u_tl(t1, cpu_icc_Z);
+ tcg_gen_negsetcond_tl(TCG_COND_EQ, t1, t1, cmp->c2);
+ }
+ t2 = tcg_temp_new();
+ tcg_gen_xor_tl(t2, cpu_cc_N, cpu_cc_V);
+ if (TARGET_LONG_BITS == 64 && !xcc) {
+ tcg_gen_ext32s_tl(t2, t2);
+ }
+ tcg_gen_or_tl(t1, t1, t2);
+ break;
+
+ case 0x3: /* lt: N ^ V */
+ cmp->cond = TCG_COND_LT;
+ cmp->c1 = t1 = tcg_temp_new();
+ tcg_gen_xor_tl(t1, cpu_cc_N, cpu_cc_V);
+ if (TARGET_LONG_BITS == 64 && !xcc) {
+ tcg_gen_ext32s_tl(t1, t1);
+ }
+ break;
+
+ case 0x4: /* leu: C | Z -> !(!C & !Z) */
+ cmp->cond = TCG_COND_EQ;
+ cmp->c1 = t1 = tcg_temp_new();
+ if (TARGET_LONG_BITS == 32 || xcc) {
+ tcg_gen_subi_tl(t1, cpu_cc_C, 1);
+ tcg_gen_and_tl(t1, t1, cpu_cc_Z);
+ } else {
+ tcg_gen_extract_tl(t1, cpu_icc_C, 32, 1);
+ tcg_gen_subi_tl(t1, t1, 1);
+ t2 = tcg_temp_new();
+ tcg_gen_ext32u_tl(t2, cpu_icc_Z);
+ tcg_gen_and_tl(t1, t1, t2);
+ }
+ break;
+
+ case 0x5: /* ltu: C */
+ cmp->cond = TCG_COND_NE;
+ cmp->is_bool = true;
+ if (TARGET_LONG_BITS == 32 || xcc) {
+ cmp->c1 = cpu_cc_C;
+ } else {
+ cmp->c1 = t1 = tcg_temp_new();
+ tcg_gen_extract_tl(t1, cpu_icc_C, 32, 1);
+ }
+ break;
+
+ case 0x6: /* neg: N */
+ cmp->cond = TCG_COND_LT;
+ if (TARGET_LONG_BITS == 32 || xcc) {
+ cmp->c1 = cpu_cc_N;
+ } else {
+ cmp->c1 = t1 = tcg_temp_new();
+ tcg_gen_ext32s_tl(t1, cpu_cc_N);
+ }
+ break;
+
+ case 0x7: /* vs: V */
+ cmp->cond = TCG_COND_LT;
+ if (TARGET_LONG_BITS == 32 || xcc) {
+ cmp->c1 = cpu_cc_V;
+ } else {
+ cmp->c1 = t1 = tcg_temp_new();
+ tcg_gen_ext32s_tl(t1, cpu_cc_V);
+ }
+ break;
+ }
+ if (cond & 8) {
+ cmp->cond = tcg_invert_cond(cmp->cond);
+ cmp->is_bool = false;
}
}
@@ -5602,13 +5513,11 @@ void sparc_tcg_init(void)
static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
#ifdef TARGET_SPARC64
- { &cpu_xcc, offsetof(CPUSPARCState, xcc), "xcc" },
{ &cpu_fprs, offsetof(CPUSPARCState, fprs), "fprs" },
#else
{ &cpu_wim, offsetof(CPUSPARCState, wim), "wim" },
#endif
{ &cpu_cc_op, offsetof(CPUSPARCState, cc_op), "cc_op" },
- { &cpu_psr, offsetof(CPUSPARCState, psr), "psr" },
};
static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {
@@ -5623,7 +5532,13 @@ void sparc_tcg_init(void)
{ &cpu_hver, offsetof(CPUSPARCState, hver), "hver" },
{ &cpu_ssr, offsetof(CPUSPARCState, ssr), "ssr" },
{ &cpu_ver, offsetof(CPUSPARCState, version), "ver" },
+ { &cpu_xcc_Z, offsetof(CPUSPARCState, cc_xcc_Z), "xcc_Z" },
+ { &cpu_xcc_C, offsetof(CPUSPARCState, cc_xcc_C), "xcc_C" },
#endif
+ { &cpu_cc_N, offsetof(CPUSPARCState, cc_N), "cc_N" },
+ { &cpu_cc_V, offsetof(CPUSPARCState, cc_V), "cc_V" },
+ { &cpu_icc_Z, offsetof(CPUSPARCState, cc_icc_Z), "icc_Z" },
+ { &cpu_icc_C, offsetof(CPUSPARCState, cc_icc_C), "icc_C" },
{ &cpu_cond, offsetof(CPUSPARCState, cond), "cond" },
{ &cpu_cc_src, offsetof(CPUSPARCState, cc_src), "cc_src" },
{ &cpu_cc_src2, offsetof(CPUSPARCState, cc_src2), "cc_src2" },
diff --git a/target/sparc/win_helper.c b/target/sparc/win_helper.c
index bf2c90c780..a446c1785d 100644
--- a/target/sparc/win_helper.c
+++ b/target/sparc/win_helper.c
@@ -53,23 +53,43 @@ void cpu_set_cwp(CPUSPARCState *env, int new_cwp)
target_ulong cpu_get_psr(CPUSPARCState *env)
{
+ target_ulong icc = 0;
+
helper_compute_psr(env);
+ icc |= ((int32_t)env->cc_N < 0) << PSR_NEG_SHIFT;
+ icc |= ((int32_t)env->cc_V < 0) << PSR_OVF_SHIFT;
+ icc |= ((int32_t)env->cc_icc_Z == 0) << PSR_ZERO_SHIFT;
+ if (TARGET_LONG_BITS == 64) {
+ icc |= extract64(env->cc_icc_C, 32, 1) << PSR_CARRY_SHIFT;
+ } else {
+ icc |= env->cc_icc_C << PSR_CARRY_SHIFT;
+ }
+
#if !defined(TARGET_SPARC64)
- return env->version | (env->psr & PSR_ICC) |
+ return env->version | icc |
(env->psref ? PSR_EF : 0) |
(env->psrpil << 8) |
(env->psrs ? PSR_S : 0) |
(env->psrps ? PSR_PS : 0) |
(env->psret ? PSR_ET : 0) | env->cwp;
#else
- return env->psr & PSR_ICC;
+ return icc;
#endif
}
void cpu_put_psr_icc(CPUSPARCState *env, target_ulong val)
{
- env->psr = val & PSR_ICC;
+ if (TARGET_LONG_BITS == 64) {
+ env->cc_N = deposit64(env->cc_N, 0, 32, -(val & PSR_NEG));
+ env->cc_V = deposit64(env->cc_V, 0, 32, -(val & PSR_OVF));
+ env->cc_icc_C = -(val & PSR_CARRY);
+ } else {
+ env->cc_N = -(val & PSR_NEG);
+ env->cc_V = -(val & PSR_OVF);
+ env->cc_icc_C = (val >> PSR_CARRY_SHIFT) & 1;
+ }
+ env->cc_icc_Z = ~val & PSR_ZERO;
}
void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val)
@@ -249,17 +269,32 @@ void helper_restored(CPUSPARCState *env)
target_ulong cpu_get_ccr(CPUSPARCState *env)
{
- target_ulong psr;
+ target_ulong ccr = 0;
- psr = cpu_get_psr(env);
+ helper_compute_psr(env);
- return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
+ ccr |= (env->cc_icc_C >> 32) & 1;
+ ccr |= ((int32_t)env->cc_V < 0) << 1;
+ ccr |= ((int32_t)env->cc_icc_Z == 0) << 2;
+ ccr |= ((int32_t)env->cc_N < 0) << 3;
+
+ ccr |= env->cc_xcc_C << 4;
+ ccr |= (env->cc_V < 0) << 5;
+ ccr |= (env->cc_xcc_Z == 0) << 6;
+ ccr |= (env->cc_N < 0) << 7;
+
+ return ccr;
}
void cpu_put_ccr(CPUSPARCState *env, target_ulong val)
{
- env->xcc = (val >> 4) << 20;
- env->psr = (val & 0xf) << 20;
+ env->cc_N = deposit64(-(val & 0x08), 32, 32, -(val & 0x80));
+ env->cc_V = deposit64(-(val & 0x02), 32, 32, -(val & 0x20));
+ env->cc_icc_C = (uint64_t)val << 32;
+ env->cc_xcc_C = (val >> 4) & 1;
+ env->cc_icc_Z = ~val & 0x04;
+ env->cc_xcc_Z = ~val & 0x40;
+
CC_OP = CC_OP_FLAGS;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 03/20] target/sparc: Remove CC_OP_DIV
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
2023-10-17 6:40 ` [PATCH 01/20] target/sparc: Introduce cpu_put_psr_icc Richard Henderson
2023-10-17 6:40 ` [PATCH 02/20] target/sparc: Split psr and xcc into components Richard Henderson
@ 2023-10-17 6:40 ` Richard Henderson
2023-10-17 6:40 ` [PATCH 04/20] target/sparc: Remove CC_OP_LOGIC Richard Henderson
` (16 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:40 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
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(-)
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index ac93658c33..df49d8423a 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -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 */
diff --git a/target/sparc/helper.h b/target/sparc/helper.h
index dd1721a340..58d3c979d4 100644
--- a/target/sparc/helper.h
+++ b/target/sparc/helper.h
@@ -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)
diff --git a/target/sparc/cc_helper.c b/target/sparc/cc_helper.c
index fe4618ad34..a6d1a4b9ae 100644
--- a/target/sparc/cc_helper.c
+++ b/target/sparc/cc_helper.c
@@ -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 },
diff --git a/target/sparc/helper.c b/target/sparc/helper.c
index c4358bba84..87a4258792 100644
--- a/target/sparc/helper.c
+++ b/target/sparc/helper.c
@@ -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)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index f2a2d69f91..2ca20ba110 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -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)
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 04/20] target/sparc: Remove CC_OP_LOGIC
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (2 preceding siblings ...)
2023-10-17 6:40 ` [PATCH 03/20] target/sparc: Remove CC_OP_DIV Richard Henderson
@ 2023-10-17 6:40 ` Richard Henderson
2023-10-17 6:40 ` [PATCH 05/20] target/sparc: Remove CC_OP_ADD, CC_OP_ADDX, CC_OP_TADD Richard Henderson
` (15 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:40 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/cpu.h | 1 -
target/sparc/cc_helper.c | 19 --------
target/sparc/translate.c | 97 +++++++++++++++++-----------------------
3 files changed, 40 insertions(+), 77 deletions(-)
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index df49d8423a..48e549f7cb 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -158,7 +158,6 @@ enum {
CC_OP_SUBX, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_TSUB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_TSUBTV, /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
- CC_OP_LOGIC, /* modify N and Z, C = V = 0, CC_DST = res */
CC_OP_NB,
};
diff --git a/target/sparc/cc_helper.c b/target/sparc/cc_helper.c
index a6d1a4b9ae..a88399d74a 100644
--- a/target/sparc/cc_helper.c
+++ b/target/sparc/cc_helper.c
@@ -354,23 +354,6 @@ static uint32_t compute_all_tsubtv(CPUSPARCState *env)
return ret;
}
-static uint32_t compute_all_logic(CPUSPARCState *env)
-{
- return get_NZ_icc(CC_DST);
-}
-
-static uint32_t compute_C_logic(CPUSPARCState *env)
-{
- return 0;
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_logic_xcc(CPUSPARCState *env)
-{
- return get_NZ_xcc(CC_DST);
-}
-#endif
-
typedef struct CCTable {
uint32_t (*compute_all)(CPUSPARCState *env); /* return all the flags */
uint32_t (*compute_c)(CPUSPARCState *env); /* return the C flag */
@@ -386,7 +369,6 @@ static const CCTable icc_table[CC_OP_NB] = {
[CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
[CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
[CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
- [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
};
#ifdef TARGET_SPARC64
@@ -400,7 +382,6 @@ static const CCTable xcc_table[CC_OP_NB] = {
[CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
[CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
[CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
- [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
};
#endif
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 2ca20ba110..989275b17d 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -437,15 +437,6 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
TCGv carry;
switch (dc->cc_op) {
- case CC_OP_LOGIC:
- /* Carry is known to be zero. Fall back to plain ADD. */
- if (update_cc) {
- gen_op_add_cc(dst, src1, src2);
- } else {
- tcg_gen_add_tl(dst, src1, src2);
- }
- return;
-
case CC_OP_ADD:
case CC_OP_TADD:
case CC_OP_TADDTV:
@@ -509,15 +500,6 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
TCGv carry;
switch (dc->cc_op) {
- case CC_OP_LOGIC:
- /* Carry is known to be zero. Fall back to plain SUB. */
- if (update_cc) {
- gen_op_sub_cc(dst, src1, src2);
- } else {
- tcg_gen_sub_tl(dst, src1, src2);
- }
- return;
-
case CC_OP_ADD:
case CC_OP_TADD:
case CC_OP_TADDTV:
@@ -1069,48 +1051,25 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
-1, /* no overflow */
};
- static int logic_cond[16] = {
- TCG_COND_NEVER,
- TCG_COND_EQ, /* eq: Z */
- TCG_COND_LE, /* le: Z | (N ^ V) -> Z | N */
- TCG_COND_LT, /* lt: N ^ V -> N */
- TCG_COND_EQ, /* leu: C | Z -> Z */
- TCG_COND_NEVER, /* ltu: C -> 0 */
- TCG_COND_LT, /* neg: N */
- TCG_COND_NEVER, /* vs: V -> 0 */
- TCG_COND_ALWAYS,
- TCG_COND_NE, /* ne: !Z */
- TCG_COND_GT, /* gt: !(Z | (N ^ V)) -> !(Z | N) */
- TCG_COND_GE, /* ge: !(N ^ V) -> !N */
- TCG_COND_NE, /* gtu: !(C | Z) -> !Z */
- TCG_COND_ALWAYS, /* geu: !C -> 1 */
- TCG_COND_GE, /* pos: !N */
- TCG_COND_ALWAYS, /* vc: !V -> 1 */
- };
-
TCGv t1, t2;
cmp->is_bool = false;
switch (dc->cc_op) {
- case CC_OP_LOGIC:
- cmp->cond = logic_cond[cond];
- do_compare_dst_0:
- cmp->c2 = tcg_constant_tl(0);
- if (TARGET_LONG_BITS == 32 || xcc) {
- cmp->c1 = cpu_cc_dst;
- } else {
- cmp->c1 = t1 = tcg_temp_new();
- tcg_gen_ext32s_tl(t1, cpu_cc_dst);
- }
- return;
case CC_OP_SUB:
switch (cond) {
case 6: /* neg */
case 14: /* pos */
cmp->cond = (cond == 6 ? TCG_COND_LT : TCG_COND_GE);
- goto do_compare_dst_0;
+ cmp->c2 = tcg_constant_tl(0);
+ if (TARGET_LONG_BITS == 32 || xcc) {
+ cmp->c1 = cpu_cc_dst;
+ } else {
+ cmp->c1 = t1 = tcg_temp_new();
+ tcg_gen_ext32s_tl(t1, cpu_cc_dst);
+ }
+ return;
case 7: /* overflow */
case 15: /* !overflow */
@@ -3726,6 +3685,8 @@ static bool do_cc_arith(DisasContext *dc, arg_r_r_ri *a, int cc_op,
if (cc_op < 0) {
dst = gen_dest_gpr(dc, a->rd);
+ } else if (cc_op == CC_OP_FLAGS) {
+ dst = cpu_cc_N;
} else {
dst = cpu_cc_dst;
tcg_gen_movi_i32(cpu_cc_op, cc_op);
@@ -3742,6 +3703,21 @@ static bool do_cc_arith(DisasContext *dc, arg_r_r_ri *a, int cc_op,
} else {
func(dst, src1, cpu_regs[a->rs2_or_imm]);
}
+
+ /* Logic insn; to be cleaned up later. */
+ if (cc_op == CC_OP_FLAGS) {
+ tcg_gen_movi_tl(cpu_cc_V, 0);
+ tcg_gen_movi_tl(cpu_icc_C, 0);
+#ifdef TARGET_SPARC64
+ tcg_gen_movi_tl(cpu_xcc_C, 0);
+ tcg_gen_mov_tl(cpu_xcc_Z, dst);
+#endif
+ tcg_gen_mov_tl(cpu_icc_Z, dst);
+
+ tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
+ dc->cc_op = CC_OP_FLAGS;
+ }
+
gen_store_gpr(dc, a->rd, dst);
return advance_pc(dc);
}
@@ -3764,6 +3740,13 @@ static bool do_flags_arith(DisasContext *dc, arg_r_r_ri *a, int cc_op,
return false;
}
+static bool do_logic_cc(DisasContext *dc, arg_r_r_ri *a,
+ void (*func)(TCGv, TCGv, TCGv),
+ void (*funci)(TCGv, TCGv, target_long))
+{
+ return do_cc_arith(dc, a, CC_OP_FLAGS, func, funci);
+}
+
static bool trans_OR(DisasContext *dc, arg_r_r_ri *a)
{
/* For simplicity, we under-decoded the rs2 form. */
@@ -3805,15 +3788,15 @@ TRANS(SDIV, DIV, do_arith, a, gen_op_sdiv, NULL)
TRANS(POPC, 64, do_arith, a, gen_op_popc, NULL)
TRANS(ADDcc, ALL, do_cc_arith, a, CC_OP_ADD, gen_op_add_cc, NULL)
-TRANS(ANDcc, ALL, do_cc_arith, a, CC_OP_LOGIC, tcg_gen_and_tl, tcg_gen_andi_tl)
-TRANS(ORcc, ALL, do_cc_arith, a, CC_OP_LOGIC, tcg_gen_or_tl, tcg_gen_ori_tl)
-TRANS(XORcc, ALL, do_cc_arith, a, CC_OP_LOGIC, tcg_gen_xor_tl, tcg_gen_xori_tl)
+TRANS(ANDcc, ALL, do_logic_cc, a, tcg_gen_and_tl, tcg_gen_andi_tl)
+TRANS(ORcc, ALL, do_logic_cc, a, tcg_gen_or_tl, tcg_gen_ori_tl)
+TRANS(XORcc, ALL, do_logic_cc, a, tcg_gen_xor_tl, tcg_gen_xori_tl)
TRANS(SUBcc, ALL, do_cc_arith, a, CC_OP_SUB, gen_op_sub_cc, NULL)
-TRANS(ANDNcc, ALL, do_cc_arith, a, CC_OP_LOGIC, tcg_gen_andc_tl, NULL)
-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(ANDNcc, ALL, do_logic_cc, a, tcg_gen_andc_tl, NULL)
+TRANS(ORNcc, ALL, do_logic_cc, a, tcg_gen_orc_tl, NULL)
+TRANS(XORNcc, ALL, do_logic_cc, a, tcg_gen_eqv_tl, NULL)
+TRANS(UMULcc, MUL, do_logic_cc, a, gen_op_umul, NULL)
+TRANS(SMULcc, MUL, do_logic_cc, a, gen_op_smul, NULL)
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)
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 05/20] target/sparc: Remove CC_OP_ADD, CC_OP_ADDX, CC_OP_TADD
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (3 preceding siblings ...)
2023-10-17 6:40 ` [PATCH 04/20] target/sparc: Remove CC_OP_LOGIC Richard Henderson
@ 2023-10-17 6:40 ` Richard Henderson
2023-10-17 6:40 ` [PATCH 06/20] target/sparc: Remove CC_OP_SUB, CC_OP_SUBX, CC_OP_TSUB Richard Henderson
` (14 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:40 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
These are all related and implementable with common code.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/cpu.h | 3 -
target/sparc/cc_helper.c | 59 ------------
target/sparc/translate.c | 199 +++++++++++++++++++--------------------
3 files changed, 95 insertions(+), 166 deletions(-)
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 48e549f7cb..4925b35859 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -150,9 +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_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 */
CC_OP_TADDTV, /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
CC_OP_SUB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_SUBX, /* modify all flags, CC_DST = res, CC_SRC = src1 */
diff --git a/target/sparc/cc_helper.c b/target/sparc/cc_helper.c
index a88399d74a..c004a9b1d8 100644
--- a/target/sparc/cc_helper.c
+++ b/target/sparc/cc_helper.c
@@ -128,53 +128,11 @@ static uint32_t compute_C_add_xcc(CPUSPARCState *env)
}
#endif
-static uint32_t compute_all_add(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_add_icc(CC_DST, CC_SRC);
- ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
static uint32_t compute_C_add(CPUSPARCState *env)
{
return get_C_add_icc(CC_DST, CC_SRC);
}
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_addx_xcc(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_addx_xcc(CPUSPARCState *env)
-{
- return get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
-}
-#endif
-
-static uint32_t compute_all_addx(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_addx(CPUSPARCState *env)
-{
- return get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
-}
-
static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
{
uint32_t ret = 0;
@@ -185,17 +143,6 @@ static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
return ret;
}
-static uint32_t compute_all_tadd(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_add_icc(CC_DST, CC_SRC);
- ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
- return ret;
-}
-
static uint32_t compute_all_taddtv(CPUSPARCState *env)
{
uint32_t ret;
@@ -361,9 +308,6 @@ typedef struct CCTable {
static const CCTable icc_table[CC_OP_NB] = {
/* CC_OP_DYNAMIC should never happen */
- [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 },
[CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
[CC_OP_SUB] = { compute_all_sub, compute_C_sub },
[CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
@@ -374,9 +318,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_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 },
[CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
[CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
[CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 989275b17d..59e96bf39d 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -380,12 +380,72 @@ static void gen_goto_tb(DisasContext *s, int tb_num,
}
}
-static void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2)
+static TCGv gen_carry32(void)
{
- tcg_gen_mov_tl(cpu_cc_src, src1);
- tcg_gen_mov_tl(cpu_cc_src2, src2);
- tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
- tcg_gen_mov_tl(dst, cpu_cc_dst);
+#ifdef TARGET_SPARC64
+ TCGv t = tcg_temp_new();
+ tcg_gen_extract_tl(t, cpu_icc_C, 32, 1);
+ return t;
+#else
+ return cpu_icc_C;
+#endif
+}
+
+static void gen_op_addcc_int(TCGv dst, TCGv src1, TCGv src2, TCGv cin)
+{
+ TCGv z = tcg_constant_tl(0);
+
+ if (cin) {
+ tcg_gen_add2_tl(cpu_cc_N, cpu_cc_C, src1, z, cin, z);
+ tcg_gen_add2_tl(cpu_cc_N, cpu_cc_C, cpu_cc_N, cpu_cc_C, src2, z);
+ } else {
+ tcg_gen_add2_tl(cpu_cc_N, cpu_cc_C, src1, z, src2, z);
+ }
+ tcg_gen_xor_tl(cpu_cc_Z, src1, src2);
+ tcg_gen_xor_tl(cpu_cc_V, cpu_cc_N, src2);
+ tcg_gen_andc_tl(cpu_cc_V, cpu_cc_V, cpu_cc_Z);
+#ifdef TARGET_SPARC64
+ /*
+ * Carry-in to bit 32 is result ^ src1 ^ src2.
+ * We already have the src xor term in Z, from computation of V.
+ */
+ tcg_gen_xor_tl(cpu_icc_C, cpu_cc_Z, cpu_cc_N);
+ tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
+#endif
+ tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
+ tcg_gen_mov_tl(dst, cpu_cc_N);
+}
+
+static void gen_op_addcc(TCGv dst, TCGv src1, TCGv src2)
+{
+ gen_op_addcc_int(dst, src1, src2, NULL);
+}
+
+static void gen_op_taddcc(TCGv dst, TCGv src1, TCGv src2)
+{
+ TCGv t = tcg_temp_new();
+
+ /* Save the tag bits around modification of dst. */
+ tcg_gen_or_tl(t, src1, src2);
+
+ gen_op_addcc(dst, src1, src2);
+
+ /* Incorprate tag bits into icc.V */
+ tcg_gen_andi_tl(t, t, 3);
+ tcg_gen_neg_tl(t, t);
+ tcg_gen_ext32u_tl(t, t);
+ tcg_gen_or_tl(cpu_cc_N, cpu_cc_N, t);
+}
+
+static void gen_op_addc(TCGv dst, TCGv src1, TCGv src2)
+{
+ tcg_gen_add_tl(dst, src1, src2);
+ tcg_gen_add_tl(dst, dst, gen_carry32());
+}
+
+static void gen_op_addccc(TCGv dst, TCGv src1, TCGv src2)
+{
+ gen_op_addcc_int(dst, src1, src2, gen_carry32());
}
static TCGv_i32 gen_add32_carry32(void)
@@ -430,61 +490,6 @@ static TCGv_i32 gen_sub32_carry32(void)
return carry_32;
}
-static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
- TCGv src2, int update_cc)
-{
- TCGv_i32 carry_32;
- TCGv carry;
-
- switch (dc->cc_op) {
- case CC_OP_ADD:
- case CC_OP_TADD:
- case CC_OP_TADDTV:
- if (TARGET_LONG_BITS == 32) {
- /* We can re-use the host's hardware carry generation by using
- an ADD2 opcode. We discard the low part of the output.
- Ideally we'd combine this operation with the add that
- generated the carry in the first place. */
- carry = tcg_temp_new();
- tcg_gen_add2_tl(carry, dst, cpu_cc_src, src1, cpu_cc_src2, src2);
- goto add_done;
- }
- carry_32 = gen_add32_carry32();
- break;
-
- case CC_OP_SUB:
- case CC_OP_TSUB:
- case CC_OP_TSUBTV:
- carry_32 = gen_sub32_carry32();
- break;
-
- default:
- /* We need external help to produce the carry. */
- carry_32 = tcg_temp_new_i32();
- gen_helper_compute_C_icc(carry_32, tcg_env);
- break;
- }
-
-#if TARGET_LONG_BITS == 64
- carry = tcg_temp_new();
- tcg_gen_extu_i32_i64(carry, carry_32);
-#else
- carry = carry_32;
-#endif
-
- tcg_gen_add_tl(dst, src1, src2);
- tcg_gen_add_tl(dst, dst, carry);
-
- add_done:
- if (update_cc) {
- tcg_gen_mov_tl(cpu_cc_src, src1);
- tcg_gen_mov_tl(cpu_cc_src2, src2);
- tcg_gen_mov_tl(cpu_cc_dst, dst);
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADDX);
- dc->cc_op = CC_OP_ADDX;
- }
-}
-
static void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
{
tcg_gen_mov_tl(cpu_cc_src, src1);
@@ -500,8 +505,6 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
TCGv carry;
switch (dc->cc_op) {
- case CC_OP_ADD:
- case CC_OP_TADD:
case CC_OP_TADDTV:
carry_32 = gen_add32_carry32();
break;
@@ -550,39 +553,39 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
static void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
{
- TCGv r_temp, zero, t0;
+ TCGv zero = tcg_constant_tl(0);
+ TCGv t_src1 = tcg_temp_new();
+ TCGv t_src2 = tcg_temp_new();
+ TCGv t0 = tcg_temp_new();
- r_temp = tcg_temp_new();
- t0 = tcg_temp_new();
+ tcg_gen_ext32u_tl(t_src1, src1);
+ tcg_gen_ext32u_tl(t_src2, src2);
- /* old op:
- if (!(env->y & 1))
- T1 = 0;
- */
- zero = tcg_constant_tl(0);
- tcg_gen_andi_tl(cpu_cc_src, src1, 0xffffffff);
- tcg_gen_andi_tl(r_temp, cpu_y, 0x1);
- tcg_gen_andi_tl(cpu_cc_src2, src2, 0xffffffff);
- tcg_gen_movcond_tl(TCG_COND_EQ, cpu_cc_src2, r_temp, zero,
- zero, cpu_cc_src2);
+ /*
+ * if (!(env->y & 1))
+ * src2 = 0;
+ */
+ tcg_gen_andi_tl(t0, cpu_y, 0x1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, t_src2, t0, zero, zero, t_src2);
- // b2 = T0 & 1;
- // env->y = (b2 << 31) | (env->y >> 1);
+ /*
+ * b2 = src1 & 1;
+ * y = (b2 << 31) | (y >> 1);
+ */
tcg_gen_extract_tl(t0, cpu_y, 1, 31);
- tcg_gen_deposit_tl(cpu_y, t0, cpu_cc_src, 31, 1);
+ tcg_gen_deposit_tl(cpu_y, t0, src1, 31, 1);
// b1 = N ^ V;
tcg_gen_xor_tl(t0, cpu_cc_N, cpu_cc_V);
- // T0 = (b1 << 31) | (T0 >> 1);
- // src1 = T0;
+ /*
+ * src1 = (b1 << 31) | (src1 >> 1)
+ */
tcg_gen_andi_tl(t0, t0, 1u << 31);
- tcg_gen_shri_tl(cpu_cc_src, cpu_cc_src, 1);
- tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0);
+ tcg_gen_shri_tl(t_src1, t_src1, 1);
+ tcg_gen_or_tl(t_src1, t_src1, t0);
- tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
-
- tcg_gen_mov_tl(dst, cpu_cc_dst);
+ gen_op_addcc(dst, t_src1, t_src2);
}
static void gen_op_multiply(TCGv dst, TCGv src1, TCGv src2, int sign_ext)
@@ -3787,7 +3790,7 @@ TRANS(SDIV, DIV, do_arith, a, gen_op_sdiv, NULL)
/* TODO: Should have feature bit -- comes in with UltraSparc T2. */
TRANS(POPC, 64, do_arith, a, gen_op_popc, NULL)
-TRANS(ADDcc, ALL, do_cc_arith, a, CC_OP_ADD, gen_op_add_cc, NULL)
+TRANS(ADDcc, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_addcc)
TRANS(ANDcc, ALL, do_logic_cc, a, tcg_gen_and_tl, tcg_gen_andi_tl)
TRANS(ORcc, ALL, do_logic_cc, a, tcg_gen_or_tl, tcg_gen_ori_tl)
TRANS(XORcc, ALL, do_logic_cc, a, tcg_gen_xor_tl, tcg_gen_xori_tl)
@@ -3799,7 +3802,7 @@ TRANS(UMULcc, MUL, do_logic_cc, a, gen_op_umul, NULL)
TRANS(SMULcc, MUL, do_logic_cc, a, gen_op_smul, NULL)
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(TADDcc, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_taddcc)
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)
TRANS(TSUBccTV, ALL, do_flags_arith, a, CC_OP_TSUBTV, gen_op_tsubcctv)
@@ -3819,26 +3822,14 @@ static TCGv gen_rs2_or_imm(DisasContext *dc, bool imm, int rs2_or_imm)
static bool trans_ADDC(DisasContext *dc, arg_r_r_ri *a)
{
- TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm);
-
- if (src2 == NULL) {
- return false;
- }
- gen_op_addx_int(dc, gen_dest_gpr(dc, a->rd),
- gen_load_gpr(dc, a->rs1), src2, false);
- return advance_pc(dc);
+ update_psr(dc);
+ return do_arith(dc, a, gen_op_addc, NULL);
}
static bool trans_ADDCcc(DisasContext *dc, arg_r_r_ri *a)
{
- TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm);
-
- if (src2 == NULL) {
- return false;
- }
- gen_op_addx_int(dc, gen_dest_gpr(dc, a->rd),
- gen_load_gpr(dc, a->rs1), src2, true);
- return advance_pc(dc);
+ update_psr(dc);
+ return do_flags_arith(dc, a, CC_OP_FLAGS, gen_op_addccc);
}
static bool trans_SUBC(DisasContext *dc, arg_r_r_ri *a)
@@ -3868,7 +3859,7 @@ static bool trans_SUBCcc(DisasContext *dc, arg_r_r_ri *a)
static bool trans_MULScc(DisasContext *dc, arg_r_r_ri *a)
{
update_psr(dc);
- return do_cc_arith(dc, a, CC_OP_ADD, gen_op_mulscc, NULL);
+ return do_flags_arith(dc, a, CC_OP_FLAGS, gen_op_mulscc);
}
static bool gen_edge(DisasContext *dc, arg_r_r_r *a,
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 06/20] target/sparc: Remove CC_OP_SUB, CC_OP_SUBX, CC_OP_TSUB
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (4 preceding siblings ...)
2023-10-17 6:40 ` [PATCH 05/20] target/sparc: Remove CC_OP_ADD, CC_OP_ADDX, CC_OP_TADD Richard Henderson
@ 2023-10-17 6:40 ` Richard Henderson
2023-10-17 6:40 ` [PATCH 07/20] target/sparc: Remove CC_OP_TADDTV, CC_OP_TSUBTV Richard Henderson
` (13 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:40 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
These are all related and implementable with common code.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/cpu.h | 3 -
target/sparc/cc_helper.c | 59 ----------
target/sparc/translate.c | 226 ++++++++++-----------------------------
3 files changed, 54 insertions(+), 234 deletions(-)
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 4925b35859..8498bd07db 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -151,9 +151,6 @@ 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_TADDTV, /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
- CC_OP_SUB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
- CC_OP_SUBX, /* modify all flags, CC_DST = res, CC_SRC = src1 */
- CC_OP_TSUB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_TSUBTV, /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
CC_OP_NB,
};
diff --git a/target/sparc/cc_helper.c b/target/sparc/cc_helper.c
index c004a9b1d8..d31aa24b5d 100644
--- a/target/sparc/cc_helper.c
+++ b/target/sparc/cc_helper.c
@@ -234,64 +234,11 @@ static uint32_t compute_C_sub_xcc(CPUSPARCState *env)
}
#endif
-static uint32_t compute_all_sub(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
- ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
static uint32_t compute_C_sub(CPUSPARCState *env)
{
return get_C_sub_icc(CC_SRC, CC_SRC2);
}
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_subx_xcc(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_subx_xcc(CPUSPARCState *env)
-{
- return get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
-}
-#endif
-
-static uint32_t compute_all_subx(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_subx(CPUSPARCState *env)
-{
- return get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
-}
-
-static uint32_t compute_all_tsub(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
- ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
- return ret;
-}
-
static uint32_t compute_all_tsubtv(CPUSPARCState *env)
{
uint32_t ret;
@@ -309,9 +256,6 @@ typedef struct CCTable {
static const CCTable icc_table[CC_OP_NB] = {
/* CC_OP_DYNAMIC should never happen */
[CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
- [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
- [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
- [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
[CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
};
@@ -319,9 +263,6 @@ static const CCTable icc_table[CC_OP_NB] = {
static const CCTable xcc_table[CC_OP_NB] = {
/* CC_OP_DYNAMIC should never happen */
[CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
- [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
- [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
- [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
[CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
};
#endif
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 59e96bf39d..ff523a4e7d 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -448,107 +448,58 @@ static void gen_op_addccc(TCGv dst, TCGv src1, TCGv src2)
gen_op_addcc_int(dst, src1, src2, gen_carry32());
}
-static TCGv_i32 gen_add32_carry32(void)
+static void gen_op_subcc_int(TCGv dst, TCGv src1, TCGv src2, TCGv cin)
{
- TCGv_i32 carry_32, cc_src1_32, cc_src2_32;
+ TCGv z = tcg_constant_tl(0);
- /* Carry is computed from a previous add: (dst < src) */
-#if TARGET_LONG_BITS == 64
- cc_src1_32 = tcg_temp_new_i32();
- cc_src2_32 = tcg_temp_new_i32();
- tcg_gen_extrl_i64_i32(cc_src1_32, cpu_cc_dst);
- tcg_gen_extrl_i64_i32(cc_src2_32, cpu_cc_src);
-#else
- cc_src1_32 = cpu_cc_dst;
- cc_src2_32 = cpu_cc_src;
-#endif
-
- carry_32 = tcg_temp_new_i32();
- tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32);
-
- return carry_32;
-}
-
-static TCGv_i32 gen_sub32_carry32(void)
-{
- TCGv_i32 carry_32, cc_src1_32, cc_src2_32;
-
- /* Carry is computed from a previous borrow: (src1 < src2) */
-#if TARGET_LONG_BITS == 64
- cc_src1_32 = tcg_temp_new_i32();
- cc_src2_32 = tcg_temp_new_i32();
- tcg_gen_extrl_i64_i32(cc_src1_32, cpu_cc_src);
- tcg_gen_extrl_i64_i32(cc_src2_32, cpu_cc_src2);
-#else
- cc_src1_32 = cpu_cc_src;
- cc_src2_32 = cpu_cc_src2;
-#endif
-
- carry_32 = tcg_temp_new_i32();
- tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32);
-
- return carry_32;
-}
-
-static void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
-{
- tcg_gen_mov_tl(cpu_cc_src, src1);
- tcg_gen_mov_tl(cpu_cc_src2, src2);
- tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
- tcg_gen_mov_tl(dst, cpu_cc_dst);
-}
-
-static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
- TCGv src2, int update_cc)
-{
- TCGv_i32 carry_32;
- TCGv carry;
-
- switch (dc->cc_op) {
- case CC_OP_TADDTV:
- carry_32 = gen_add32_carry32();
- break;
-
- case CC_OP_SUB:
- case CC_OP_TSUB:
- case CC_OP_TSUBTV:
- if (TARGET_LONG_BITS == 32) {
- /* We can re-use the host's hardware carry generation by using
- a SUB2 opcode. We discard the low part of the output.
- Ideally we'd combine this operation with the add that
- generated the carry in the first place. */
- carry = tcg_temp_new();
- tcg_gen_sub2_tl(carry, dst, cpu_cc_src, src1, cpu_cc_src2, src2);
- goto sub_done;
- }
- carry_32 = gen_sub32_carry32();
- break;
-
- default:
- /* We need external help to produce the carry. */
- carry_32 = tcg_temp_new_i32();
- gen_helper_compute_C_icc(carry_32, tcg_env);
- break;
+ if (cin) {
+ tcg_gen_sub2_tl(cpu_cc_N, cpu_cc_C, src1, z, cin, z);
+ tcg_gen_sub2_tl(cpu_cc_N, cpu_cc_C, cpu_cc_N, cpu_cc_C, src2, z);
+ } else {
+ tcg_gen_sub2_tl(cpu_cc_N, cpu_cc_C, src1, z, src2, z);
}
-
-#if TARGET_LONG_BITS == 64
- carry = tcg_temp_new();
- tcg_gen_extu_i32_i64(carry, carry_32);
-#else
- carry = carry_32;
+ tcg_gen_neg_tl(cpu_cc_C, cpu_cc_C);
+ tcg_gen_xor_tl(cpu_cc_Z, src1, src2);
+ tcg_gen_xor_tl(cpu_cc_V, cpu_cc_N, src1);
+ tcg_gen_and_tl(cpu_cc_V, cpu_cc_V, cpu_cc_Z);
+#ifdef TARGET_SPARC64
+ tcg_gen_xor_tl(cpu_icc_C, cpu_cc_Z, cpu_cc_N);
+ tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
#endif
+ tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
+ tcg_gen_mov_tl(dst, cpu_cc_N);
+}
+static void gen_op_subcc(TCGv dst, TCGv src1, TCGv src2)
+{
+ gen_op_subcc_int(dst, src1, src2, NULL);
+}
+
+static void gen_op_tsubcc(TCGv dst, TCGv src1, TCGv src2)
+{
+ TCGv t = tcg_temp_new();
+
+ /* Save the tag bits around modification of dst. */
+ tcg_gen_or_tl(t, src1, src2);
+
+ gen_op_subcc(dst, src1, src2);
+
+ /* Incorprate tag bits into icc.V */
+ tcg_gen_andi_tl(t, t, 3);
+ tcg_gen_neg_tl(t, t);
+ tcg_gen_ext32u_tl(t, t);
+ tcg_gen_or_tl(cpu_cc_N, cpu_cc_N, t);
+}
+
+static void gen_op_subc(TCGv dst, TCGv src1, TCGv src2)
+{
tcg_gen_sub_tl(dst, src1, src2);
- tcg_gen_sub_tl(dst, dst, carry);
+ tcg_gen_sub_tl(dst, dst, gen_carry32());
+}
- sub_done:
- if (update_cc) {
- tcg_gen_mov_tl(cpu_cc_src, src1);
- tcg_gen_mov_tl(cpu_cc_src2, src2);
- tcg_gen_mov_tl(cpu_cc_dst, dst);
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUBX);
- dc->cc_op = CC_OP_SUBX;
- }
+static void gen_op_subccc(TCGv dst, TCGv src1, TCGv src2)
+{
+ gen_op_subcc_int(dst, src1, src2, gen_carry32());
}
static void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
@@ -1035,66 +986,11 @@ static void gen_op_next_insn(void)
static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
DisasContext *dc)
{
- static int subcc_cond[16] = {
- TCG_COND_NEVER,
- TCG_COND_EQ,
- TCG_COND_LE,
- TCG_COND_LT,
- TCG_COND_LEU,
- TCG_COND_LTU,
- -1, /* neg */
- -1, /* overflow */
- TCG_COND_ALWAYS,
- TCG_COND_NE,
- TCG_COND_GT,
- TCG_COND_GE,
- TCG_COND_GTU,
- TCG_COND_GEU,
- -1, /* pos */
- -1, /* no overflow */
- };
-
TCGv t1, t2;
cmp->is_bool = false;
switch (dc->cc_op) {
-
- case CC_OP_SUB:
- switch (cond) {
- case 6: /* neg */
- case 14: /* pos */
- cmp->cond = (cond == 6 ? TCG_COND_LT : TCG_COND_GE);
- cmp->c2 = tcg_constant_tl(0);
- if (TARGET_LONG_BITS == 32 || xcc) {
- cmp->c1 = cpu_cc_dst;
- } else {
- cmp->c1 = t1 = tcg_temp_new();
- tcg_gen_ext32s_tl(t1, cpu_cc_dst);
- }
- return;
-
- case 7: /* overflow */
- case 15: /* !overflow */
- break;
-
- default:
- cmp->cond = subcc_cond[cond];
- if (TARGET_LONG_BITS == 32 || xcc) {
- cmp->c1 = cpu_cc_src;
- cmp->c2 = cpu_cc_src2;
- } else {
- /* Note that sign-extension works for unsigned compares as
- long as both operands are sign-extended. */
- cmp->c1 = t1 = tcg_temp_new();
- tcg_gen_ext32s_tl(t1, cpu_cc_src);
- cmp->c2 = t2 = tcg_temp_new();
- tcg_gen_ext32s_tl(t2, cpu_cc_src2);
- }
- return;
- }
- break;
-
default:
gen_helper_compute_psr(tcg_env);
dc->cc_op = CC_OP_FLAGS;
@@ -3794,7 +3690,7 @@ TRANS(ADDcc, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_addcc)
TRANS(ANDcc, ALL, do_logic_cc, a, tcg_gen_and_tl, tcg_gen_andi_tl)
TRANS(ORcc, ALL, do_logic_cc, a, tcg_gen_or_tl, tcg_gen_ori_tl)
TRANS(XORcc, ALL, do_logic_cc, a, tcg_gen_xor_tl, tcg_gen_xori_tl)
-TRANS(SUBcc, ALL, do_cc_arith, a, CC_OP_SUB, gen_op_sub_cc, NULL)
+TRANS(SUBcc, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_subcc)
TRANS(ANDNcc, ALL, do_logic_cc, a, tcg_gen_andc_tl, NULL)
TRANS(ORNcc, ALL, do_logic_cc, a, tcg_gen_orc_tl, NULL)
TRANS(XORNcc, ALL, do_logic_cc, a, tcg_gen_eqv_tl, NULL)
@@ -3803,7 +3699,7 @@ TRANS(SMULcc, MUL, do_logic_cc, a, gen_op_smul, NULL)
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_flags_arith, a, CC_OP_FLAGS, gen_op_taddcc)
-TRANS(TSUBcc, ALL, do_cc_arith, a, CC_OP_TSUB, gen_op_sub_cc, NULL)
+TRANS(TSUBcc, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_tsubcc)
TRANS(TADDccTV, ALL, do_flags_arith, a, CC_OP_TADDTV, gen_op_taddcctv)
TRANS(TSUBccTV, ALL, do_flags_arith, a, CC_OP_TSUBTV, gen_op_tsubcctv)
@@ -3834,26 +3730,14 @@ static bool trans_ADDCcc(DisasContext *dc, arg_r_r_ri *a)
static bool trans_SUBC(DisasContext *dc, arg_r_r_ri *a)
{
- TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm);
-
- if (src2 == NULL) {
- return false;
- }
- gen_op_subx_int(dc, gen_dest_gpr(dc, a->rd),
- gen_load_gpr(dc, a->rs1), src2, false);
- return advance_pc(dc);
+ update_psr(dc);
+ return do_arith(dc, a, gen_op_subc, NULL);
}
static bool trans_SUBCcc(DisasContext *dc, arg_r_r_ri *a)
{
- TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm);
-
- if (src2 == NULL) {
- return false;
- }
- gen_op_subx_int(dc, gen_dest_gpr(dc, a->rd),
- gen_load_gpr(dc, a->rs1), src2, true);
- return advance_pc(dc);
+ update_psr(dc);
+ return do_flags_arith(dc, a, CC_OP_FLAGS, gen_op_subccc);
}
static bool trans_MULScc(DisasContext *dc, arg_r_r_ri *a)
@@ -3874,11 +3758,9 @@ static bool gen_edge(DisasContext *dc, arg_r_r_r *a,
s2 = gen_load_gpr(dc, a->rs2);
if (cc) {
- tcg_gen_mov_tl(cpu_cc_src, s1);
- tcg_gen_mov_tl(cpu_cc_src2, s2);
- tcg_gen_sub_tl(cpu_cc_dst, s1, s2);
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB);
- dc->cc_op = CC_OP_SUB;
+ gen_op_subcc(cpu_cc_N, s1, s2);
+ tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
+ dc->cc_op = CC_OP_FLAGS;
}
/*
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 07/20] target/sparc: Remove CC_OP_TADDTV, CC_OP_TSUBTV
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (5 preceding siblings ...)
2023-10-17 6:40 ` [PATCH 06/20] target/sparc: Remove CC_OP_SUB, CC_OP_SUBX, CC_OP_TSUB Richard Henderson
@ 2023-10-17 6:40 ` Richard Henderson
2023-10-17 6:40 ` [PATCH 08/20] target/sparc: Remove CC_OP leftovers Richard Henderson
` (12 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:40 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/cpu.h | 2 -
target/sparc/cc_helper.c | 267 +--------------------------------------
target/sparc/helper.c | 40 ++++--
target/sparc/translate.c | 4 +-
4 files changed, 32 insertions(+), 281 deletions(-)
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 8498bd07db..27f7fed293 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -150,8 +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_TADDTV, /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
- CC_OP_TSUBTV, /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
CC_OP_NB,
};
diff --git a/target/sparc/cc_helper.c b/target/sparc/cc_helper.c
index d31aa24b5d..cebe03ff51 100644
--- a/target/sparc/cc_helper.c
+++ b/target/sparc/cc_helper.c
@@ -21,275 +21,12 @@
#include "cpu.h"
#include "exec/helper-proto.h"
-static inline uint32_t get_NZ_icc(int32_t dst)
-{
- uint32_t ret = 0;
-
- if (dst == 0) {
- ret = PSR_ZERO;
- } else if (dst < 0) {
- ret = PSR_NEG;
- }
- return ret;
-}
-
-#ifdef TARGET_SPARC64
-static inline uint32_t get_NZ_xcc(target_long dst)
-{
- uint32_t ret = 0;
-
- if (!dst) {
- ret = PSR_ZERO;
- } else if (dst < 0) {
- ret = PSR_NEG;
- }
- return ret;
-}
-#endif
-
-static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
-{
- uint32_t ret = 0;
-
- if (dst < src1) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-#ifdef TARGET_SPARC64
-static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
-{
- uint32_t ret = 0;
-
- if (dst < src1) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_add_xcc(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_add_xcc(CC_DST, CC_SRC);
- ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_add_xcc(CPUSPARCState *env)
-{
- return get_C_add_xcc(CC_DST, CC_SRC);
-}
-#endif
-
-static uint32_t compute_C_add(CPUSPARCState *env)
-{
- return get_C_add_icc(CC_DST, CC_SRC);
-}
-
-static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
-{
- uint32_t ret = 0;
-
- if ((src1 | src2) & 0x3) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_taddtv(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_add_icc(CC_DST, CC_SRC);
- return ret;
-}
-
-static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (src1 < src2) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-
-#ifdef TARGET_SPARC64
-static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (src1 < src2) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_sub_xcc(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
- ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_sub_xcc(CPUSPARCState *env)
-{
- return get_C_sub_xcc(CC_SRC, CC_SRC2);
-}
-#endif
-
-static uint32_t compute_C_sub(CPUSPARCState *env)
-{
- return get_C_sub_icc(CC_SRC, CC_SRC2);
-}
-
-static uint32_t compute_all_tsubtv(CPUSPARCState *env)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
- return ret;
-}
-
-typedef struct CCTable {
- uint32_t (*compute_all)(CPUSPARCState *env); /* return all the flags */
- uint32_t (*compute_c)(CPUSPARCState *env); /* return the C flag */
-} CCTable;
-
-static const CCTable icc_table[CC_OP_NB] = {
- /* CC_OP_DYNAMIC should never happen */
- [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
- [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
-};
-
-#ifdef TARGET_SPARC64
-static const CCTable xcc_table[CC_OP_NB] = {
- /* CC_OP_DYNAMIC should never happen */
- [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
- [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
-};
-#endif
-
void helper_compute_psr(CPUSPARCState *env)
{
if (CC_OP == CC_OP_FLAGS) {
return;
}
-
- uint32_t icc = icc_table[CC_OP].compute_all(env);
-#ifdef TARGET_SPARC64
- uint32_t xcc = xcc_table[CC_OP].compute_all(env);
-
- env->cc_N = deposit64(-(icc & PSR_NEG), 32, 32, -(xcc & PSR_NEG));
- env->cc_V = deposit64(-(icc & PSR_OVF), 32, 32, -(xcc & PSR_OVF));
- env->cc_icc_C = (uint64_t)icc << (32 - PSR_CARRY_SHIFT);
- env->cc_xcc_C = (xcc >> PSR_CARRY_SHIFT) & 1;
- env->cc_xcc_Z = ~xcc & PSR_ZERO;
-#else
- env->cc_N = -(icc & PSR_NEG);
- env->cc_V = -(icc & PSR_OVF);
- env->cc_icc_C = (icc >> PSR_CARRY_SHIFT) & 1;
-#endif
- env->cc_icc_Z = ~icc & PSR_ZERO;
-
- CC_OP = CC_OP_FLAGS;
+ g_assert_not_reached();
}
uint32_t helper_compute_C_icc(CPUSPARCState *env)
@@ -301,5 +38,5 @@ uint32_t helper_compute_C_icc(CPUSPARCState *env)
return env->cc_icc_C;
#endif
}
- return icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT;
+ g_assert_not_reached();
}
diff --git a/target/sparc/helper.c b/target/sparc/helper.c
index 87a4258792..4887f295a5 100644
--- a/target/sparc/helper.c
+++ b/target/sparc/helper.c
@@ -204,7 +204,7 @@ uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
target_ulong src2)
{
- target_ulong dst;
+ target_ulong dst, v;
/* Tag overflow occurs if either input has bits 0 or 1 set. */
if ((src1 | src2) & 3) {
@@ -214,15 +214,23 @@ target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
dst = src1 + src2;
/* Tag overflow occurs if the addition overflows. */
- if (~(src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
+ v = ~(src1 ^ src2) & (src1 ^ dst);
+ if (v & (1u << 31)) {
goto tag_overflow;
}
/* Only modify the CC after any exceptions have been generated. */
- env->cc_op = CC_OP_TADDTV;
- env->cc_src = src1;
- env->cc_src2 = src2;
- env->cc_dst = dst;
+ env->cc_V = v;
+ env->cc_N = dst;
+ env->cc_icc_Z = dst;
+#ifdef TARGET_SPARC64
+ env->cc_xcc_Z = dst;
+ env->cc_icc_C = dst ^ src1 ^ src2;
+ env->cc_xcc_C = dst < src1;
+#else
+ env->cc_icc_C = dst < src1;
+#endif
+
return dst;
tag_overflow:
@@ -232,7 +240,7 @@ target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
target_ulong src2)
{
- target_ulong dst;
+ target_ulong dst, v;
/* Tag overflow occurs if either input has bits 0 or 1 set. */
if ((src1 | src2) & 3) {
@@ -242,15 +250,23 @@ target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
dst = src1 - src2;
/* Tag overflow occurs if the subtraction overflows. */
- if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
+ v = (src1 ^ src2) & (src1 ^ dst);
+ if (v & (1u << 31)) {
goto tag_overflow;
}
/* Only modify the CC after any exceptions have been generated. */
- env->cc_op = CC_OP_TSUBTV;
- env->cc_src = src1;
- env->cc_src2 = src2;
- env->cc_dst = dst;
+ env->cc_V = v;
+ env->cc_N = dst;
+ env->cc_icc_Z = dst;
+#ifdef TARGET_SPARC64
+ env->cc_xcc_Z = dst;
+ env->cc_icc_C = dst ^ src1 ^ src2;
+ env->cc_xcc_C = src1 < src2;
+#else
+ env->cc_icc_C = src1 < src2;
+#endif
+
return dst;
tag_overflow:
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index ff523a4e7d..d8cb669592 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -3700,8 +3700,8 @@ 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_flags_arith, a, CC_OP_FLAGS, gen_op_taddcc)
TRANS(TSUBcc, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_tsubcc)
-TRANS(TADDccTV, ALL, do_flags_arith, a, CC_OP_TADDTV, gen_op_taddcctv)
-TRANS(TSUBccTV, ALL, do_flags_arith, a, CC_OP_TSUBTV, gen_op_tsubcctv)
+TRANS(TADDccTV, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_taddcctv)
+TRANS(TSUBccTV, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_tsubcctv)
static TCGv gen_rs2_or_imm(DisasContext *dc, bool imm, int rs2_or_imm)
{
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 08/20] target/sparc: Remove CC_OP leftovers
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (6 preceding siblings ...)
2023-10-17 6:40 ` [PATCH 07/20] target/sparc: Remove CC_OP_TADDTV, CC_OP_TSUBTV Richard Henderson
@ 2023-10-17 6:40 ` Richard Henderson
2023-10-17 6:40 ` [PATCH 09/20] target/sparc: Remove DisasCompare.is_bool Richard Henderson
` (11 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:40 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
All instructions have been converted to generate
full condition codes explicitly.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/cpu.h | 21 -------
target/sparc/helper.h | 2 -
linux-user/sparc/cpu_loop.c | 5 --
target/sparc/cc_helper.c | 42 -------------
target/sparc/cpu.c | 1 -
target/sparc/int32_helper.c | 5 --
target/sparc/int64_helper.c | 5 --
target/sparc/translate.c | 120 +++++++-----------------------------
target/sparc/win_helper.c | 7 ---
target/sparc/meson.build | 1 -
10 files changed, 22 insertions(+), 187 deletions(-)
delete mode 100644 target/sparc/cc_helper.c
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 27f7fed293..855ac8b59f 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -137,22 +137,6 @@ enum {
#define PSR_CWP 0x1f
#endif
-#define CC_SRC (env->cc_src)
-#define CC_SRC2 (env->cc_src2)
-#define CC_DST (env->cc_dst)
-#define CC_OP (env->cc_op)
-
-/* Even though lazy evaluation of CPU condition codes tends to be less
- * important on RISC systems where condition codes are only updated
- * when explicitly requested, SPARC uses it to update 32-bit and 64-bit
- * condition codes.
- */
-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_NB,
-};
-
/* Trap base register */
#define TBR_BASE_MASK 0xfffff000
@@ -474,11 +458,6 @@ struct CPUArchState {
target_ulong cc_xcc_C;
#endif
- /* emulator internal flags handling */
- target_ulong cc_src, cc_src2;
- target_ulong cc_dst;
- uint32_t cc_op;
-
target_ulong cond; /* conditional branch result (XXX: save it in a
temporary register when possible) */
diff --git a/target/sparc/helper.h b/target/sparc/helper.h
index 58d3c979d4..6415942e03 100644
--- a/target/sparc/helper.h
+++ b/target/sparc/helper.h
@@ -150,5 +150,3 @@ VIS_CMPHELPER(cmpne)
#undef F_HELPER_0_1
#undef VIS_HELPER
#undef VIS_CMPHELPER
-DEF_HELPER_1(compute_psr, void, env)
-DEF_HELPER_FLAGS_1(compute_C_icc, TCG_CALL_NO_WG_SE, i32, env)
diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c
index a2086afada..e4d66cbbac 100644
--- a/linux-user/sparc/cpu_loop.c
+++ b/linux-user/sparc/cpu_loop.c
@@ -234,11 +234,6 @@ void cpu_loop (CPUSPARCState *env)
cpu_exec_end(cs);
process_queued_cpu_work(cs);
- /* Compute PSR before exposing state. */
- if (env->cc_op != CC_OP_FLAGS) {
- cpu_get_psr(env);
- }
-
switch (trapnr) {
case TARGET_TT_SYSCALL:
ret = do_syscall (env, env->gregs[1],
diff --git a/target/sparc/cc_helper.c b/target/sparc/cc_helper.c
deleted file mode 100644
index cebe03ff51..0000000000
--- a/target/sparc/cc_helper.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Helpers for lazy condition code handling
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "exec/helper-proto.h"
-
-void helper_compute_psr(CPUSPARCState *env)
-{
- if (CC_OP == CC_OP_FLAGS) {
- return;
- }
- g_assert_not_reached();
-}
-
-uint32_t helper_compute_C_icc(CPUSPARCState *env)
-{
- if (CC_OP == CC_OP_FLAGS) {
-#ifdef TARGET_SPARC64
- return extract64(env->cc_icc_C, 32, 1);
-#else
- return env->cc_icc_C;
-#endif
- }
- g_assert_not_reached();
-}
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index 0a3882653c..3980c2d3ca 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -46,7 +46,6 @@ static void sparc_cpu_reset_hold(Object *obj)
env->wim = 1;
#endif
env->regwptr = env->regbase + (env->cwp * 16);
- CC_OP = CC_OP_FLAGS;
#if defined(CONFIG_USER_ONLY)
#ifdef TARGET_SPARC64
env->cleanwin = env->nwindows - 2;
diff --git a/target/sparc/int32_helper.c b/target/sparc/int32_helper.c
index 82e8418e46..1563613582 100644
--- a/target/sparc/int32_helper.c
+++ b/target/sparc/int32_helper.c
@@ -103,11 +103,6 @@ void sparc_cpu_do_interrupt(CPUState *cs)
CPUSPARCState *env = &cpu->env;
int cwp, intno = cs->exception_index;
- /* Compute PSR before exposing state. */
- if (env->cc_op != CC_OP_FLAGS) {
- cpu_get_psr(env);
- }
-
if (qemu_loglevel_mask(CPU_LOG_INT)) {
static int count;
const char *name;
diff --git a/target/sparc/int64_helper.c b/target/sparc/int64_helper.c
index 793e57c536..1b4155f5f3 100644
--- a/target/sparc/int64_helper.c
+++ b/target/sparc/int64_helper.c
@@ -135,11 +135,6 @@ void sparc_cpu_do_interrupt(CPUState *cs)
int intno = cs->exception_index;
trap_state *tsptr;
- /* Compute PSR before exposing state. */
- if (env->cc_op != CC_OP_FLAGS) {
- cpu_get_psr(env);
- }
-
#ifdef DEBUG_PCALL
if (qemu_loglevel_mask(CPU_LOG_INT)) {
static int count;
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index d8cb669592..5c0b6b2764 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -116,8 +116,6 @@ static void gen_helper_array8(TCGv r, TCGv a, TCGv b)
/* global register indexes */
static TCGv_ptr cpu_regwptr;
-static TCGv cpu_cc_src, cpu_cc_src2, cpu_cc_dst;
-static TCGv_i32 cpu_cc_op;
static TCGv cpu_fsr, cpu_pc, cpu_npc;
static TCGv cpu_regs[32];
static TCGv cpu_y;
@@ -175,7 +173,6 @@ typedef struct DisasContext {
#endif
#endif
- uint32_t cc_op; /* current CC operation */
sparc_def_t *def;
#ifdef TARGET_SPARC64
int fprs_dirty;
@@ -900,14 +897,6 @@ static void save_npc(DisasContext *dc)
}
}
-static void update_psr(DisasContext *dc)
-{
- if (dc->cc_op != CC_OP_FLAGS) {
- dc->cc_op = CC_OP_FLAGS;
- gen_helper_compute_psr(tcg_env);
- }
-}
-
static void save_state(DisasContext *dc)
{
tcg_gen_movi_tl(cpu_pc, dc->pc);
@@ -989,17 +978,6 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
TCGv t1, t2;
cmp->is_bool = false;
-
- switch (dc->cc_op) {
- default:
- gen_helper_compute_psr(tcg_env);
- dc->cc_op = CC_OP_FLAGS;
- break;
-
- case CC_OP_FLAGS:
- break;
- }
-
cmp->c1 = NULL;
cmp->c2 = tcg_constant_tl(0);
@@ -2657,7 +2635,6 @@ TRANS(RDASR17, ASR17, do_rd_special, true, a->rd, do_rd_leon3_config)
static TCGv do_rdccr(DisasContext *dc, TCGv dst)
{
- update_psr(dc);
gen_helper_rdccr(dst, tcg_env);
return dst;
}
@@ -2800,7 +2777,6 @@ TRANS(RDSTRAND_STATUS, HYPV, do_rd_special, true, a->rd, do_rdstrand_status)
static TCGv do_rdpsr(DisasContext *dc, TCGv dst)
{
- update_psr(dc);
gen_helper_rdpsr(dst, tcg_env);
return dst;
}
@@ -3261,8 +3237,6 @@ TRANS(WRPOWERDOWN, POWERDOWN, do_wr_special, a, supervisor(dc), do_wrpowerdown)
static void do_wrpsr(DisasContext *dc, TCGv src)
{
gen_helper_wrpsr(tcg_env, src);
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
- dc->cc_op = CC_OP_FLAGS;
save_state(dc);
gen_op_next_insn();
tcg_gen_exit_tb(NULL, 0);
@@ -3571,9 +3545,10 @@ static bool trans_NOP_v9(DisasContext *dc, arg_NOP_v9 *a)
return false;
}
-static bool do_cc_arith(DisasContext *dc, arg_r_r_ri *a, int cc_op,
- void (*func)(TCGv, TCGv, TCGv),
- void (*funci)(TCGv, TCGv, target_long))
+static bool do_arith_int(DisasContext *dc, arg_r_r_ri *a,
+ void (*func)(TCGv, TCGv, TCGv),
+ void (*funci)(TCGv, TCGv, target_long),
+ bool logic_cc)
{
TCGv dst, src1;
@@ -3582,14 +3557,10 @@ static bool do_cc_arith(DisasContext *dc, arg_r_r_ri *a, int cc_op,
return false;
}
- if (cc_op < 0) {
- dst = gen_dest_gpr(dc, a->rd);
- } else if (cc_op == CC_OP_FLAGS) {
+ if (logic_cc) {
dst = cpu_cc_N;
} else {
- dst = cpu_cc_dst;
- tcg_gen_movi_i32(cpu_cc_op, cc_op);
- dc->cc_op = cc_op;
+ dst = gen_dest_gpr(dc, a->rd);
}
src1 = gen_load_gpr(dc, a->rs1);
@@ -3603,8 +3574,7 @@ static bool do_cc_arith(DisasContext *dc, arg_r_r_ri *a, int cc_op,
func(dst, src1, cpu_regs[a->rs2_or_imm]);
}
- /* Logic insn; to be cleaned up later. */
- if (cc_op == CC_OP_FLAGS) {
+ if (logic_cc) {
tcg_gen_movi_tl(cpu_cc_V, 0);
tcg_gen_movi_tl(cpu_icc_C, 0);
#ifdef TARGET_SPARC64
@@ -3612,9 +3582,6 @@ static bool do_cc_arith(DisasContext *dc, arg_r_r_ri *a, int cc_op,
tcg_gen_mov_tl(cpu_xcc_Z, dst);
#endif
tcg_gen_mov_tl(cpu_icc_Z, dst);
-
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
- dc->cc_op = CC_OP_FLAGS;
}
gen_store_gpr(dc, a->rd, dst);
@@ -3625,25 +3592,14 @@ static bool do_arith(DisasContext *dc, arg_r_r_ri *a,
void (*func)(TCGv, TCGv, TCGv),
void (*funci)(TCGv, TCGv, target_long))
{
- return do_cc_arith(dc, a, -1, func, funci);
-}
-
-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)) {
- tcg_gen_movi_i32(cpu_cc_op, cc_op);
- dc->cc_op = cc_op;
- return true;
- }
- return false;
+ return do_arith_int(dc, a, func, funci, false);
}
static bool do_logic_cc(DisasContext *dc, arg_r_r_ri *a,
void (*func)(TCGv, TCGv, TCGv),
void (*funci)(TCGv, TCGv, target_long))
{
- return do_cc_arith(dc, a, CC_OP_FLAGS, func, funci);
+ return do_arith_int(dc, a, func, funci, true);
}
static bool trans_OR(DisasContext *dc, arg_r_r_ri *a)
@@ -3683,25 +3639,30 @@ TRANS(UDIVX, 64, do_arith, a, gen_op_udivx, NULL)
TRANS(SDIVX, 64, do_arith, a, gen_op_sdivx, NULL)
TRANS(UDIV, DIV, do_arith, a, gen_op_udiv, NULL)
TRANS(SDIV, DIV, do_arith, a, gen_op_sdiv, NULL)
+TRANS(ADDC, ALL, do_arith, a, gen_op_addc, NULL)
+TRANS(SUBC, ALL, do_arith, a, gen_op_subc, NULL)
/* TODO: Should have feature bit -- comes in with UltraSparc T2. */
TRANS(POPC, 64, do_arith, a, gen_op_popc, NULL)
-TRANS(ADDcc, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_addcc)
+TRANS(ADDcc, ALL, do_arith, a, gen_op_addcc, NULL)
TRANS(ANDcc, ALL, do_logic_cc, a, tcg_gen_and_tl, tcg_gen_andi_tl)
TRANS(ORcc, ALL, do_logic_cc, a, tcg_gen_or_tl, tcg_gen_ori_tl)
TRANS(XORcc, ALL, do_logic_cc, a, tcg_gen_xor_tl, tcg_gen_xori_tl)
-TRANS(SUBcc, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_subcc)
+TRANS(SUBcc, ALL, do_arith, a, gen_op_subcc, NULL)
TRANS(ANDNcc, ALL, do_logic_cc, a, tcg_gen_andc_tl, NULL)
TRANS(ORNcc, ALL, do_logic_cc, a, tcg_gen_orc_tl, NULL)
TRANS(XORNcc, ALL, do_logic_cc, a, tcg_gen_eqv_tl, NULL)
TRANS(UMULcc, MUL, do_logic_cc, a, gen_op_umul, NULL)
TRANS(SMULcc, MUL, do_logic_cc, a, gen_op_smul, NULL)
-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_flags_arith, a, CC_OP_FLAGS, gen_op_taddcc)
-TRANS(TSUBcc, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_tsubcc)
-TRANS(TADDccTV, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_taddcctv)
-TRANS(TSUBccTV, ALL, do_flags_arith, a, CC_OP_FLAGS, gen_op_tsubcctv)
+TRANS(UDIVcc, DIV, do_arith, a, gen_op_udivcc, NULL)
+TRANS(SDIVcc, DIV, do_arith, a, gen_op_sdivcc, NULL)
+TRANS(TADDcc, ALL, do_arith, a, gen_op_taddcc, NULL)
+TRANS(TSUBcc, ALL, do_arith, a, gen_op_tsubcc, NULL)
+TRANS(TADDccTV, ALL, do_arith, a, gen_op_taddcctv, NULL)
+TRANS(TSUBccTV, ALL, do_arith, a, gen_op_tsubcctv, NULL)
+TRANS(ADDCcc, ALL, do_arith, a, gen_op_addccc, NULL)
+TRANS(SUBCcc, ALL, do_arith, a, gen_op_subccc, NULL)
+TRANS(MULScc, ALL, do_arith, a, gen_op_mulscc, NULL)
static TCGv gen_rs2_or_imm(DisasContext *dc, bool imm, int rs2_or_imm)
{
@@ -3716,36 +3677,6 @@ static TCGv gen_rs2_or_imm(DisasContext *dc, bool imm, int rs2_or_imm)
}
}
-static bool trans_ADDC(DisasContext *dc, arg_r_r_ri *a)
-{
- update_psr(dc);
- return do_arith(dc, a, gen_op_addc, NULL);
-}
-
-static bool trans_ADDCcc(DisasContext *dc, arg_r_r_ri *a)
-{
- update_psr(dc);
- return do_flags_arith(dc, a, CC_OP_FLAGS, gen_op_addccc);
-}
-
-static bool trans_SUBC(DisasContext *dc, arg_r_r_ri *a)
-{
- update_psr(dc);
- return do_arith(dc, a, gen_op_subc, NULL);
-}
-
-static bool trans_SUBCcc(DisasContext *dc, arg_r_r_ri *a)
-{
- update_psr(dc);
- return do_flags_arith(dc, a, CC_OP_FLAGS, gen_op_subccc);
-}
-
-static bool trans_MULScc(DisasContext *dc, arg_r_r_ri *a)
-{
- update_psr(dc);
- return do_flags_arith(dc, a, CC_OP_FLAGS, gen_op_mulscc);
-}
-
static bool gen_edge(DisasContext *dc, arg_r_r_r *a,
int width, bool cc, bool left)
{
@@ -3759,8 +3690,6 @@ static bool gen_edge(DisasContext *dc, arg_r_r_r *a,
if (cc) {
gen_op_subcc(cpu_cc_N, s1, s2);
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
- dc->cc_op = CC_OP_FLAGS;
}
/*
@@ -5176,7 +5105,6 @@ static void sparc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
dc->pc = dc->base.pc_first;
dc->npc = (target_ulong)dc->base.tb->cs_base;
- dc->cc_op = CC_OP_DYNAMIC;
dc->mem_idx = dc->base.tb->flags & TB_FLAG_MMU_MASK;
dc->def = &env->def;
dc->fpu_enabled = tb_fpu_enabled(dc->base.tb->flags);
@@ -5371,7 +5299,6 @@ void sparc_tcg_init(void)
#else
{ &cpu_wim, offsetof(CPUSPARCState, wim), "wim" },
#endif
- { &cpu_cc_op, offsetof(CPUSPARCState, cc_op), "cc_op" },
};
static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {
@@ -5394,9 +5321,6 @@ void sparc_tcg_init(void)
{ &cpu_icc_Z, offsetof(CPUSPARCState, cc_icc_Z), "icc_Z" },
{ &cpu_icc_C, offsetof(CPUSPARCState, cc_icc_C), "icc_C" },
{ &cpu_cond, offsetof(CPUSPARCState, cond), "cond" },
- { &cpu_cc_src, offsetof(CPUSPARCState, cc_src), "cc_src" },
- { &cpu_cc_src2, offsetof(CPUSPARCState, cc_src2), "cc_src2" },
- { &cpu_cc_dst, offsetof(CPUSPARCState, cc_dst), "cc_dst" },
{ &cpu_fsr, offsetof(CPUSPARCState, fsr), "fsr" },
{ &cpu_pc, offsetof(CPUSPARCState, pc), "pc" },
{ &cpu_npc, offsetof(CPUSPARCState, npc), "npc" },
diff --git a/target/sparc/win_helper.c b/target/sparc/win_helper.c
index a446c1785d..64e498ce2b 100644
--- a/target/sparc/win_helper.c
+++ b/target/sparc/win_helper.c
@@ -55,8 +55,6 @@ target_ulong cpu_get_psr(CPUSPARCState *env)
{
target_ulong icc = 0;
- helper_compute_psr(env);
-
icc |= ((int32_t)env->cc_N < 0) << PSR_NEG_SHIFT;
icc |= ((int32_t)env->cc_V < 0) << PSR_OVF_SHIFT;
icc |= ((int32_t)env->cc_icc_Z == 0) << PSR_ZERO_SHIFT;
@@ -102,7 +100,6 @@ void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val)
env->psrps = (val & PSR_PS) ? 1 : 0;
env->psret = (val & PSR_ET) ? 1 : 0;
#endif
- env->cc_op = CC_OP_FLAGS;
#if !defined(TARGET_SPARC64)
cpu_set_cwp(env, val & PSR_CWP);
#endif
@@ -271,8 +268,6 @@ target_ulong cpu_get_ccr(CPUSPARCState *env)
{
target_ulong ccr = 0;
- helper_compute_psr(env);
-
ccr |= (env->cc_icc_C >> 32) & 1;
ccr |= ((int32_t)env->cc_V < 0) << 1;
ccr |= ((int32_t)env->cc_icc_Z == 0) << 2;
@@ -294,8 +289,6 @@ void cpu_put_ccr(CPUSPARCState *env, target_ulong val)
env->cc_xcc_C = (val >> 4) & 1;
env->cc_icc_Z = ~val & 0x04;
env->cc_xcc_Z = ~val & 0x40;
-
- CC_OP = CC_OP_FLAGS;
}
target_ulong cpu_get_cwp64(CPUSPARCState *env)
diff --git a/target/sparc/meson.build b/target/sparc/meson.build
index c316773db6..46289c8669 100644
--- a/target/sparc/meson.build
+++ b/target/sparc/meson.build
@@ -3,7 +3,6 @@ gen = decodetree.process('insns.decode')
sparc_ss = ss.source_set()
sparc_ss.add(gen)
sparc_ss.add(files(
- 'cc_helper.c',
'cpu.c',
'fop_helper.c',
'gdbstub.c',
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 09/20] target/sparc: Remove DisasCompare.is_bool
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (7 preceding siblings ...)
2023-10-17 6:40 ` [PATCH 08/20] target/sparc: Remove CC_OP leftovers Richard Henderson
@ 2023-10-17 6:40 ` Richard Henderson
2023-10-17 6:40 ` [PATCH 10/20] target/sparc: Change DisasCompare.c2 to int Richard Henderson
` (10 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:40 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Since we're going to feed cpu_cond to another comparison, we don't
reqire a boolean value -- anything non-zero is sufficient.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/translate.c | 22 +++++++---------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 5c0b6b2764..a8933d2fc3 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -183,7 +183,6 @@ typedef struct DisasContext {
typedef struct {
TCGCond cond;
- bool is_bool;
TCGv c1, c2;
} DisasCompare;
@@ -977,7 +976,6 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
{
TCGv t1, t2;
- cmp->is_bool = false;
cmp->c1 = NULL;
cmp->c2 = tcg_constant_tl(0);
@@ -1040,7 +1038,6 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
case 0x5: /* ltu: C */
cmp->cond = TCG_COND_NE;
- cmp->is_bool = true;
if (TARGET_LONG_BITS == 32 || xcc) {
cmp->c1 = cpu_cc_C;
} else {
@@ -1071,7 +1068,6 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
}
if (cond & 8) {
cmp->cond = tcg_invert_cond(cmp->cond);
- cmp->is_bool = false;
}
}
@@ -1082,7 +1078,6 @@ static void gen_fcompare(DisasCompare *cmp, unsigned int cc, unsigned int cond)
/* For now we still generate a straight boolean result. */
cmp->cond = TCG_COND_NE;
- cmp->is_bool = true;
cmp->c1 = r_dst = tcg_temp_new();
cmp->c2 = tcg_constant_tl(0);
@@ -1169,7 +1164,6 @@ static const TCGCond gen_tcg_cond_reg[8] = {
static void gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src)
{
cmp->cond = tcg_invert_cond(gen_tcg_cond_reg[cond]);
- cmp->is_bool = false;
cmp->c1 = r_src;
cmp->c2 = tcg_constant_tl(0);
}
@@ -2155,18 +2149,14 @@ static void gen_fmovs(DisasContext *dc, DisasCompare *cmp, int rd, int rs)
{
#ifdef TARGET_SPARC64
TCGv_i32 c32, zero, dst, s1, s2;
+ TCGv_i64 c64 = tcg_temp_new_i64();
/* We have two choices here: extend the 32 bit data and use movcond_i64,
or fold the comparison down to 32 bits and use movcond_i32. Choose
the later. */
c32 = tcg_temp_new_i32();
- if (cmp->is_bool) {
- tcg_gen_extrl_i64_i32(c32, cmp->c1);
- } else {
- TCGv_i64 c64 = tcg_temp_new_i64();
- tcg_gen_setcond_i64(cmp->cond, c64, cmp->c1, cmp->c2);
- tcg_gen_extrl_i64_i32(c32, c64);
- }
+ tcg_gen_setcond_i64(cmp->cond, c64, cmp->c1, cmp->c2);
+ tcg_gen_extrl_i64_i32(c32, c64);
s1 = gen_load_fpr_F(dc, rs);
s2 = gen_load_fpr_F(dc, rd);
@@ -2359,8 +2349,10 @@ static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
dc->jump_pc[0] = dest;
dc->jump_pc[1] = npc + 4;
dc->npc = JUMP_PC;
- if (cmp->is_bool) {
- tcg_gen_mov_tl(cpu_cond, cmp->c1);
+
+ /* The condition for cpu_cond is always NE -- normalize. */
+ if (cmp->cond == TCG_COND_NE) {
+ tcg_gen_sub_tl(cpu_cond, cmp->c1, cmp->c2);
} else {
tcg_gen_setcond_tl(cmp->cond, cpu_cond, cmp->c1, cmp->c2);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 10/20] target/sparc: Change DisasCompare.c2 to int
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (8 preceding siblings ...)
2023-10-17 6:40 ` [PATCH 09/20] target/sparc: Remove DisasCompare.is_bool Richard Henderson
@ 2023-10-17 6:40 ` Richard Henderson
2023-10-17 6:41 ` [PATCH 11/20] target/sparc: Always copy conditions into a new temporary Richard Henderson
` (9 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:40 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
We don't require c2 to be variable, so emphasize that.
We don't currently require c2 to be non-zero, but that will change.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/translate.c | 40 ++++++++++++++++++++++------------------
1 file changed, 22 insertions(+), 18 deletions(-)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index a8933d2fc3..32d29f16b5 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -183,7 +183,8 @@ typedef struct DisasContext {
typedef struct {
TCGCond cond;
- TCGv c1, c2;
+ TCGv c1;
+ int c2;
} DisasCompare;
// This function uses non-native bit order
@@ -974,15 +975,15 @@ static void gen_op_next_insn(void)
static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
DisasContext *dc)
{
- TCGv t1, t2;
+ TCGv t1, t2, zero;
cmp->c1 = NULL;
- cmp->c2 = tcg_constant_tl(0);
+ cmp->c2 = 0;
switch (cond & 7) {
case 0x0: /* never */
cmp->cond = TCG_COND_NEVER;
- cmp->c1 = cmp->c2;
+ cmp->c1 = tcg_constant_tl(0);
break;
case 0x1: /* eq */
@@ -998,11 +999,12 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
case 0x2: /* le: Z | (N ^ V) */
cmp->cond = TCG_COND_LT;
cmp->c1 = t1 = tcg_temp_new();
+ zero = tcg_constant_tl(0);
if (TARGET_LONG_BITS == 32 || xcc) {
- tcg_gen_negsetcond_tl(TCG_COND_EQ, t1, cpu_cc_Z, cmp->c2);
+ tcg_gen_negsetcond_tl(TCG_COND_EQ, t1, cpu_cc_Z, zero);
} else {
tcg_gen_ext32u_tl(t1, cpu_icc_Z);
- tcg_gen_negsetcond_tl(TCG_COND_EQ, t1, t1, cmp->c2);
+ tcg_gen_negsetcond_tl(TCG_COND_EQ, t1, t1, zero);
}
t2 = tcg_temp_new();
tcg_gen_xor_tl(t2, cpu_cc_N, cpu_cc_V);
@@ -1079,7 +1081,7 @@ static void gen_fcompare(DisasCompare *cmp, unsigned int cc, unsigned int cond)
/* For now we still generate a straight boolean result. */
cmp->cond = TCG_COND_NE;
cmp->c1 = r_dst = tcg_temp_new();
- cmp->c2 = tcg_constant_tl(0);
+ cmp->c2 = 0;
switch (cc) {
default:
@@ -1165,7 +1167,7 @@ static void gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src)
{
cmp->cond = tcg_invert_cond(gen_tcg_cond_reg[cond]);
cmp->c1 = r_src;
- cmp->c2 = tcg_constant_tl(0);
+ cmp->c2 = 0;
}
static void gen_op_clear_ieee_excp_and_FTT(void)
@@ -2155,7 +2157,7 @@ static void gen_fmovs(DisasContext *dc, DisasCompare *cmp, int rd, int rs)
or fold the comparison down to 32 bits and use movcond_i32. Choose
the later. */
c32 = tcg_temp_new_i32();
- tcg_gen_setcond_i64(cmp->cond, c64, cmp->c1, cmp->c2);
+ tcg_gen_setcondi_i64(cmp->cond, c64, cmp->c1, cmp->c2);
tcg_gen_extrl_i64_i32(c32, c64);
s1 = gen_load_fpr_F(dc, rs);
@@ -2175,7 +2177,7 @@ static void gen_fmovd(DisasContext *dc, DisasCompare *cmp, int rd, int rs)
{
#ifdef TARGET_SPARC64
TCGv_i64 dst = gen_dest_fpr_D(dc, rd);
- tcg_gen_movcond_i64(cmp->cond, dst, cmp->c1, cmp->c2,
+ tcg_gen_movcond_i64(cmp->cond, dst, cmp->c1, tcg_constant_tl(cmp->c2),
gen_load_fpr_D(dc, rs),
gen_load_fpr_D(dc, rd));
gen_store_fpr_D(dc, rd, dst);
@@ -2189,10 +2191,11 @@ static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs)
#ifdef TARGET_SPARC64
int qd = QFPREG(rd);
int qs = QFPREG(rs);
+ TCGv c2 = tcg_constant_tl(cmp->c2);
- tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2], cmp->c1, cmp->c2,
+ tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2], cmp->c1, c2,
cpu_fpr[qs / 2], cpu_fpr[qd / 2]);
- tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2 + 1], cmp->c1, cmp->c2,
+ tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2 + 1], cmp->c1, c2,
cpu_fpr[qs / 2 + 1], cpu_fpr[qd / 2 + 1]);
gen_update_fprs_dirty(dc, qd);
@@ -2323,7 +2326,7 @@ static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
if (annul) {
TCGLabel *l1 = gen_new_label();
- tcg_gen_brcond_tl(tcg_invert_cond(cmp->cond), cmp->c1, cmp->c2, l1);
+ tcg_gen_brcondi_tl(tcg_invert_cond(cmp->cond), cmp->c1, cmp->c2, l1);
gen_goto_tb(dc, 0, npc, dest);
gen_set_label(l1);
gen_goto_tb(dc, 1, npc + 4, npc + 8);
@@ -2337,7 +2340,7 @@ static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
tcg_gen_mov_tl(cpu_pc, cpu_npc);
tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
tcg_gen_movcond_tl(cmp->cond, cpu_npc,
- cmp->c1, cmp->c2,
+ cmp->c1, tcg_constant_tl(cmp->c2),
tcg_constant_tl(dest), cpu_npc);
dc->pc = npc;
break;
@@ -2352,9 +2355,9 @@ static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
/* The condition for cpu_cond is always NE -- normalize. */
if (cmp->cond == TCG_COND_NE) {
- tcg_gen_sub_tl(cpu_cond, cmp->c1, cmp->c2);
+ tcg_gen_subi_tl(cpu_cond, cmp->c1, cmp->c2);
} else {
- tcg_gen_setcond_tl(cmp->cond, cpu_cond, cmp->c1, cmp->c2);
+ tcg_gen_setcondi_tl(cmp->cond, cpu_cond, cmp->c1, cmp->c2);
}
}
}
@@ -2554,7 +2557,7 @@ static bool trans_Tcc(DisasContext *dc, arg_Tcc *a)
flush_cond(dc);
lab = delay_exceptionv(dc, trap);
gen_compare(&cmp, a->cc, a->cond, dc);
- tcg_gen_brcond_tl(cmp.cond, cmp.c1, cmp.c2, lab);
+ tcg_gen_brcondi_tl(cmp.cond, cmp.c1, cmp.c2, lab);
return advance_pc(dc);
}
@@ -3913,8 +3916,9 @@ TRANS(SRA_i, ALL, do_shift_i, a, false, false)
static bool do_mov_cond(DisasContext *dc, DisasCompare *cmp, int rd, TCGv src2)
{
TCGv dst = gen_load_gpr(dc, rd);
+ TCGv c2 = tcg_constant_tl(cmp->c2);
- tcg_gen_movcond_tl(cmp->cond, dst, cmp->c1, cmp->c2, src2, dst);
+ tcg_gen_movcond_tl(cmp->cond, dst, cmp->c1, c2, src2, dst);
gen_store_gpr(dc, rd, dst);
return advance_pc(dc);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 11/20] target/sparc: Always copy conditions into a new temporary
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (9 preceding siblings ...)
2023-10-17 6:40 ` [PATCH 10/20] target/sparc: Change DisasCompare.c2 to int Richard Henderson
@ 2023-10-17 6:41 ` Richard Henderson
2023-10-17 6:41 ` [PATCH 12/20] target/sparc: Do flush_cond in advance_jump_cond Richard Henderson
` (8 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:41 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
This will allow the condition to live across changes to
the global cc variables.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/translate.c | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 32d29f16b5..a75f75dfb9 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -977,7 +977,7 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
{
TCGv t1, t2, zero;
- cmp->c1 = NULL;
+ cmp->c1 = t1 = tcg_temp_new();
cmp->c2 = 0;
switch (cond & 7) {
@@ -989,16 +989,14 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
case 0x1: /* eq */
cmp->cond = TCG_COND_EQ;
if (TARGET_LONG_BITS == 32 || xcc) {
- cmp->c1 = cpu_cc_Z;
+ tcg_gen_mov_tl(t1, cpu_cc_Z);
} else {
- cmp->c1 = t1 = tcg_temp_new();
tcg_gen_ext32u_tl(t1, cpu_icc_Z);
}
break;
case 0x2: /* le: Z | (N ^ V) */
cmp->cond = TCG_COND_LT;
- cmp->c1 = t1 = tcg_temp_new();
zero = tcg_constant_tl(0);
if (TARGET_LONG_BITS == 32 || xcc) {
tcg_gen_negsetcond_tl(TCG_COND_EQ, t1, cpu_cc_Z, zero);
@@ -1016,7 +1014,6 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
case 0x3: /* lt: N ^ V */
cmp->cond = TCG_COND_LT;
- cmp->c1 = t1 = tcg_temp_new();
tcg_gen_xor_tl(t1, cpu_cc_N, cpu_cc_V);
if (TARGET_LONG_BITS == 64 && !xcc) {
tcg_gen_ext32s_tl(t1, t1);
@@ -1025,7 +1022,6 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
case 0x4: /* leu: C | Z -> !(!C & !Z) */
cmp->cond = TCG_COND_EQ;
- cmp->c1 = t1 = tcg_temp_new();
if (TARGET_LONG_BITS == 32 || xcc) {
tcg_gen_subi_tl(t1, cpu_cc_C, 1);
tcg_gen_and_tl(t1, t1, cpu_cc_Z);
@@ -1041,9 +1037,8 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
case 0x5: /* ltu: C */
cmp->cond = TCG_COND_NE;
if (TARGET_LONG_BITS == 32 || xcc) {
- cmp->c1 = cpu_cc_C;
+ tcg_gen_mov_tl(t1, cpu_cc_C);
} else {
- cmp->c1 = t1 = tcg_temp_new();
tcg_gen_extract_tl(t1, cpu_icc_C, 32, 1);
}
break;
@@ -1051,9 +1046,8 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
case 0x6: /* neg: N */
cmp->cond = TCG_COND_LT;
if (TARGET_LONG_BITS == 32 || xcc) {
- cmp->c1 = cpu_cc_N;
+ tcg_gen_mov_tl(t1, cpu_cc_N);
} else {
- cmp->c1 = t1 = tcg_temp_new();
tcg_gen_ext32s_tl(t1, cpu_cc_N);
}
break;
@@ -1061,9 +1055,8 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
case 0x7: /* vs: V */
cmp->cond = TCG_COND_LT;
if (TARGET_LONG_BITS == 32 || xcc) {
- cmp->c1 = cpu_cc_V;
+ tcg_gen_mov_tl(t1, cpu_cc_V);
} else {
- cmp->c1 = t1 = tcg_temp_new();
tcg_gen_ext32s_tl(t1, cpu_cc_V);
}
break;
@@ -1166,8 +1159,9 @@ static const TCGCond gen_tcg_cond_reg[8] = {
static void gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src)
{
cmp->cond = tcg_invert_cond(gen_tcg_cond_reg[cond]);
- cmp->c1 = r_src;
+ cmp->c1 = tcg_temp_new();
cmp->c2 = 0;
+ tcg_gen_mov_tl(cmp->c1, r_src);
}
static void gen_op_clear_ieee_excp_and_FTT(void)
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 12/20] target/sparc: Do flush_cond in advance_jump_cond
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (10 preceding siblings ...)
2023-10-17 6:41 ` [PATCH 11/20] target/sparc: Always copy conditions into a new temporary Richard Henderson
@ 2023-10-17 6:41 ` Richard Henderson
2023-10-17 6:41 ` [PATCH 13/20] target/sparc: Merge gen_branch2 into advance_pc Richard Henderson
` (7 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:41 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Do this here instead of in each caller.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/translate.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index a75f75dfb9..74a0972bda 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -2317,6 +2317,8 @@ static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
{
target_ulong npc = dc->npc;
+ flush_cond(dc);
+
if (annul) {
TCGLabel *l1 = gen_new_label();
@@ -2392,8 +2394,6 @@ static bool do_bpcc(DisasContext *dc, arg_bcc *a)
case 0x8:
return advance_jump_uncond_always(dc, a->a, target);
default:
- flush_cond(dc);
-
gen_compare(&cmp, a->cc, a->cond, dc);
return advance_jump_cond(dc, &cmp, a->a, target);
}
@@ -2419,8 +2419,6 @@ static bool do_fbpfcc(DisasContext *dc, arg_bcc *a)
case 0x8:
return advance_jump_uncond_always(dc, a->a, target);
default:
- flush_cond(dc);
-
gen_fcompare(&cmp, a->cc, a->cond);
return advance_jump_cond(dc, &cmp, a->a, target);
}
@@ -2446,8 +2444,6 @@ static bool trans_BPr(DisasContext *dc, arg_BPr *a)
target &= 0xffffffffULL;
}
- flush_cond(dc);
-
gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1));
return advance_jump_cond(dc, &cmp, a->a, target);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 13/20] target/sparc: Merge gen_branch2 into advance_pc
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (11 preceding siblings ...)
2023-10-17 6:41 ` [PATCH 12/20] target/sparc: Do flush_cond in advance_jump_cond Richard Henderson
@ 2023-10-17 6:41 ` Richard Henderson
2023-10-17 6:41 ` [PATCH 14/20] target/sparc: Merge advance_jump_uncond_{never, always} into advance_jump_cond Richard Henderson
` (6 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:41 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
The function had only one caller. Canonicalize the cpu_cond
test to TCG_COND_NE, the "natural" sense of its value.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/translate.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 74a0972bda..4c52425702 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -846,19 +846,6 @@ static void gen_op_eval_fbo(TCGv dst, TCGv src, unsigned int fcc_offset)
tcg_gen_xori_tl(dst, dst, 0x1);
}
-static void gen_branch2(DisasContext *dc, target_ulong pc1,
- target_ulong pc2, TCGv r_cond)
-{
- TCGLabel *l1 = gen_new_label();
-
- tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1);
-
- gen_goto_tb(dc, 0, pc1, pc1 + 4);
-
- gen_set_label(l1);
- gen_goto_tb(dc, 1, pc2, pc2 + 4);
-}
-
static void gen_generic_branch(DisasContext *dc)
{
TCGv npc0 = tcg_constant_tl(dc->jump_pc[0]);
@@ -2260,6 +2247,8 @@ static int extract_qfpreg(DisasContext *dc, int x)
/* Default case for non jump instructions. */
static bool advance_pc(DisasContext *dc)
{
+ TCGLabel *l1;
+
if (dc->npc & 3) {
switch (dc->npc) {
case DYNAMIC_PC:
@@ -2267,11 +2256,22 @@ static bool advance_pc(DisasContext *dc)
dc->pc = dc->npc;
gen_op_next_insn();
break;
+
case JUMP_PC:
/* we can do a static jump */
- gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1], cpu_cond);
+ l1 = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_NE, cpu_cond, 0, l1);
+
+ /* jump not taken */
+ gen_goto_tb(dc, 1, dc->jump_pc[1], dc->jump_pc[1] + 4);
+
+ /* jump taken */
+ gen_set_label(l1);
+ gen_goto_tb(dc, 0, dc->jump_pc[0], dc->jump_pc[0] + 4);
+
dc->base.is_jmp = DISAS_NORETURN;
break;
+
default:
g_assert_not_reached();
}
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 14/20] target/sparc: Merge advance_jump_uncond_{never, always} into advance_jump_cond
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (12 preceding siblings ...)
2023-10-17 6:41 ` [PATCH 13/20] target/sparc: Merge gen_branch2 into advance_pc Richard Henderson
@ 2023-10-17 6:41 ` Richard Henderson
2023-10-17 6:41 ` [PATCH 15/20] target/sparc: Use DISAS_EXIT in do_wrpsr Richard Henderson
` (5 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:41 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Handle these via TCG_COND_{ALWAYS,NEVER}.
Allow dc->npc to be variable, using gen_mov_pc_npc.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/translate.c | 73 ++++++++++++++++------------------------
1 file changed, 29 insertions(+), 44 deletions(-)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 4c52425702..53a755874e 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -2286,37 +2286,36 @@ static bool advance_pc(DisasContext *dc)
* Major opcodes 00 and 01 -- branches, call, and sethi
*/
-static bool advance_jump_uncond_never(DisasContext *dc, bool annul)
-{
- if (annul) {
- dc->pc = dc->npc + 4;
- dc->npc = dc->pc + 4;
- } else {
- dc->pc = dc->npc;
- dc->npc = dc->pc + 4;
- }
- return true;
-}
-
-static bool advance_jump_uncond_always(DisasContext *dc, bool annul,
- target_ulong dest)
-{
- if (annul) {
- dc->pc = dest;
- dc->npc = dest + 4;
- } else {
- dc->pc = dc->npc;
- dc->npc = dest;
- tcg_gen_mov_tl(cpu_pc, cpu_npc);
- }
- return true;
-}
-
static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
bool annul, target_ulong dest)
{
target_ulong npc = dc->npc;
+ if (cmp->cond == TCG_COND_ALWAYS) {
+ if (annul) {
+ dc->pc = dest;
+ dc->npc = dest + 4;
+ } else {
+ gen_mov_pc_npc(dc);
+ dc->npc = dest;
+ }
+ return true;
+ }
+
+ if (cmp->cond == TCG_COND_NEVER) {
+ if (npc & 3) {
+ gen_mov_pc_npc(dc);
+ if (annul) {
+ tcg_gen_addi_tl(cpu_pc, cpu_pc, 4);
+ }
+ tcg_gen_addi_tl(cpu_npc, cpu_pc, 4);
+ } else {
+ dc->pc = npc + (annul ? 4 : 0);
+ dc->npc = dc->pc + 4;
+ }
+ return true;
+ }
+
flush_cond(dc);
if (annul) {
@@ -2388,15 +2387,8 @@ static bool do_bpcc(DisasContext *dc, arg_bcc *a)
if (unlikely(AM_CHECK(dc))) {
target &= 0xffffffffULL;
}
- switch (a->cond) {
- case 0x0:
- return advance_jump_uncond_never(dc, a->a);
- case 0x8:
- return advance_jump_uncond_always(dc, a->a, target);
- default:
- gen_compare(&cmp, a->cc, a->cond, dc);
- return advance_jump_cond(dc, &cmp, a->a, target);
- }
+ gen_compare(&cmp, a->cc, a->cond, dc);
+ return advance_jump_cond(dc, &cmp, a->a, target);
}
TRANS(BPcc, 64, do_bpcc, a)
@@ -2413,15 +2405,8 @@ static bool do_fbpfcc(DisasContext *dc, arg_bcc *a)
if (unlikely(AM_CHECK(dc))) {
target &= 0xffffffffULL;
}
- switch (a->cond) {
- case 0x0:
- return advance_jump_uncond_never(dc, a->a);
- case 0x8:
- return advance_jump_uncond_always(dc, a->a, target);
- default:
- gen_fcompare(&cmp, a->cc, a->cond);
- return advance_jump_cond(dc, &cmp, a->a, target);
- }
+ gen_fcompare(&cmp, a->cc, a->cond);
+ return advance_jump_cond(dc, &cmp, a->a, target);
}
TRANS(FBPfcc, 64, do_fbpfcc, a)
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 15/20] target/sparc: Use DISAS_EXIT in do_wrpsr
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (13 preceding siblings ...)
2023-10-17 6:41 ` [PATCH 14/20] target/sparc: Merge advance_jump_uncond_{never, always} into advance_jump_cond Richard Henderson
@ 2023-10-17 6:41 ` Richard Henderson
2023-10-17 6:41 ` [PATCH 16/20] target/sparc: Merge gen_op_next_insn into only caller Richard Henderson
` (4 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:41 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/translate.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 53a755874e..18546d3bd2 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -3207,10 +3207,7 @@ TRANS(WRPOWERDOWN, POWERDOWN, do_wr_special, a, supervisor(dc), do_wrpowerdown)
static void do_wrpsr(DisasContext *dc, TCGv src)
{
gen_helper_wrpsr(tcg_env, src);
- save_state(dc);
- gen_op_next_insn();
- tcg_gen_exit_tb(NULL, 0);
- dc->base.is_jmp = DISAS_NORETURN;
+ dc->base.is_jmp = DISAS_EXIT;
}
TRANS(WRPSR, 32, do_wr_special, a, supervisor(dc), do_wrpsr)
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 16/20] target/sparc: Merge gen_op_next_insn into only caller
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (14 preceding siblings ...)
2023-10-17 6:41 ` [PATCH 15/20] target/sparc: Use DISAS_EXIT in do_wrpsr Richard Henderson
@ 2023-10-17 6:41 ` Richard Henderson
2023-10-17 6:41 ` [PATCH 17/20] target/sparc: Record entire jump condition in DisasContext Richard Henderson
` (3 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:41 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/translate.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 18546d3bd2..8a92fa4a1a 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -953,12 +953,6 @@ static void gen_mov_pc_npc(DisasContext *dc)
}
}
-static void gen_op_next_insn(void)
-{
- tcg_gen_mov_tl(cpu_pc, cpu_npc);
- tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
-}
-
static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
DisasContext *dc)
{
@@ -2254,7 +2248,8 @@ static bool advance_pc(DisasContext *dc)
case DYNAMIC_PC:
case DYNAMIC_PC_LOOKUP:
dc->pc = dc->npc;
- gen_op_next_insn();
+ tcg_gen_mov_tl(cpu_pc, cpu_npc);
+ tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
break;
case JUMP_PC:
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 17/20] target/sparc: Record entire jump condition in DisasContext
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (15 preceding siblings ...)
2023-10-17 6:41 ` [PATCH 16/20] target/sparc: Merge gen_op_next_insn into only caller Richard Henderson
@ 2023-10-17 6:41 ` Richard Henderson
2023-10-17 6:41 ` [PATCH 18/20] target/sparc: Discard cpu_cond at the end of each insn Richard Henderson
` (2 subsequent siblings)
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:41 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Use the original condition instead of consuming cpu_cond,
which will now only be live along exception paths.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/translate.c | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 8a92fa4a1a..bdf1753a65 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -149,6 +149,12 @@ static TCGv cpu_wim;
/* Floating point registers */
static TCGv_i64 cpu_fpr[TARGET_DPREGS];
+typedef struct DisasCompare {
+ TCGCond cond;
+ TCGv c1;
+ int c2;
+} DisasCompare;
+
typedef struct DisasDelayException {
struct DisasDelayException *next;
TCGLabel *lab;
@@ -162,7 +168,11 @@ typedef struct DisasContext {
DisasContextBase base;
target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */
target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */
- target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */
+
+ /* Used when JUMP_PC value is used. */
+ DisasCompare jump;
+ target_ulong jump_pc[2];
+
int mem_idx;
bool fpu_enabled;
bool address_mask_32bit;
@@ -181,12 +191,6 @@ typedef struct DisasContext {
DisasDelayException *delay_excp_list;
} DisasContext;
-typedef struct {
- TCGCond cond;
- TCGv c1;
- int c2;
-} DisasCompare;
-
// This function uses non-native bit order
#define GET_FIELD(X, FROM, TO) \
((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
@@ -850,9 +854,9 @@ static void gen_generic_branch(DisasContext *dc)
{
TCGv npc0 = tcg_constant_tl(dc->jump_pc[0]);
TCGv npc1 = tcg_constant_tl(dc->jump_pc[1]);
- TCGv zero = tcg_constant_tl(0);
+ TCGv c2 = tcg_constant_tl(dc->jump.c2);
- tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc, cpu_cond, zero, npc0, npc1);
+ tcg_gen_movcond_tl(dc->jump.cond, cpu_npc, dc->jump.c1, c2, npc0, npc1);
}
/* call this function before using the condition register as it may
@@ -2255,7 +2259,7 @@ static bool advance_pc(DisasContext *dc)
case JUMP_PC:
/* we can do a static jump */
l1 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_NE, cpu_cond, 0, l1);
+ tcg_gen_brcondi_tl(dc->jump.cond, dc->jump.c1, dc->jump.c2, l1);
/* jump not taken */
gen_goto_tb(dc, 1, dc->jump_pc[1], dc->jump_pc[1] + 4);
@@ -2339,9 +2343,10 @@ static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
}
} else {
dc->pc = npc;
+ dc->npc = JUMP_PC;
+ dc->jump = *cmp;
dc->jump_pc[0] = dest;
dc->jump_pc[1] = npc + 4;
- dc->npc = JUMP_PC;
/* The condition for cpu_cond is always NE -- normalize. */
if (cmp->cond == TCG_COND_NE) {
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 18/20] target/sparc: Discard cpu_cond at the end of each insn
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (16 preceding siblings ...)
2023-10-17 6:41 ` [PATCH 17/20] target/sparc: Record entire jump condition in DisasContext Richard Henderson
@ 2023-10-17 6:41 ` Richard Henderson
2023-10-17 6:41 ` [PATCH 19/20] target/sparc: Implement UDIVX and SDIVX inline Richard Henderson
2023-10-17 6:41 ` [PATCH 20/20] target/sparc: Implement UDIV inline Richard Henderson
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:41 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
If the insn raises no exceptions, there will be no path in which
cpu_cond is used, and so the computation may be optimized away.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/translate.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index bdf1753a65..9f53e703e6 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -174,6 +174,7 @@ typedef struct DisasContext {
target_ulong jump_pc[2];
int mem_idx;
+ bool cpu_cond_live;
bool fpu_enabled;
bool address_mask_32bit;
#ifndef CONFIG_USER_ONLY
@@ -850,6 +851,19 @@ static void gen_op_eval_fbo(TCGv dst, TCGv src, unsigned int fcc_offset)
tcg_gen_xori_tl(dst, dst, 0x1);
}
+static void finishing_insn(DisasContext *dc)
+{
+ /*
+ * From here, there is no future path through an unwinding exception.
+ * If the current insn cannot raise an exception, the computation of
+ * cpu_cond may be able to be elided.
+ */
+ if (dc->cpu_cond_live) {
+ tcg_gen_discard_tl(cpu_cond);
+ dc->cpu_cond_live = false;
+ }
+}
+
static void gen_generic_branch(DisasContext *dc)
{
TCGv npc0 = tcg_constant_tl(dc->jump_pc[0]);
@@ -896,6 +910,7 @@ static void save_state(DisasContext *dc)
static void gen_exception(DisasContext *dc, int which)
{
+ finishing_insn(dc);
save_state(dc);
gen_helper_raise_exception(tcg_env, tcg_constant_i32(which));
dc->base.is_jmp = DISAS_NORETURN;
@@ -937,6 +952,8 @@ static void gen_check_align(DisasContext *dc, TCGv addr, int mask)
static void gen_mov_pc_npc(DisasContext *dc)
{
+ finishing_insn(dc);
+
if (dc->npc & 3) {
switch (dc->npc) {
case JUMP_PC:
@@ -2247,6 +2264,8 @@ static bool advance_pc(DisasContext *dc)
{
TCGLabel *l1;
+ finishing_insn(dc);
+
if (dc->npc & 3) {
switch (dc->npc) {
case DYNAMIC_PC:
@@ -2290,6 +2309,8 @@ static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
{
target_ulong npc = dc->npc;
+ finishing_insn(dc);
+
if (cmp->cond == TCG_COND_ALWAYS) {
if (annul) {
dc->pc = dest;
@@ -2354,6 +2375,7 @@ static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
} else {
tcg_gen_setcondi_tl(cmp->cond, cpu_cond, cmp->c1, cmp->c2);
}
+ dc->cpu_cond_live = true;
}
}
return true;
@@ -2520,6 +2542,8 @@ static bool trans_Tcc(DisasContext *dc, arg_Tcc *a)
tcg_gen_addi_i32(trap, trap, TT_TRAP);
}
+ finishing_insn(dc);
+
/* Trap always. */
if (a->cond == 8) {
save_state(dc);
@@ -3198,6 +3222,7 @@ TRANS(WRSTICK_CMPR, 64, do_wr_special, a, supervisor(dc), do_wrstick_cmpr)
static void do_wrpowerdown(DisasContext *dc, TCGv src)
{
+ finishing_insn(dc);
save_state(dc);
gen_helper_power_down(tcg_env);
}
@@ -5148,6 +5173,8 @@ static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
DisasDelayException *e, *e_next;
bool may_lookup;
+ finishing_insn(dc);
+
switch (dc->base.is_jmp) {
case DISAS_NEXT:
case DISAS_TOO_MANY:
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 19/20] target/sparc: Implement UDIVX and SDIVX inline
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (17 preceding siblings ...)
2023-10-17 6:41 ` [PATCH 18/20] target/sparc: Discard cpu_cond at the end of each insn Richard Henderson
@ 2023-10-17 6:41 ` Richard Henderson
2023-10-17 6:41 ` [PATCH 20/20] target/sparc: Implement UDIV inline Richard Henderson
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:41 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/helper.h | 4 --
target/sparc/helper.c | 24 ---------
target/sparc/translate.c | 109 ++++++++++++++++++++++++++++++++++-----
3 files changed, 95 insertions(+), 42 deletions(-)
diff --git a/target/sparc/helper.h b/target/sparc/helper.h
index 6415942e03..12181d1106 100644
--- a/target/sparc/helper.h
+++ b/target/sparc/helper.h
@@ -33,10 +33,6 @@ DEF_HELPER_3(udiv_cc, 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)
-#ifdef TARGET_SPARC64
-DEF_HELPER_FLAGS_3(sdivx, TCG_CALL_NO_WG, s64, env, s64, s64)
-DEF_HELPER_FLAGS_3(udivx, TCG_CALL_NO_WG, i64, env, i64, i64)
-#endif
#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
DEF_HELPER_FLAGS_4(ld_asi, TCG_CALL_NO_WG, i64, env, tl, int, i32)
DEF_HELPER_FLAGS_5(st_asi, TCG_CALL_NO_WG, void, env, tl, i64, int, i32)
diff --git a/target/sparc/helper.c b/target/sparc/helper.c
index 4887f295a5..3830d01634 100644
--- a/target/sparc/helper.c
+++ b/target/sparc/helper.c
@@ -177,30 +177,6 @@ target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
return do_sdiv(env, a, b, 1, GETPC());
}
-#ifdef TARGET_SPARC64
-int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b)
-{
- if (b == 0) {
- /* Raise divide by zero trap. */
- cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
- } else if (b == -1) {
- /* Avoid overflow trap with i386 divide insn. */
- return -a;
- } else {
- return a / b;
- }
-}
-
-uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
-{
- if (b == 0) {
- /* Raise divide by zero trap. */
- cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
- }
- return a / b;
-}
-#endif
-
target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
target_ulong src2)
{
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 9f53e703e6..b344422f8a 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -65,8 +65,6 @@
#define gen_helper_fabsd(D, S) qemu_build_not_reached()
#define gen_helper_done(E) qemu_build_not_reached()
#define gen_helper_retry(E) qemu_build_not_reached()
-#define gen_helper_udivx(D, E, A, B) qemu_build_not_reached()
-#define gen_helper_sdivx(D, E, A, B) qemu_build_not_reached()
#define gen_helper_fmul8x16 ({ g_assert_not_reached(); NULL; })
#define gen_helper_fmul8x16au ({ g_assert_not_reached(); NULL; })
#define gen_helper_fmul8x16al ({ g_assert_not_reached(); NULL; })
@@ -578,16 +576,6 @@ static void gen_op_smul(TCGv dst, TCGv src1, TCGv src2)
gen_op_multiply(dst, src1, src2, 1);
}
-static void gen_op_udivx(TCGv dst, TCGv src1, TCGv src2)
-{
- gen_helper_udivx(dst, tcg_env, src1, src2);
-}
-
-static void gen_op_sdivx(TCGv dst, TCGv src1, TCGv src2)
-{
- gen_helper_sdivx(dst, tcg_env, src1, src2);
-}
-
static void gen_op_udiv(TCGv dst, TCGv src1, TCGv src2)
{
gen_helper_udiv(dst, tcg_env, src1, src2);
@@ -3627,8 +3615,6 @@ TRANS(XORN, ALL, do_arith, a, tcg_gen_eqv_tl, NULL)
TRANS(MULX, 64, do_arith, a, tcg_gen_mul_tl, tcg_gen_muli_tl)
TRANS(UMUL, MUL, do_arith, a, gen_op_umul, NULL)
TRANS(SMUL, MUL, do_arith, a, gen_op_smul, NULL)
-TRANS(UDIVX, 64, do_arith, a, gen_op_udivx, NULL)
-TRANS(SDIVX, 64, do_arith, a, gen_op_sdivx, NULL)
TRANS(UDIV, DIV, do_arith, a, gen_op_udiv, NULL)
TRANS(SDIV, DIV, do_arith, a, gen_op_sdiv, NULL)
TRANS(ADDC, ALL, do_arith, a, gen_op_addc, NULL)
@@ -3656,6 +3642,101 @@ TRANS(ADDCcc, ALL, do_arith, a, gen_op_addccc, NULL)
TRANS(SUBCcc, ALL, do_arith, a, gen_op_subccc, NULL)
TRANS(MULScc, ALL, do_arith, a, gen_op_mulscc, NULL)
+static bool trans_UDIVX(DisasContext *dc, arg_r_r_ri *a)
+{
+ TCGv dst, src1, src2;
+
+ if (!avail_64(dc)) {
+ return false;
+ }
+ /* For simplicity, we under-decoded the rs2 form. */
+ if (!a->imm && a->rs2_or_imm & ~0x1f) {
+ return false;
+ }
+
+ if (unlikely(a->rs2_or_imm == 0)) {
+ gen_exception(dc, TT_DIV_ZERO);
+ return true;
+ }
+
+ if (a->imm) {
+ src2 = tcg_constant_tl(a->rs2_or_imm);
+ } else {
+ TCGLabel *lab;
+
+ finishing_insn(dc);
+ flush_cond(dc);
+
+ lab = delay_exception(dc, TT_DIV_ZERO);
+ src2 = cpu_regs[a->rs2_or_imm];
+ tcg_gen_brcondi_tl(TCG_COND_EQ, src2, 0, lab);
+ }
+
+ dst = gen_dest_gpr(dc, a->rd);
+ src1 = gen_load_gpr(dc, a->rs1);
+
+ tcg_gen_divu_tl(dst, src1, src2);
+ gen_store_gpr(dc, a->rd, dst);
+ return advance_pc(dc);
+}
+
+static bool trans_SDIVX(DisasContext *dc, arg_r_r_ri *a)
+{
+ TCGv dst, src1, src2;
+
+ if (!avail_64(dc)) {
+ return false;
+ }
+ /* For simplicity, we under-decoded the rs2 form. */
+ if (!a->imm && a->rs2_or_imm & ~0x1f) {
+ return false;
+ }
+
+ if (unlikely(a->rs2_or_imm == 0)) {
+ gen_exception(dc, TT_DIV_ZERO);
+ return true;
+ }
+
+ dst = gen_dest_gpr(dc, a->rd);
+ src1 = gen_load_gpr(dc, a->rs1);
+
+ if (a->imm) {
+ if (unlikely(a->rs2_or_imm == -1)) {
+ tcg_gen_neg_tl(dst, src1);
+ gen_store_gpr(dc, a->rd, dst);
+ return advance_pc(dc);
+ }
+ src2 = tcg_constant_tl(a->rs2_or_imm);
+ } else {
+ TCGLabel *lab;
+ TCGv t1, t2;
+
+ finishing_insn(dc);
+ flush_cond(dc);
+
+ lab = delay_exception(dc, TT_DIV_ZERO);
+ src2 = cpu_regs[a->rs2_or_imm];
+ tcg_gen_brcondi_tl(TCG_COND_EQ, src2, 0, lab);
+
+ /*
+ * Need to avoid INT64_MIN / -1, which will trap on x86 host.
+ * Set SRC2 to 1 as a new divisor, to produce the correct result.
+ */
+ t1 = tcg_temp_new();
+ t2 = tcg_temp_new();
+ tcg_gen_setcondi_tl(TCG_COND_EQ, t1, src1, (target_long)INT64_MIN);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, t2, src2, -1);
+ tcg_gen_and_tl(t1, t1, t2);
+ tcg_gen_movcond_tl(TCG_COND_NE, t2, t1, tcg_constant_tl(0),
+ tcg_constant_tl(1), src2);
+ src2 = t2;
+ }
+
+ tcg_gen_div_tl(dst, src1, src2);
+ gen_store_gpr(dc, a->rd, dst);
+ return advance_pc(dc);
+}
+
static TCGv gen_rs2_or_imm(DisasContext *dc, bool imm, int rs2_or_imm)
{
/* For simplicity, we under-decoded the rs2 form. */
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 20/20] target/sparc: Implement UDIV inline
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
` (18 preceding siblings ...)
2023-10-17 6:41 ` [PATCH 19/20] target/sparc: Implement UDIVX and SDIVX inline Richard Henderson
@ 2023-10-17 6:41 ` Richard Henderson
19 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-17 6:41 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/helper.h | 1 -
target/sparc/helper.c | 29 +++++++---------------
target/sparc/translate.c | 52 +++++++++++++++++++++++++++++++++++-----
3 files changed, 54 insertions(+), 28 deletions(-)
diff --git a/target/sparc/helper.h b/target/sparc/helper.h
index 12181d1106..624a8fdedf 100644
--- a/target/sparc/helper.h
+++ b/target/sparc/helper.h
@@ -27,7 +27,6 @@ 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_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_cc, tl, env, tl, tl)
diff --git a/target/sparc/helper.c b/target/sparc/helper.c
index 3830d01634..1a900753d7 100644
--- a/target/sparc/helper.c
+++ b/target/sparc/helper.c
@@ -81,15 +81,14 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
}
#endif
-static target_ulong do_udiv(CPUSPARCState *env, target_ulong a,
- target_ulong b, int cc, uintptr_t ra)
+target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
{
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);
+ cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
}
x0 = x0 / x1;
@@ -99,29 +98,17 @@ static target_ulong do_udiv(CPUSPARCState *env, target_ulong a,
v = r = UINT32_MAX;
}
- if (cc) {
- env->cc_N = r;
- env->cc_V = v;
- env->cc_icc_Z = r;
- env->cc_icc_C = 0;
+ 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;
+ env->cc_xcc_Z = r;
+ env->cc_xcc_C = 0;
#endif
- }
return r;
}
-target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
-{
- return do_udiv(env, a, b, 0, GETPC());
-}
-
-target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
-{
- return do_udiv(env, a, b, 1, GETPC());
-}
-
static target_ulong do_sdiv(CPUSPARCState *env, target_ulong a,
target_ulong b, int cc, uintptr_t ra)
{
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index b344422f8a..2c533a1998 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -576,11 +576,6 @@ static void gen_op_smul(TCGv dst, TCGv src1, TCGv src2)
gen_op_multiply(dst, src1, src2, 1);
}
-static void gen_op_udiv(TCGv dst, TCGv src1, TCGv src2)
-{
- gen_helper_udiv(dst, tcg_env, src1, src2);
-}
-
static void gen_op_sdiv(TCGv dst, TCGv src1, TCGv src2)
{
gen_helper_sdiv(dst, tcg_env, src1, src2);
@@ -3615,7 +3610,6 @@ TRANS(XORN, ALL, do_arith, a, tcg_gen_eqv_tl, NULL)
TRANS(MULX, 64, do_arith, a, tcg_gen_mul_tl, tcg_gen_muli_tl)
TRANS(UMUL, MUL, do_arith, a, gen_op_umul, NULL)
TRANS(SMUL, MUL, do_arith, a, gen_op_smul, NULL)
-TRANS(UDIV, DIV, do_arith, a, gen_op_udiv, NULL)
TRANS(SDIV, DIV, do_arith, a, gen_op_sdiv, NULL)
TRANS(ADDC, ALL, do_arith, a, gen_op_addc, NULL)
TRANS(SUBC, ALL, do_arith, a, gen_op_subc, NULL)
@@ -3642,6 +3636,52 @@ TRANS(ADDCcc, ALL, do_arith, a, gen_op_addccc, NULL)
TRANS(SUBCcc, ALL, do_arith, a, gen_op_subccc, NULL)
TRANS(MULScc, ALL, do_arith, a, gen_op_mulscc, NULL)
+static bool trans_UDIV(DisasContext *dc, arg_r_r_ri *a)
+{
+ TCGv_i64 t1, t2;
+ TCGv dst;
+
+ /* For simplicity, we under-decoded the rs2 form. */
+ if (!a->imm && a->rs2_or_imm & ~0x1f) {
+ return false;
+ }
+
+ if (unlikely(a->rs2_or_imm == 0)) {
+ gen_exception(dc, TT_DIV_ZERO);
+ return true;
+ }
+
+ if (a->imm) {
+ t2 = tcg_constant_i64((uint32_t)a->rs2_or_imm);
+ } else {
+ TCGLabel *lab;
+ TCGv_i32 n2;
+
+ finishing_insn(dc);
+ flush_cond(dc);
+
+ n2 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(n2, cpu_regs[a->rs2_or_imm]);
+
+ lab = delay_exception(dc, TT_DIV_ZERO);
+ tcg_gen_brcondi_i32(TCG_COND_EQ, n2, 0, lab);
+
+ t2 = tcg_temp_new_i64();
+ tcg_gen_extu_tl_i64(t2, cpu_regs[a->rs2_or_imm]);
+ }
+
+ t1 = tcg_temp_new_i64();
+ tcg_gen_concat_tl_i64(t1, gen_load_gpr(dc, a->rs1), cpu_y);
+
+ tcg_gen_divu_i64(t1, t1, t2);
+ tcg_gen_umin_i64(t1, t1, tcg_constant_i64(UINT32_MAX));
+
+ dst = gen_dest_gpr(dc, a->rd);
+ tcg_gen_trunc_i64_tl(dst, t1);
+ gen_store_gpr(dc, a->rd, dst);
+ return advance_pc(dc);
+}
+
static bool trans_UDIVX(DisasContext *dc, arg_r_r_ri *a)
{
TCGv dst, src1, src2;
--
2.34.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH 01/20] target/sparc: Introduce cpu_put_psr_icc
2023-10-17 6:40 ` [PATCH 01/20] target/sparc: Introduce cpu_put_psr_icc Richard Henderson
@ 2023-10-19 14:11 ` Philippe Mathieu-Daudé
2023-10-26 1:04 ` Richard Henderson
0 siblings, 1 reply; 23+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-10-19 14:11 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: mark.cave-ayland
Hi Richard,
On 17/10/23 08:40, Richard Henderson wrote:
> Isolate linux-user from changes to icc representation.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> target/sparc/cpu.h | 1 +
> linux-user/sparc/signal.c | 2 +-
> target/sparc/win_helper.c | 7 ++++++-
> 3 files changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
> index 758a4e8aaa..955329f6c9 100644
> --- a/target/sparc/cpu.h
> +++ b/target/sparc/cpu.h
> @@ -619,6 +619,7 @@ void sparc_restore_state_to_opc(CPUState *cs,
> /* win_helper.c */
> target_ulong cpu_get_psr(CPUSPARCState *env1);
> void cpu_put_psr(CPUSPARCState *env1, target_ulong val);
> +void cpu_put_psr_icc(CPUSPARCState *env1, target_ulong val);
> void cpu_put_psr_raw(CPUSPARCState *env1, target_ulong val);
> #ifdef TARGET_SPARC64
> void cpu_change_pstate(CPUSPARCState *env1, uint32_t new_pstate);
> diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
> index 2be9000b9e..dfcae707e0 100644
> --- a/linux-user/sparc/signal.c
> +++ b/linux-user/sparc/signal.c
> @@ -164,7 +164,7 @@ static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
> */
> uint32_t psr;
> __get_user(psr, ®s->psr);
> - env->psr = (psr & PSR_ICC) | (env->psr & ~PSR_ICC);
This keeps the non-PSR_ICC fields from env->psr, ...
> + cpu_put_psr_icc(env, psr);
> #endif
>
> /* Note that pc and npc are handled in the caller. */
> diff --git a/target/sparc/win_helper.c b/target/sparc/win_helper.c
> index 3a7c0ff943..bf2c90c780 100644
> --- a/target/sparc/win_helper.c
> +++ b/target/sparc/win_helper.c
> @@ -67,9 +67,14 @@ target_ulong cpu_get_psr(CPUSPARCState *env)
> #endif
> }
>
> -void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val)
> +void cpu_put_psr_icc(CPUSPARCState *env, target_ulong val)
> {
> env->psr = val & PSR_ICC;
... while this zeroes the non-PSR_ICC fields. Is that expected?
> +}
> +
> +void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val)
> +{
> + cpu_put_psr_icc(env, val);
> #if !defined(TARGET_SPARC64)
> env->psref = (val & PSR_EF) ? 1 : 0;
> env->psrpil = (val & PSR_PIL) >> 8;
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 01/20] target/sparc: Introduce cpu_put_psr_icc
2023-10-19 14:11 ` Philippe Mathieu-Daudé
@ 2023-10-26 1:04 ` Richard Henderson
0 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-10-26 1:04 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel; +Cc: mark.cave-ayland
On 10/19/23 07:11, Philippe Mathieu-Daudé wrote:
>> uint32_t psr;
>> __get_user(psr, ®s->psr);
>> - env->psr = (psr & PSR_ICC) | (env->psr & ~PSR_ICC);
>
> This keeps the non-PSR_ICC fields from env->psr, ...
>
>> + cpu_put_psr_icc(env, psr);
>> #endif
>> /* Note that pc and npc are handled in the caller. */
>> diff --git a/target/sparc/win_helper.c b/target/sparc/win_helper.c
>> index 3a7c0ff943..bf2c90c780 100644
>> --- a/target/sparc/win_helper.c
>> +++ b/target/sparc/win_helper.c
>> @@ -67,9 +67,14 @@ target_ulong cpu_get_psr(CPUSPARCState *env)
>> #endif
>> }
>> -void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val)
>> +void cpu_put_psr_icc(CPUSPARCState *env, target_ulong val)
>> {
>> env->psr = val & PSR_ICC;
>
> ... while this zeroes the non-PSR_ICC fields. Is that expected?
The only field in env->psr is ICC.
The other fields are in env->psr{s,ps,et,pil,ef}.
This is a bit of old linux-user confusion, which apparently presumed more.
Anyway, the situation is improved with this patch, and further in the next by removing
"env->psr" entirely.
r~
PS: The handling of PSR could probably be cleaned up. I don't think there is a real need
for the fields to be split apart like this. A test of e.g. (env->psr & PSR_S) should be
more or less identical in performance to (env->psrs != 0). It's only the PSR_ICC
subfields that get heavy use within translation.
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2023-10-26 1:04 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-17 6:40 [PATCH 00/20] target/sparc: Cleanup condition codes etc Richard Henderson
2023-10-17 6:40 ` [PATCH 01/20] target/sparc: Introduce cpu_put_psr_icc Richard Henderson
2023-10-19 14:11 ` Philippe Mathieu-Daudé
2023-10-26 1:04 ` Richard Henderson
2023-10-17 6:40 ` [PATCH 02/20] target/sparc: Split psr and xcc into components Richard Henderson
2023-10-17 6:40 ` [PATCH 03/20] target/sparc: Remove CC_OP_DIV Richard Henderson
2023-10-17 6:40 ` [PATCH 04/20] target/sparc: Remove CC_OP_LOGIC Richard Henderson
2023-10-17 6:40 ` [PATCH 05/20] target/sparc: Remove CC_OP_ADD, CC_OP_ADDX, CC_OP_TADD Richard Henderson
2023-10-17 6:40 ` [PATCH 06/20] target/sparc: Remove CC_OP_SUB, CC_OP_SUBX, CC_OP_TSUB Richard Henderson
2023-10-17 6:40 ` [PATCH 07/20] target/sparc: Remove CC_OP_TADDTV, CC_OP_TSUBTV Richard Henderson
2023-10-17 6:40 ` [PATCH 08/20] target/sparc: Remove CC_OP leftovers Richard Henderson
2023-10-17 6:40 ` [PATCH 09/20] target/sparc: Remove DisasCompare.is_bool Richard Henderson
2023-10-17 6:40 ` [PATCH 10/20] target/sparc: Change DisasCompare.c2 to int Richard Henderson
2023-10-17 6:41 ` [PATCH 11/20] target/sparc: Always copy conditions into a new temporary Richard Henderson
2023-10-17 6:41 ` [PATCH 12/20] target/sparc: Do flush_cond in advance_jump_cond Richard Henderson
2023-10-17 6:41 ` [PATCH 13/20] target/sparc: Merge gen_branch2 into advance_pc Richard Henderson
2023-10-17 6:41 ` [PATCH 14/20] target/sparc: Merge advance_jump_uncond_{never, always} into advance_jump_cond Richard Henderson
2023-10-17 6:41 ` [PATCH 15/20] target/sparc: Use DISAS_EXIT in do_wrpsr Richard Henderson
2023-10-17 6:41 ` [PATCH 16/20] target/sparc: Merge gen_op_next_insn into only caller Richard Henderson
2023-10-17 6:41 ` [PATCH 17/20] target/sparc: Record entire jump condition in DisasContext Richard Henderson
2023-10-17 6:41 ` [PATCH 18/20] target/sparc: Discard cpu_cond at the end of each insn Richard Henderson
2023-10-17 6:41 ` [PATCH 19/20] target/sparc: Implement UDIVX and SDIVX inline Richard Henderson
2023-10-17 6:41 ` [PATCH 20/20] target/sparc: Implement UDIV inline Richard Henderson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).