qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/21] target/sparc: Cleanup condition codes etc
@ 2023-11-01  4:11 Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 01/21] target/sparc: Introduce cpu_put_psr_icc Richard Henderson
                   ` (21 more replies)
  0 siblings, 22 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 more often that we'd like.

Since almost all Sparc instructions that set cc also have a version of
the instruction that does not set cc, we can trust that the compiler
has only used the cc-setting version when it is actually required.
Thus, unlike CISC processors, there is very little scope for optimization
of the flags -- we might as well compute them immediately.

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.  (For "normal" setting of Z, we could share, but it is
possible to set xcc.Z and !icc.Z via explicit write to %ccr, and for
that we have to have two variables.)

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~


Richard Henderson (21):
  target/sparc: Introduce cpu_put_psr_icc
  target/sparc: Split psr and xcc into components
  target/sparc: Remove CC_OP_LOGIC
  target/sparc: Remove CC_OP_DIV
  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: Pass displacement to advance_jump_cond
  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
  target/sparc: Check for invalid cond in gen_compare_reg

 linux-user/sparc/target_cpu.h |   17 +-
 target/sparc/cpu.h            |   58 +-
 target/sparc/helper.h         |   12 +-
 target/sparc/insns.decode     |    7 +-
 linux-user/sparc/cpu_loop.c   |   11 +-
 linux-user/sparc/signal.c     |    2 +-
 target/sparc/cc_helper.c      |  471 ------------
 target/sparc/cpu.c            |    1 -
 target/sparc/helper.c         |  171 ++---
 target/sparc/int32_helper.c   |    5 -
 target/sparc/int64_helper.c   |    5 -
 target/sparc/machine.c        |   45 +-
 target/sparc/translate.c      | 1333 ++++++++++++++-------------------
 target/sparc/win_helper.c     |   56 +-
 target/sparc/meson.build      |    1 -
 15 files changed, 789 insertions(+), 1406 deletions(-)
 delete mode 100644 target/sparc/cc_helper.c

-- 
2.34.1



^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 01/21] target/sparc: Introduce cpu_put_psr_icc
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 02/21] target/sparc: Split psr and xcc into components Richard Henderson
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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, &regs->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 v2 02/21] target/sparc: Split psr and xcc into components
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 01/21] target/sparc: Introduce cpu_put_psr_icc Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 03/21] target/sparc: Remove CC_OP_LOGIC Richard Henderson
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 |  17 +-
 target/sparc/cpu.h            |  30 ++-
 linux-user/sparc/cpu_loop.c   |   6 +-
 target/sparc/cc_helper.c      |  51 +++--
 target/sparc/machine.c        |  45 ++++-
 target/sparc/translate.c      | 362 +++++++++++++---------------------
 target/sparc/win_helper.c     |  52 ++++-
 7 files changed, 291 insertions(+), 272 deletions(-)

diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h
index 1f4bed50f4..5f62c5eb75 100644
--- a/linux-user/sparc/target_cpu.h
+++ b/linux-user/sparc/target_cpu.h
@@ -26,6 +26,17 @@
 # define TARGET_STACK_BIAS 0
 #endif
 
+static void set_syscall_C(CPUSPARCState *env, bool val)
+{
+#ifndef TARGET_SPARC64
+    env->icc_C = val;
+#elif defined(TARGET_ABI32)
+    env->icc_C = (uint64_t)val << 32;
+#else
+    env->xcc_C = val;
+#endif
+}
+
 static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp,
                                         unsigned flags)
 {
@@ -58,11 +69,7 @@ static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp,
          * do the pc advance twice.
          */
         env->regwptr[WREG_O0] = 0;
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-        env->xcc &= ~PSR_CARRY;
-#else
-        env->psr &= ~PSR_CARRY;
-#endif
+        set_syscall_C(env, 0);
         env->pc = env->npc;
         env->npc = env->npc + 4;
     }
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 955329f6c9..ea8a04c6e3 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 icc_Z;
+#ifdef TARGET_SPARC64
+    target_ulong 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 icc_C;
+#ifdef TARGET_SPARC64
+    target_ulong 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..c1a2362041 100644
--- a/linux-user/sparc/cpu_loop.c
+++ b/linux-user/sparc/cpu_loop.c
@@ -197,10 +197,8 @@ 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
 
 /* Avoid ifdefs below for the v9 and pre-v9 hw traps. */
@@ -240,10 +238,10 @@ void cpu_loop (CPUSPARCState *env)
                 break;
             }
             if ((abi_ulong)ret >= (abi_ulong)(-515)) {
-                env->syscall_cc |= PSR_CARRY;
+                set_syscall_C(env, 1);
                 ret = -ret;
             } else {
-                env->syscall_cc &= ~PSR_CARRY;
+                set_syscall_C(env, 0);
             }
             env->regwptr[0] = ret;
             /* next instruction */
diff --git a/target/sparc/cc_helper.c b/target/sparc/cc_helper.c
index 7ad5b9b29e..46bec69d96 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->icc_C = (uint64_t)icc << (32 - PSR_CARRY_SHIFT);
+    env->xcc_C = (xcc >> PSR_CARRY_SHIFT) & 1;
+    env->xcc_Z = ~xcc & PSR_ZERO;
+#else
+    env->cc_N = -(icc & PSR_NEG);
+    env->cc_V = -(icc & PSR_OVF);
+    env->icc_C = (icc >> PSR_CARRY_SHIFT) & 1;
 #endif
+    env->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->icc_C, 32, 1);
+#else
+        return env->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..44dfc07014 100644
--- a/target/sparc/machine.c
+++ b/target/sparc/machine.c
@@ -83,6 +83,42 @@ 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);
+
+    /* Do not clobber icc.[NV] */
+    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->xcc_Z = ~val & PSR_ZERO;
+    env->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 +191,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 986a88c4e1..261f142636 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -107,19 +107,35 @@
 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;
 #else
 # define cpu_fprs               ({ qemu_build_not_reached(); (TCGv)NULL; })
 # define cpu_gsr                ({ qemu_build_not_reached(); (TCGv)NULL; })
 #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];
 
@@ -366,31 +382,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);
@@ -640,13 +631,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);
 
@@ -825,114 +814,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 =
@@ -1249,34 +1136,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) {
@@ -1287,92 +1162,127 @@ 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 = t1 = tcg_temp_new();
+    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: Z */
+        cmp->cond = TCG_COND_EQ;
+        if (TARGET_LONG_BITS == 32 || xcc) {
+            tcg_gen_mov_tl(t1, cpu_cc_Z);
+        } else {
+            tcg_gen_ext32u_tl(t1, cpu_icc_Z);
         }
         break;
+
+    case 0x2: /* le: Z | (N ^ V) */
+        /*
+         * Simplify:
+         *   cc_Z || (N ^ V) < 0        NE
+         *   cc_Z && !((N ^ V) < 0)     EQ
+         *   cc_Z & ~((N ^ V) >> TLB)   EQ
+         */
+        cmp->cond = TCG_COND_EQ;
+        tcg_gen_xor_tl(t1, cpu_cc_N, cpu_cc_V);
+        tcg_gen_sextract_tl(t1, t1, xcc ? 63 : 31, 1);
+        tcg_gen_andc_tl(t1, xcc ? cpu_cc_Z : cpu_icc_Z, t1);
+        if (TARGET_LONG_BITS == 64 && !xcc) {
+            tcg_gen_ext32u_tl(t1, t1);
+        }
+        break;
+
+    case 0x3: /* lt: N ^ V */
+        cmp->cond = TCG_COND_LT;
+        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: Z | C */
+        /*
+         * Simplify:
+         *   cc_Z == 0 || cc_C != 0     NE
+         *   cc_Z != 0 && cc_C == 0     EQ
+         *   cc_Z & (cc_C ? 0 : -1)     EQ
+         *   cc_Z & (cc_C - 1)          EQ
+         */
+        cmp->cond = TCG_COND_EQ;
+        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);
+            tcg_gen_and_tl(t1, t1, cpu_icc_Z);
+            tcg_gen_ext32u_tl(t1, t1);
+        }
+        break;
+
+    case 0x5: /* ltu: C */
+        cmp->cond = TCG_COND_NE;
+        cmp->is_bool = true;
+        if (TARGET_LONG_BITS == 32 || xcc) {
+            tcg_gen_mov_tl(t1, cpu_cc_C);
+        } else {
+            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) {
+            tcg_gen_mov_tl(t1, cpu_cc_N);
+        } else {
+            tcg_gen_ext32s_tl(t1, cpu_cc_N);
+        }
+        break;
+
+    case 0x7: /* vs: V */
+        cmp->cond = TCG_COND_LT;
+        if (TARGET_LONG_BITS == 32 || xcc) {
+            tcg_gen_mov_tl(t1, cpu_cc_V);
+        } else {
+            tcg_gen_ext32s_tl(t1, cpu_cc_V);
+        }
+        break;
+    }
+    if (cond & 8) {
+        cmp->cond = tcg_invert_cond(cmp->cond);
+        cmp->is_bool = false;
     }
 }
 
@@ -5513,17 +5423,21 @@ 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" },
 #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[] = {
 #ifdef TARGET_SPARC64
         { &cpu_gsr, offsetof(CPUSPARCState, gsr), "gsr" },
+        { &cpu_xcc_Z, offsetof(CPUSPARCState, xcc_Z), "xcc_Z" },
+        { &cpu_xcc_C, offsetof(CPUSPARCState, 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, icc_Z), "icc_Z" },
+        { &cpu_icc_C, offsetof(CPUSPARCState, 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..f0ff6bf5db 100644
--- a/target/sparc/win_helper.c
+++ b/target/sparc/win_helper.c
@@ -53,23 +53,44 @@ 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->icc_Z == 0) << PSR_ZERO_SHIFT;
+    if (TARGET_LONG_BITS == 64) {
+        icc |= extract64(env->icc_C, 32, 1) << PSR_CARRY_SHIFT;
+    } else {
+        icc |= env->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) {
+        /* Do not clobber xcc.[NV] */
+        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->icc_C = -(val & PSR_CARRY);
+    } else {
+        env->cc_N = -(val & PSR_NEG);
+        env->cc_V = -(val & PSR_OVF);
+        env->icc_C = (val >> PSR_CARRY_SHIFT) & 1;
+    }
+    env->icc_Z = ~val & PSR_ZERO;
 }
 
 void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val)
@@ -249,17 +270,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->icc_C >> 32) & 1;
+    ccr |= ((int32_t)env->cc_V < 0) << 1;
+    ccr |= ((int32_t)env->icc_Z == 0) << 2;
+    ccr |= ((int32_t)env->cc_N < 0) << 3;
+
+    ccr |= env->xcc_C << 4;
+    ccr |= (env->cc_V < 0) << 5;
+    ccr |= (env->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->icc_C = (uint64_t)val << 32;
+    env->xcc_C = (val >> 4) & 1;
+    env->icc_Z = ~val & 0x04;
+    env->xcc_Z = ~val & 0x40;
+
     CC_OP = CC_OP_FLAGS;
 }
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 03/21] target/sparc: Remove CC_OP_LOGIC
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 01/21] target/sparc: Introduce cpu_put_psr_icc Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 02/21] target/sparc: Split psr and xcc into components Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 04/21] target/sparc: Remove CC_OP_DIV Richard Henderson
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 | 14 +--------
 target/sparc/translate.c | 66 ++++++++++++++++------------------------
 3 files changed, 28 insertions(+), 53 deletions(-)

diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index ea8a04c6e3..202c34f7ca 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -159,7 +159,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 46bec69d96..1622300a14 100644
--- a/target/sparc/cc_helper.c
+++ b/target/sparc/cc_helper.c
@@ -378,16 +378,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)
 {
@@ -411,13 +401,12 @@ 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
 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_DIV] = { compute_all_logic_xcc, compute_C_div },
     [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 },
@@ -426,7 +415,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 261f142636..b11d89343b 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -1117,48 +1117,24 @@ 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 */
@@ -3652,7 +3628,8 @@ TRANS(NOP_v9, 64, trans_NOP, a)
 
 static bool do_arith_int(DisasContext *dc, arg_r_r_ri_cc *a, int cc_op,
                          void (*func)(TCGv, TCGv, TCGv),
-                         void (*funci)(TCGv, TCGv, target_long))
+                         void (*funci)(TCGv, TCGv, target_long),
+                         bool logic_cc)
 {
     TCGv dst, src1;
 
@@ -3661,7 +3638,9 @@ static bool do_arith_int(DisasContext *dc, arg_r_r_ri_cc *a, int cc_op,
         return false;
     }
 
-    if (a->cc) {
+    if (logic_cc) {
+        dst = cpu_cc_N;
+    } else if (a->cc && cc_op > CC_OP_FLAGS) {
         dst = cpu_cc_dst;
     } else {
         dst = gen_dest_gpr(dc, a->rd);
@@ -3677,6 +3656,17 @@ static bool do_arith_int(DisasContext *dc, arg_r_r_ri_cc *a, int cc_op,
     } else {
         func(dst, src1, cpu_regs[a->rs2_or_imm]);
     }
+
+    if (logic_cc) {
+        if (TARGET_LONG_BITS == 64) {
+            tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
+            tcg_gen_movi_tl(cpu_icc_C, 0);
+        }
+        tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
+        tcg_gen_movi_tl(cpu_cc_C, 0);
+        tcg_gen_movi_tl(cpu_cc_V, 0);
+    }
+
     gen_store_gpr(dc, a->rd, dst);
 
     if (a->cc) {
@@ -3693,16 +3683,16 @@ static bool do_arith(DisasContext *dc, arg_r_r_ri_cc *a, int cc_op,
 {
     if (a->cc) {
         assert(cc_op >= 0);
-        return do_arith_int(dc, a, cc_op, func_cc, NULL);
+        return do_arith_int(dc, a, cc_op, func_cc, NULL, false);
     }
-    return do_arith_int(dc, a, cc_op, func, funci);
+    return do_arith_int(dc, a, cc_op, func, funci, false);
 }
 
 static bool do_logic(DisasContext *dc, arg_r_r_ri_cc *a,
                      void (*func)(TCGv, TCGv, TCGv),
                      void (*funci)(TCGv, TCGv, target_long))
 {
-    return do_arith_int(dc, a, CC_OP_LOGIC, func, funci);
+    return do_arith_int(dc, a, CC_OP_FLAGS, func, funci, a->cc);
 }
 
 TRANS(ADD, ALL, do_arith, a, CC_OP_ADD,
@@ -3754,7 +3744,6 @@ static bool trans_ADDC(DisasContext *dc, arg_r_r_ri_cc *a)
 {
     switch (dc->cc_op) {
     case CC_OP_DIV:
-    case CC_OP_LOGIC:
         /* Carry is known to be zero.  Fall back to plain ADD.  */
         return do_arith(dc, a, CC_OP_ADD,
                         tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_add_cc);
@@ -3778,7 +3767,6 @@ static bool trans_SUBC(DisasContext *dc, arg_r_r_ri_cc *a)
 {
     switch (dc->cc_op) {
     case CC_OP_DIV:
-    case CC_OP_LOGIC:
         /* Carry is known to be zero.  Fall back to plain SUB.  */
         return do_arith(dc, a, CC_OP_SUB,
                         tcg_gen_sub_tl, tcg_gen_subi_tl, gen_op_sub_cc);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 04/21] target/sparc: Remove CC_OP_DIV
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (2 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 03/21] target/sparc: Remove CC_OP_LOGIC Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 05/21] target/sparc: Remove CC_OP_ADD, CC_OP_ADDX, CC_OP_TADD Richard Henderson
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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    |   6 +--
 target/sparc/cc_helper.c |  33 -------------
 target/sparc/helper.c    | 101 ++++++++++++++-------------------------
 target/sparc/translate.c |  70 ++++++++++++++++++++++-----
 5 files changed, 97 insertions(+), 114 deletions(-)

diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 202c34f7ca..b16d53b91f 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..a7b0079c3b 100644
--- a/target/sparc/helper.h
+++ b/target/sparc/helper.h
@@ -27,10 +27,8 @@ 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_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_FLAGS_3(udiv, TCG_CALL_NO_WG, i64, env, tl, tl)
+DEF_HELPER_FLAGS_3(sdiv, TCG_CALL_NO_WG, i64, env, tl, tl)
 DEF_HELPER_3(taddcctv, tl, env, tl, tl)
 DEF_HELPER_3(tsubcctv, tl, env, tl, tl)
 #ifdef TARGET_SPARC64
diff --git a/target/sparc/cc_helper.c b/target/sparc/cc_helper.c
index 1622300a14..5400dfec15 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;
@@ -378,13 +354,6 @@ static uint32_t compute_all_tsubtv(CPUSPARCState *env)
     return ret;
 }
 
-#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 */
@@ -392,7 +361,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 },
@@ -406,7 +374,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_div },
     [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 2bcdc81d54..53eec693dd 100644
--- a/target/sparc/helper.c
+++ b/target/sparc/helper.c
@@ -81,79 +81,52 @@ 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)
+uint64_t helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
 {
-    int overflow = 0;
-    uint64_t x0;
-    uint32_t x1;
+    uint64_t a64 = (uint32_t)a | ((uint64_t)env->y << 32);
+    uint32_t b32 = b;
+    uint32_t r;
 
-    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
-    x1 = (b & 0xffffffff);
-
-    if (x1 == 0) {
-        cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
+    if (b32 == 0) {
+        cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
     }
 
-    x0 = x0 / x1;
-    if (x0 > UINT32_MAX) {
-        x0 = UINT32_MAX;
-        overflow = 1;
+    a64 /= b32;
+    r = a64;
+    if (unlikely(a64 > UINT32_MAX)) {
+        return -1; /* r = UINT32_MAX, v = 1 */
+    }
+    return r;
+}
+
+uint64_t helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
+{
+    int64_t a64 = (uint32_t)a | ((uint64_t)env->y << 32);
+    int32_t b32 = b;
+    int32_t r;
+
+    if (b32 == 0) {
+        cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
     }
 
-    if (cc) {
-        env->cc_src2 = overflow;
-    }
-    return x0;
-}
-
-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)
-{
-    int overflow = 0;
-    int64_t x0;
-    int32_t x1;
-
-    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
-    x1 = (b & 0xffffffff);
-
-    if (x1 == 0) {
-        cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
-    } else if (x1 == -1 && x0 == INT64_MIN) {
-        x0 = INT32_MAX;
-        overflow = 1;
-    } else {
-        x0 = x0 / x1;
-        if ((int32_t) x0 != x0) {
-            x0 = x0 < 0 ? INT32_MIN : INT32_MAX;
-            overflow = 1;
-        }
+    if (unlikely(a64 == 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.
+         */
+        return (uint32_t)(b32 < 0 ? INT32_MAX : INT32_MIN) | (-1ull << 32);
     }
 
-    if (cc) {
-        env->cc_src2 = overflow;
+    a64 /= b;
+    r = a64;
+    if (unlikely(r != a64)) {
+        return (uint32_t)(a64 < 0 ? INT32_MIN : INT32_MAX) | (-1ull << 32);
     }
-    return x0;
-}
-
-target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
-{
-    return do_sdiv(env, a, b, 0, GETPC());
-}
-
-target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
-{
-    return do_sdiv(env, a, b, 1, GETPC());
+    return (uint32_t)r;
 }
 
 #ifdef TARGET_SPARC64
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index b11d89343b..fa4bad6d1f 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -693,22 +693,76 @@ static void gen_op_sdivx(TCGv dst, TCGv src1, TCGv src2)
 
 static void gen_op_udiv(TCGv dst, TCGv src1, TCGv src2)
 {
+#ifdef TARGET_SPARC64
     gen_helper_udiv(dst, tcg_env, src1, src2);
+    tcg_gen_ext32u_tl(dst, dst);
+#else
+    TCGv_i64 t64 = tcg_temp_new_i64();
+    gen_helper_udiv(t64, tcg_env, src1, src2);
+    tcg_gen_trunc_i64_tl(dst, t64);
+#endif
 }
 
 static void gen_op_sdiv(TCGv dst, TCGv src1, TCGv src2)
 {
+#ifdef TARGET_SPARC64
     gen_helper_sdiv(dst, tcg_env, src1, src2);
+    tcg_gen_ext32s_tl(dst, dst);
+#else
+    TCGv_i64 t64 = tcg_temp_new_i64();
+    gen_helper_sdiv(t64, tcg_env, src1, src2);
+    tcg_gen_trunc_i64_tl(dst, t64);
+#endif
 }
 
 static void gen_op_udivcc(TCGv dst, TCGv src1, TCGv src2)
 {
-    gen_helper_udiv_cc(dst, tcg_env, src1, src2);
+    TCGv_i64 t64;
+
+#ifdef TARGET_SPARC64
+    t64 = cpu_cc_V;
+#else
+    t64 = tcg_temp_new_i64();
+#endif
+
+    gen_helper_udiv(t64, tcg_env, src1, src2);
+
+#ifdef TARGET_SPARC64
+    tcg_gen_ext32u_tl(cpu_cc_N, t64);
+    tcg_gen_shri_tl(cpu_cc_V, t64, 32);
+    tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
+    tcg_gen_movi_tl(cpu_icc_C, 0);
+#else
+    tcg_gen_extr_i64_tl(cpu_cc_N, cpu_cc_V, t64);
+#endif
+    tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
+    tcg_gen_movi_tl(cpu_cc_C, 0);
+    tcg_gen_mov_tl(dst, cpu_cc_N);
 }
 
 static void gen_op_sdivcc(TCGv dst, TCGv src1, TCGv src2)
 {
-    gen_helper_sdiv_cc(dst, tcg_env, src1, src2);
+    TCGv_i64 t64;
+
+#ifdef TARGET_SPARC64
+    t64 = cpu_cc_V;
+#else
+    t64 = tcg_temp_new_i64();
+#endif
+
+    gen_helper_sdiv(t64, tcg_env, src1, src2);
+
+#ifdef TARGET_SPARC64
+    tcg_gen_ext32s_tl(cpu_cc_N, t64);
+    tcg_gen_shri_tl(cpu_cc_V, t64, 32);
+    tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N);
+    tcg_gen_movi_tl(cpu_icc_C, 0);
+#else
+    tcg_gen_extr_i64_tl(cpu_cc_N, cpu_cc_V, t64);
+#endif
+    tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
+    tcg_gen_movi_tl(cpu_cc_C, 0);
+    tcg_gen_mov_tl(dst, cpu_cc_N);
 }
 
 static void gen_op_taddcctv(TCGv dst, TCGv src1, TCGv src2)
@@ -3717,8 +3771,8 @@ TRANS(SMUL, MUL, do_logic, a, gen_op_smul, NULL)
 
 TRANS(UDIVX, 64, do_arith, a, -1, gen_op_udivx, NULL, NULL)
 TRANS(SDIVX, 64, do_arith, a, -1, gen_op_sdivx, NULL, NULL)
-TRANS(UDIV, DIV, do_arith, a, CC_OP_DIV, gen_op_udiv, NULL, gen_op_udivcc)
-TRANS(SDIV, DIV, do_arith, a, CC_OP_DIV, gen_op_sdiv, NULL, gen_op_sdivcc)
+TRANS(UDIV, DIV, do_arith, a, CC_OP_FLAGS, gen_op_udiv, NULL, gen_op_udivcc)
+TRANS(SDIV, DIV, do_arith, a, CC_OP_FLAGS, gen_op_sdiv, NULL, gen_op_sdivcc)
 
 /* TODO: Should have feature bit -- comes in with UltraSparc T2. */
 TRANS(POPC, 64, do_arith, a, -1, gen_op_popc, NULL, NULL)
@@ -3743,10 +3797,6 @@ static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a)
 static bool trans_ADDC(DisasContext *dc, arg_r_r_ri_cc *a)
 {
     switch (dc->cc_op) {
-    case CC_OP_DIV:
-        /* Carry is known to be zero.  Fall back to plain ADD.  */
-        return do_arith(dc, a, CC_OP_ADD,
-                        tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_add_cc);
     case CC_OP_ADD:
     case CC_OP_TADD:
     case CC_OP_TADDTV:
@@ -3766,10 +3816,6 @@ static bool trans_ADDC(DisasContext *dc, arg_r_r_ri_cc *a)
 static bool trans_SUBC(DisasContext *dc, arg_r_r_ri_cc *a)
 {
     switch (dc->cc_op) {
-    case CC_OP_DIV:
-        /* Carry is known to be zero.  Fall back to plain SUB.  */
-        return do_arith(dc, a, CC_OP_SUB,
-                        tcg_gen_sub_tl, tcg_gen_subi_tl, gen_op_sub_cc);
     case CC_OP_ADD:
     case CC_OP_TADD:
     case CC_OP_TADDTV:
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 05/21] target/sparc: Remove CC_OP_ADD, CC_OP_ADDX, CC_OP_TADD
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (3 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 04/21] target/sparc: Remove CC_OP_DIV Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 06/21] target/sparc: Remove CC_OP_SUB, CC_OP_SUBX, CC_OP_TSUB Richard Henderson
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 |  92 ---------------
 target/sparc/translate.c | 247 ++++++++++++++-------------------------
 3 files changed, 87 insertions(+), 255 deletions(-)

diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index b16d53b91f..4ee8e2dc92 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 5400dfec15..55bac722d2 100644
--- a/target/sparc/cc_helper.c
+++ b/target/sparc/cc_helper.c
@@ -57,28 +57,6 @@ static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
     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)
 {
@@ -90,17 +68,6 @@ static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
     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)
 {
@@ -128,53 +95,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 +110,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 +275,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 +285,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 fa4bad6d1f..cf121a237d 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -382,33 +382,71 @@ 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);
+    if (TARGET_LONG_BITS == 64) {
+        TCGv t = tcg_temp_new();
+        tcg_gen_extract_tl(t, cpu_icc_C, 32, 1);
+        return t;
+    }
+    return cpu_icc_C;
 }
 
-static TCGv_i32 gen_add32_carry32(void)
+static void gen_op_addcc_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
+    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);
+    if (TARGET_LONG_BITS == 64) {
+        /*
+         * 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);
+    }
+    tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
+    tcg_gen_mov_tl(dst, cpu_cc_N);
+}
 
-    carry_32 = tcg_temp_new_i32();
-    tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32);
+static void gen_op_addcc(TCGv dst, TCGv src1, TCGv src2)
+{
+    gen_op_addcc_int(dst, src1, src2, NULL);
+}
 
-    return carry_32;
+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_V, cpu_cc_V, 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_sub32_carry32(void)
@@ -432,89 +470,6 @@ static TCGv_i32 gen_sub32_carry32(void)
     return carry_32;
 }
 
-static void gen_op_addc_int(TCGv dst, TCGv src1, TCGv src2,
-                            TCGv_i32 carry_32, bool update_cc)
-{
-    tcg_gen_add_tl(dst, src1, src2);
-
-#ifdef TARGET_SPARC64
-    TCGv carry = tcg_temp_new();
-    tcg_gen_extu_i32_tl(carry, carry_32);
-    tcg_gen_add_tl(dst, dst, carry);
-#else
-    tcg_gen_add_i32(dst, dst, carry_32);
-#endif
-
-    if (update_cc) {
-        tcg_debug_assert(dst == cpu_cc_dst);
-        tcg_gen_mov_tl(cpu_cc_src, src1);
-        tcg_gen_mov_tl(cpu_cc_src2, src2);
-    }
-}
-
-static void gen_op_addc_int_add(TCGv dst, TCGv src1, TCGv src2, bool update_cc)
-{
-    TCGv discard;
-
-    if (TARGET_LONG_BITS == 64) {
-        gen_op_addc_int(dst, src1, src2, gen_add32_carry32(), update_cc);
-        return;
-    }
-
-    /*
-     * 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.
-     */
-    discard = tcg_temp_new();
-    tcg_gen_add2_tl(discard, dst, cpu_cc_src, src1, cpu_cc_src2, src2);
-
-    if (update_cc) {
-        tcg_debug_assert(dst == cpu_cc_dst);
-        tcg_gen_mov_tl(cpu_cc_src, src1);
-        tcg_gen_mov_tl(cpu_cc_src2, src2);
-    }
-}
-
-static void gen_op_addc_add(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_addc_int_add(dst, src1, src2, false);
-}
-
-static void gen_op_addccc_add(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_addc_int_add(dst, src1, src2, true);
-}
-
-static void gen_op_addc_sub(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_addc_int(dst, src1, src2, gen_sub32_carry32(), false);
-}
-
-static void gen_op_addccc_sub(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_addc_int(dst, src1, src2, gen_sub32_carry32(), true);
-}
-
-static void gen_op_addc_int_generic(TCGv dst, TCGv src1, TCGv src2,
-                                    bool update_cc)
-{
-    TCGv_i32 carry_32 = tcg_temp_new_i32();
-    gen_helper_compute_C_icc(carry_32, tcg_env);
-    gen_op_addc_int(dst, src1, src2, carry_32, update_cc);
-}
-
-static void gen_op_addc_generic(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_addc_int_generic(dst, src1, src2, false);
-}
-
-static void gen_op_addccc_generic(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_addc_int_generic(dst, src1, src2, true);
-}
-
 static void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
 {
     tcg_gen_mov_tl(cpu_cc_src, src1);
@@ -545,16 +500,6 @@ static void gen_op_subc_int(TCGv dst, TCGv src1, TCGv src2,
     }
 }
 
-static void gen_op_subc_add(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_subc_int(dst, src1, src2, gen_add32_carry32(), false);
-}
-
-static void gen_op_subccc_add(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_subc_int(dst, src1, src2, gen_add32_carry32(), true);
-}
-
 static void gen_op_subc_int_sub(TCGv dst, TCGv src1, TCGv src2, bool update_cc)
 {
     TCGv discard;
@@ -609,39 +554,39 @@ static void gen_op_subccc_generic(TCGv dst, TCGv src1, TCGv src2)
 
 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)
@@ -3749,12 +3694,12 @@ static bool do_logic(DisasContext *dc, arg_r_r_ri_cc *a,
     return do_arith_int(dc, a, CC_OP_FLAGS, func, funci, a->cc);
 }
 
-TRANS(ADD, ALL, do_arith, a, CC_OP_ADD,
-      tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_add_cc)
+TRANS(ADD, ALL, do_arith, a, CC_OP_FLAGS,
+      tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_addcc)
 TRANS(SUB, ALL, do_arith, a, CC_OP_SUB,
       tcg_gen_sub_tl, tcg_gen_subi_tl, gen_op_sub_cc)
 
-TRANS(TADDcc, ALL, do_arith, a, CC_OP_TADD, NULL, NULL, gen_op_add_cc)
+TRANS(TADDcc, ALL, do_arith, a, CC_OP_FLAGS, NULL, NULL, gen_op_taddcc)
 TRANS(TSUBcc, ALL, do_arith, a, CC_OP_TSUB, NULL, NULL, gen_op_sub_cc)
 TRANS(TADDccTV, ALL, do_arith, a, CC_OP_TADDTV, NULL, NULL, gen_op_taddcctv)
 TRANS(TSUBccTV, ALL, do_arith, a, CC_OP_TSUBTV, NULL, NULL, gen_op_tsubcctv)
@@ -3796,31 +3741,13 @@ static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a)
 
 static bool trans_ADDC(DisasContext *dc, arg_r_r_ri_cc *a)
 {
-    switch (dc->cc_op) {
-    case CC_OP_ADD:
-    case CC_OP_TADD:
-    case CC_OP_TADDTV:
-        return do_arith(dc, a, CC_OP_ADDX,
-                        gen_op_addc_add, NULL, gen_op_addccc_add);
-    case CC_OP_SUB:
-    case CC_OP_TSUB:
-    case CC_OP_TSUBTV:
-        return do_arith(dc, a, CC_OP_ADDX,
-                        gen_op_addc_sub, NULL, gen_op_addccc_sub);
-    default:
-        return do_arith(dc, a, CC_OP_ADDX,
-                        gen_op_addc_generic, NULL, gen_op_addccc_generic);
-    }
+    update_psr(dc);
+    return do_arith(dc, a, CC_OP_FLAGS, gen_op_addc, NULL, gen_op_addccc);
 }
 
 static bool trans_SUBC(DisasContext *dc, arg_r_r_ri_cc *a)
 {
     switch (dc->cc_op) {
-    case CC_OP_ADD:
-    case CC_OP_TADD:
-    case CC_OP_TADDTV:
-        return do_arith(dc, a, CC_OP_SUBX,
-                        gen_op_subc_add, NULL, gen_op_subccc_add);
     case CC_OP_SUB:
     case CC_OP_TSUB:
     case CC_OP_TSUBTV:
@@ -3835,7 +3762,7 @@ static bool trans_SUBC(DisasContext *dc, arg_r_r_ri_cc *a)
 static bool trans_MULScc(DisasContext *dc, arg_r_r_ri_cc *a)
 {
     update_psr(dc);
-    return do_arith(dc, a, CC_OP_ADD, NULL, NULL, gen_op_mulscc);
+    return do_arith(dc, a, CC_OP_FLAGS, NULL, NULL, 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 v2 06/21] target/sparc: Remove CC_OP_SUB, CC_OP_SUBX, CC_OP_TSUB
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (4 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 05/21] target/sparc: Remove CC_OP_ADD, CC_OP_ADDX, CC_OP_TADD Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 07/21] target/sparc: Remove CC_OP_TADDTV, CC_OP_TSUBTV Richard Henderson
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 | 103 --------------------
 target/sparc/translate.c | 203 +++++++++------------------------------
 3 files changed, 45 insertions(+), 264 deletions(-)

diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 4ee8e2dc92..9884bd416a 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 55bac722d2..20d451aa65 100644
--- a/target/sparc/cc_helper.c
+++ b/target/sparc/cc_helper.c
@@ -100,16 +100,6 @@ 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;
@@ -129,29 +119,6 @@ static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
     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)
 {
@@ -163,17 +130,6 @@ static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
     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)
 {
@@ -201,64 +157,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;
@@ -276,9 +179,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 },
 };
 
@@ -286,9 +186,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 cf121a237d..d119ce4c94 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -449,107 +449,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_sub32_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 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;
+    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);
+    }
+    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
-
-    carry_32 = tcg_temp_new_i32();
-    tcg_gen_setcond_i32(TCG_COND_LTU, carry_32, cc_src1_32, cc_src2_32);
-
-    return carry_32;
+    tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N);
+    tcg_gen_mov_tl(dst, cpu_cc_N);
 }
 
-static void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
+static void gen_op_subcc(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);
+    gen_op_subcc_int(dst, src1, src2, NULL);
 }
 
-static void gen_op_subc_int(TCGv dst, TCGv src1, TCGv src2,
-                            TCGv_i32 carry_32, bool update_cc)
+static void gen_op_tsubcc(TCGv dst, TCGv src1, TCGv src2)
 {
-    TCGv carry;
+    TCGv t = tcg_temp_new();
 
-#if TARGET_LONG_BITS == 64
-    carry = tcg_temp_new();
-    tcg_gen_extu_i32_i64(carry, carry_32);
-#else
-    carry = carry_32;
-#endif
+    /* 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_V, cpu_cc_V, 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);
-
-    if (update_cc) {
-        tcg_debug_assert(dst == cpu_cc_dst);
-        tcg_gen_mov_tl(cpu_cc_src, src1);
-        tcg_gen_mov_tl(cpu_cc_src2, src2);
-    }
+    tcg_gen_sub_tl(dst, dst, gen_carry32());
 }
 
-static void gen_op_subc_int_sub(TCGv dst, TCGv src1, TCGv src2, bool update_cc)
+static void gen_op_subccc(TCGv dst, TCGv src1, TCGv src2)
 {
-    TCGv discard;
-
-    if (TARGET_LONG_BITS == 64) {
-        gen_op_subc_int(dst, src1, src2, gen_sub32_carry32(), update_cc);
-        return;
-    }
-
-    /*
-     * We can re-use the host's hardware carry generation by using
-     * a SUB2 opcode.  We discard the low part of the output.
-     */
-    discard = tcg_temp_new();
-    tcg_gen_sub2_tl(discard, dst, cpu_cc_src, src1, cpu_cc_src2, src2);
-
-    if (update_cc) {
-        tcg_debug_assert(dst == cpu_cc_dst);
-        tcg_gen_mov_tl(cpu_cc_src, src1);
-        tcg_gen_mov_tl(cpu_cc_src2, src2);
-    }
-}
-
-static void gen_op_subc_sub(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_subc_int_sub(dst, src1, src2, false);
-}
-
-static void gen_op_subccc_sub(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_subc_int_sub(dst, src1, src2, true);
-}
-
-static void gen_op_subc_int_generic(TCGv dst, TCGv src1, TCGv src2,
-                                    bool update_cc)
-{
-    TCGv_i32 carry_32 = tcg_temp_new_i32();
-
-    gen_helper_compute_C_icc(carry_32, tcg_env);
-    gen_op_subc_int(dst, src1, src2, carry_32, update_cc);
-}
-
-static void gen_op_subc_generic(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_subc_int_generic(dst, src1, src2, false);
-}
-
-static void gen_op_subccc_generic(TCGv dst, TCGv src1, TCGv src2)
-{
-    gen_op_subc_int_generic(dst, src1, src2, true);
+    gen_op_subcc_int(dst, src1, src2, gen_carry32());
 }
 
 static void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
@@ -1097,65 +1048,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;
@@ -3696,11 +3593,11 @@ static bool do_logic(DisasContext *dc, arg_r_r_ri_cc *a,
 
 TRANS(ADD, ALL, do_arith, a, CC_OP_FLAGS,
       tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_addcc)
-TRANS(SUB, ALL, do_arith, a, CC_OP_SUB,
-      tcg_gen_sub_tl, tcg_gen_subi_tl, gen_op_sub_cc)
+TRANS(SUB, ALL, do_arith, a, CC_OP_FLAGS,
+      tcg_gen_sub_tl, tcg_gen_subi_tl, gen_op_subcc)
 
 TRANS(TADDcc, ALL, do_arith, a, CC_OP_FLAGS, NULL, NULL, gen_op_taddcc)
-TRANS(TSUBcc, ALL, do_arith, a, CC_OP_TSUB, NULL, NULL, gen_op_sub_cc)
+TRANS(TSUBcc, ALL, do_arith, a, CC_OP_FLAGS, NULL, NULL, gen_op_tsubcc)
 TRANS(TADDccTV, ALL, do_arith, a, CC_OP_TADDTV, NULL, NULL, gen_op_taddcctv)
 TRANS(TSUBccTV, ALL, do_arith, a, CC_OP_TSUBTV, NULL, NULL, gen_op_tsubcctv)
 
@@ -3747,16 +3644,8 @@ static bool trans_ADDC(DisasContext *dc, arg_r_r_ri_cc *a)
 
 static bool trans_SUBC(DisasContext *dc, arg_r_r_ri_cc *a)
 {
-    switch (dc->cc_op) {
-    case CC_OP_SUB:
-    case CC_OP_TSUB:
-    case CC_OP_TSUBTV:
-        return do_arith(dc, a, CC_OP_SUBX,
-                        gen_op_subc_sub, NULL, gen_op_subccc_sub);
-    default:
-        return do_arith(dc, a, CC_OP_SUBX,
-                        gen_op_subc_generic, NULL, gen_op_subccc_generic);
-    }
+    update_psr(dc);
+    return do_arith(dc, a, CC_OP_FLAGS, gen_op_subc, NULL, gen_op_subccc);
 }
 
 static bool trans_MULScc(DisasContext *dc, arg_r_r_ri_cc *a)
@@ -3777,11 +3666,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 v2 07/21] target/sparc: Remove CC_OP_TADDTV, CC_OP_TSUBTV
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (5 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 06/21] target/sparc: Remove CC_OP_SUB, CC_OP_SUBX, CC_OP_TSUB Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 08/21] target/sparc: Remove CC_OP leftovers Richard Henderson
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 | 190 +--------------------------------------
 target/sparc/helper.c    |  36 ++++++--
 target/sparc/translate.c |   4 +-
 4 files changed, 32 insertions(+), 200 deletions(-)

diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 9884bd416a..a7999eaab5 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 20d451aa65..05f1479aea 100644
--- a/target/sparc/cc_helper.c
+++ b/target/sparc/cc_helper.c
@@ -21,198 +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;
-}
-
-#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_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 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;
-}
-
-#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_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->icc_C = (uint64_t)icc << (32 - PSR_CARRY_SHIFT);
-    env->xcc_C = (xcc >> PSR_CARRY_SHIFT) & 1;
-    env->xcc_Z = ~xcc & PSR_ZERO;
-#else
-    env->cc_N = -(icc & PSR_NEG);
-    env->cc_V = -(icc & PSR_OVF);
-    env->icc_C = (icc >> PSR_CARRY_SHIFT) & 1;
-#endif
-    env->icc_Z = ~icc & PSR_ZERO;
-
-    CC_OP = CC_OP_FLAGS;
+    g_assert_not_reached();
 }
 
 uint32_t helper_compute_C_icc(CPUSPARCState *env)
@@ -224,5 +38,5 @@ uint32_t helper_compute_C_icc(CPUSPARCState *env)
         return env->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 53eec693dd..6117e99b55 100644
--- a/target/sparc/helper.c
+++ b/target/sparc/helper.c
@@ -156,7 +156,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) {
@@ -166,13 +166,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_src = src1;
-    env->cc_src2 = src2;
+    env->cc_V = v;
+    env->cc_N = dst;
+    env->icc_Z = dst;
+#ifdef TARGET_SPARC64
+    env->xcc_Z = dst;
+    env->icc_C = dst ^ src1 ^ src2;
+    env->xcc_C = dst < src1;
+#else
+    env->icc_C = dst < src1;
+#endif
+
     return dst;
 
  tag_overflow:
@@ -182,7 +192,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) {
@@ -192,13 +202,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_src = src1;
-    env->cc_src2 = src2;
+    env->cc_V = v;
+    env->cc_N = dst;
+    env->icc_Z = dst;
+#ifdef TARGET_SPARC64
+    env->xcc_Z = dst;
+    env->icc_C = dst ^ src1 ^ src2;
+    env->xcc_C = src1 < src2;
+#else
+    env->icc_C = src1 < src2;
+#endif
+
     return dst;
 
  tag_overflow:
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index d119ce4c94..7703166ebd 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -3598,8 +3598,8 @@ TRANS(SUB, ALL, do_arith, a, CC_OP_FLAGS,
 
 TRANS(TADDcc, ALL, do_arith, a, CC_OP_FLAGS, NULL, NULL, gen_op_taddcc)
 TRANS(TSUBcc, ALL, do_arith, a, CC_OP_FLAGS, NULL, NULL, gen_op_tsubcc)
-TRANS(TADDccTV, ALL, do_arith, a, CC_OP_TADDTV, NULL, NULL, gen_op_taddcctv)
-TRANS(TSUBccTV, ALL, do_arith, a, CC_OP_TSUBTV, NULL, NULL, gen_op_tsubcctv)
+TRANS(TADDccTV, ALL, do_arith, a, CC_OP_FLAGS, NULL, NULL, gen_op_taddcctv)
+TRANS(TSUBccTV, ALL, do_arith, a, CC_OP_FLAGS, NULL, NULL, gen_op_tsubcctv)
 
 TRANS(AND, ALL, do_logic, a, tcg_gen_and_tl, tcg_gen_andi_tl)
 TRANS(XOR, ALL, do_logic, a, tcg_gen_xor_tl, tcg_gen_xori_tl)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 08/21] target/sparc: Remove CC_OP leftovers
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (6 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 07/21] target/sparc: Remove CC_OP_TADDTV, CC_OP_TSUBTV Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 09/21] target/sparc: Remove DisasCompare.is_bool Richard Henderson
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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    | 115 ++++++++----------------------------
 target/sparc/win_helper.c   |   7 ---
 target/sparc/meson.build    |   1 -
 10 files changed, 26 insertions(+), 178 deletions(-)
 delete mode 100644 target/sparc/cc_helper.c

diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index a7999eaab5..3e361a5b75 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 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 a7b0079c3b..decd94c0d6 100644
--- a/target/sparc/helper.h
+++ b/target/sparc/helper.h
@@ -148,5 +148,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 c1a2362041..3c1bde00dd 100644
--- a/linux-user/sparc/cpu_loop.c
+++ b/linux-user/sparc/cpu_loop.c
@@ -222,11 +222,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 05f1479aea..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->icc_C, 32, 1);
-#else
-        return env->icc_C;
-#endif
-    }
-    g_assert_not_reached();
-}
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index bb1a155510..befa7fc4eb 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 7703166ebd..7c4fcf8326 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -105,8 +105,6 @@
 
 /* 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;
@@ -172,7 +170,6 @@ typedef struct DisasContext {
 #endif
 #endif
 
-    uint32_t cc_op;  /* current CC operation */
     sparc_def_t *def;
 #ifdef TARGET_SPARC64
     int fprs_dirty;
@@ -962,14 +959,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);
@@ -1048,20 +1037,9 @@ 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;
 
     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 = t1 = tcg_temp_new();
     cmp->c2 = tcg_constant_tl(0);
 
@@ -2739,7 +2717,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;
 }
@@ -2852,7 +2829,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;
 }
@@ -3257,8 +3233,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;
     dc->base.is_jmp = DISAS_EXIT;
 }
 
@@ -3522,7 +3496,7 @@ static bool trans_NOP(DisasContext *dc, arg_NOP *a)
 TRANS(NOP_v7, 32, trans_NOP, a)
 TRANS(NOP_v9, 64, trans_NOP, a)
 
-static bool do_arith_int(DisasContext *dc, arg_r_r_ri_cc *a, int cc_op,
+static bool do_arith_int(DisasContext *dc, arg_r_r_ri_cc *a,
                          void (*func)(TCGv, TCGv, TCGv),
                          void (*funci)(TCGv, TCGv, target_long),
                          bool logic_cc)
@@ -3536,8 +3510,6 @@ static bool do_arith_int(DisasContext *dc, arg_r_r_ri_cc *a, int cc_op,
 
     if (logic_cc) {
         dst = cpu_cc_N;
-    } else if (a->cc && cc_op > CC_OP_FLAGS) {
-        dst = cpu_cc_dst;
     } else {
         dst = gen_dest_gpr(dc, a->rd);
     }
@@ -3564,42 +3536,36 @@ static bool do_arith_int(DisasContext *dc, arg_r_r_ri_cc *a, int cc_op,
     }
 
     gen_store_gpr(dc, a->rd, dst);
-
-    if (a->cc) {
-        tcg_gen_movi_i32(cpu_cc_op, cc_op);
-        dc->cc_op = cc_op;
-    }
     return advance_pc(dc);
 }
 
-static bool do_arith(DisasContext *dc, arg_r_r_ri_cc *a, int cc_op,
+static bool do_arith(DisasContext *dc, arg_r_r_ri_cc *a,
                      void (*func)(TCGv, TCGv, TCGv),
                      void (*funci)(TCGv, TCGv, target_long),
                      void (*func_cc)(TCGv, TCGv, TCGv))
 {
     if (a->cc) {
-        assert(cc_op >= 0);
-        return do_arith_int(dc, a, cc_op, func_cc, NULL, false);
+        return do_arith_int(dc, a, func_cc, NULL, false);
     }
-    return do_arith_int(dc, a, cc_op, func, funci, false);
+    return do_arith_int(dc, a, func, funci, false);
 }
 
 static bool do_logic(DisasContext *dc, arg_r_r_ri_cc *a,
                      void (*func)(TCGv, TCGv, TCGv),
                      void (*funci)(TCGv, TCGv, target_long))
 {
-    return do_arith_int(dc, a, CC_OP_FLAGS, func, funci, a->cc);
+    return do_arith_int(dc, a, func, funci, a->cc);
 }
 
-TRANS(ADD, ALL, do_arith, a, CC_OP_FLAGS,
-      tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_addcc)
-TRANS(SUB, ALL, do_arith, a, CC_OP_FLAGS,
-      tcg_gen_sub_tl, tcg_gen_subi_tl, gen_op_subcc)
+TRANS(ADD, ALL, do_arith, a, tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_addcc)
+TRANS(SUB, ALL, do_arith, a, tcg_gen_sub_tl, tcg_gen_subi_tl, gen_op_subcc)
+TRANS(ADDC, ALL, do_arith, a, gen_op_addc, NULL, gen_op_addccc)
+TRANS(SUBC, ALL, do_arith, a, gen_op_subc, NULL, gen_op_subccc)
 
-TRANS(TADDcc, ALL, do_arith, a, CC_OP_FLAGS, NULL, NULL, gen_op_taddcc)
-TRANS(TSUBcc, ALL, do_arith, a, CC_OP_FLAGS, NULL, NULL, gen_op_tsubcc)
-TRANS(TADDccTV, ALL, do_arith, a, CC_OP_FLAGS, NULL, NULL, gen_op_taddcctv)
-TRANS(TSUBccTV, ALL, do_arith, a, CC_OP_FLAGS, NULL, NULL, gen_op_tsubcctv)
+TRANS(TADDcc, ALL, do_arith, a, NULL, NULL, gen_op_taddcc)
+TRANS(TSUBcc, ALL, do_arith, a, NULL, NULL, gen_op_tsubcc)
+TRANS(TADDccTV, ALL, do_arith, a, NULL, NULL, gen_op_taddcctv)
+TRANS(TSUBccTV, ALL, do_arith, a, NULL, NULL, gen_op_tsubcctv)
 
 TRANS(AND, ALL, do_logic, a, tcg_gen_and_tl, tcg_gen_andi_tl)
 TRANS(XOR, ALL, do_logic, a, tcg_gen_xor_tl, tcg_gen_xori_tl)
@@ -3607,17 +3573,18 @@ TRANS(ANDN, ALL, do_logic, a, tcg_gen_andc_tl, NULL)
 TRANS(ORN, ALL, do_logic, a, tcg_gen_orc_tl, NULL)
 TRANS(XORN, ALL, do_logic, a, tcg_gen_eqv_tl, NULL)
 
-TRANS(MULX, 64, do_arith, a, -1, tcg_gen_mul_tl, tcg_gen_muli_tl, NULL)
+TRANS(MULX, 64, do_arith, a, tcg_gen_mul_tl, tcg_gen_muli_tl, NULL)
 TRANS(UMUL, MUL, do_logic, a, gen_op_umul, NULL)
 TRANS(SMUL, MUL, do_logic, a, gen_op_smul, NULL)
+TRANS(MULScc, ALL, do_arith, a, NULL, NULL, gen_op_mulscc)
 
-TRANS(UDIVX, 64, do_arith, a, -1, gen_op_udivx, NULL, NULL)
-TRANS(SDIVX, 64, do_arith, a, -1, gen_op_sdivx, NULL, NULL)
-TRANS(UDIV, DIV, do_arith, a, CC_OP_FLAGS, gen_op_udiv, NULL, gen_op_udivcc)
-TRANS(SDIV, DIV, do_arith, a, CC_OP_FLAGS, gen_op_sdiv, NULL, gen_op_sdivcc)
+TRANS(UDIVX, 64, do_arith, a, gen_op_udivx, NULL, NULL)
+TRANS(SDIVX, 64, do_arith, a, gen_op_sdivx, NULL, NULL)
+TRANS(UDIV, DIV, do_arith, a, gen_op_udiv, NULL, gen_op_udivcc)
+TRANS(SDIV, DIV, do_arith, a, gen_op_sdiv, NULL, gen_op_sdivcc)
 
 /* TODO: Should have feature bit -- comes in with UltraSparc T2. */
-TRANS(POPC, 64, do_arith, a, -1, gen_op_popc, NULL, NULL)
+TRANS(POPC, 64, do_arith, a, gen_op_popc, NULL, NULL)
 
 static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a)
 {
@@ -3636,24 +3603,6 @@ static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a)
     return do_logic(dc, a, tcg_gen_or_tl, tcg_gen_ori_tl);
 }
 
-static bool trans_ADDC(DisasContext *dc, arg_r_r_ri_cc *a)
-{
-    update_psr(dc);
-    return do_arith(dc, a, CC_OP_FLAGS, gen_op_addc, NULL, gen_op_addccc);
-}
-
-static bool trans_SUBC(DisasContext *dc, arg_r_r_ri_cc *a)
-{
-    update_psr(dc);
-    return do_arith(dc, a, CC_OP_FLAGS, gen_op_subc, NULL, gen_op_subccc);
-}
-
-static bool trans_MULScc(DisasContext *dc, arg_r_r_ri_cc *a)
-{
-    update_psr(dc);
-    return do_arith(dc, a, CC_OP_FLAGS, NULL, NULL, gen_op_mulscc);
-}
-
 static bool gen_edge(DisasContext *dc, arg_r_r_r *a,
                      int width, bool cc, bool left)
 {
@@ -3667,8 +3616,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;
     }
 
     /*
@@ -5080,7 +5027,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);
@@ -5269,13 +5215,6 @@ void sparc_tcg_init(void)
         "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
     };
 
-    static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
-#ifdef TARGET_SPARC64
-        { &cpu_fprs, offsetof(CPUSPARCState, fprs), "fprs" },
-#endif
-        { &cpu_cc_op, offsetof(CPUSPARCState, cc_op), "cc_op" },
-    };
-
     static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {
 #ifdef TARGET_SPARC64
         { &cpu_gsr, offsetof(CPUSPARCState, gsr), "gsr" },
@@ -5287,9 +5226,6 @@ void sparc_tcg_init(void)
         { &cpu_icc_Z, offsetof(CPUSPARCState, icc_Z), "icc_Z" },
         { &cpu_icc_C, offsetof(CPUSPARCState, 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" },
@@ -5303,10 +5239,6 @@ void sparc_tcg_init(void)
                                          offsetof(CPUSPARCState, regwptr),
                                          "regwptr");
 
-    for (i = 0; i < ARRAY_SIZE(r32); ++i) {
-        *r32[i].ptr = tcg_global_mem_new_i32(tcg_env, r32[i].off, r32[i].name);
-    }
-
     for (i = 0; i < ARRAY_SIZE(rtl); ++i) {
         *rtl[i].ptr = tcg_global_mem_new(tcg_env, rtl[i].off, rtl[i].name);
     }
@@ -5329,6 +5261,11 @@ void sparc_tcg_init(void)
                                             offsetof(CPUSPARCState, fpr[i]),
                                             fregnames[i]);
     }
+
+#ifdef TARGET_SPARC64
+    cpu_fprs = tcg_global_mem_new_i32(tcg_env,
+                                      offsetof(CPUSPARCState, fprs), "fprs");
+#endif
 }
 
 void sparc_restore_state_to_opc(CPUState *cs,
diff --git a/target/sparc/win_helper.c b/target/sparc/win_helper.c
index f0ff6bf5db..16d1c70fe7 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->icc_Z == 0) << PSR_ZERO_SHIFT;
@@ -103,7 +101,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
@@ -272,8 +269,6 @@ target_ulong cpu_get_ccr(CPUSPARCState *env)
 {
     target_ulong ccr = 0;
 
-    helper_compute_psr(env);
-
     ccr |= (env->icc_C >> 32) & 1;
     ccr |= ((int32_t)env->cc_V < 0) << 1;
     ccr |= ((int32_t)env->icc_Z == 0) << 2;
@@ -295,8 +290,6 @@ void cpu_put_ccr(CPUSPARCState *env, target_ulong val)
     env->xcc_C = (val >> 4) & 1;
     env->icc_Z = ~val & 0x04;
     env->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 v2 09/21] target/sparc: Remove DisasCompare.is_bool
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (7 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 08/21] target/sparc: Remove CC_OP leftovers Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 10/21] target/sparc: Change DisasCompare.c2 to int Richard Henderson
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 7c4fcf8326..464f1607e3 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -180,7 +180,6 @@ typedef struct DisasContext {
 
 typedef struct {
     TCGCond cond;
-    bool is_bool;
     TCGv c1, c2;
 } DisasCompare;
 
@@ -1039,7 +1038,6 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
 {
     TCGv t1;
 
-    cmp->is_bool = false;
     cmp->c1 = t1 = tcg_temp_new();
     cmp->c2 = tcg_constant_tl(0);
 
@@ -1104,7 +1102,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) {
             tcg_gen_mov_tl(t1, cpu_cc_C);
         } else {
@@ -1132,7 +1129,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;
     }
 }
 
@@ -1143,7 +1139,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);
 
@@ -1230,7 +1225,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);
 }
@@ -2232,18 +2226,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);
@@ -2445,8 +2435,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_xor_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 v2 10/21] target/sparc: Change DisasCompare.c2 to int
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (8 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 09/21] target/sparc: Remove DisasCompare.is_bool Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 11/21] target/sparc: Always copy conditions into a new temporary Richard Henderson
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 | 33 ++++++++++++++++++---------------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 464f1607e3..a405512e6c 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -180,7 +180,8 @@ typedef struct DisasContext {
 
 typedef struct {
     TCGCond cond;
-    TCGv c1, c2;
+    TCGv c1;
+    int c2;
 } DisasCompare;
 
 // This function uses non-native bit order
@@ -1039,12 +1040,12 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond,
     TCGv t1;
 
     cmp->c1 = t1 = tcg_temp_new();
-    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: Z */
@@ -1140,7 +1141,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:
@@ -1226,7 +1227,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)
@@ -2232,7 +2233,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);
@@ -2252,7 +2253,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);
@@ -2266,10 +2267,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);
@@ -2409,7 +2411,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);
@@ -2423,7 +2425,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;
@@ -2438,9 +2440,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_xor_tl(cpu_cond, cmp->c1, cmp->c2);
+                tcg_gen_xori_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);
             }
         }
     }
@@ -2612,7 +2614,7 @@ static bool do_tcc(DisasContext *dc, int cond, int cc,
     flush_cond(dc);
     lab = delay_exceptionv(dc, trap);
     gen_compare(&cmp, cc, 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);
 }
@@ -3849,8 +3851,9 @@ static TCGv gen_rs2_or_imm(DisasContext *dc, bool imm, int rs2_or_imm)
 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 v2 11/21] target/sparc: Always copy conditions into a new temporary
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (9 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 10/21] target/sparc: Change DisasCompare.c2 to int Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 12/21] target/sparc: Do flush_cond in advance_jump_cond Richard Henderson
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index a405512e6c..dd6d43d1f1 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -1226,8 +1226,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 v2 12/21] target/sparc: Do flush_cond in advance_jump_cond
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (10 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 11/21] target/sparc: Always copy conditions into a new temporary Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 13/21] target/sparc: Merge gen_branch2 into advance_pc Richard Henderson
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index dd6d43d1f1..2e7deb5e33 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -2407,7 +2407,10 @@ static bool advance_jump_uncond_always(DisasContext *dc, bool annul,
 static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
                               bool annul, target_ulong dest)
 {
-    target_ulong npc = dc->npc;
+    target_ulong npc;
+
+    flush_cond(dc);
+    npc = dc->npc;
 
     if (annul) {
         TCGLabel *l1 = gen_new_label();
@@ -2481,8 +2484,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);
     }
@@ -2505,8 +2506,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);
     }
@@ -2527,7 +2526,6 @@ static bool trans_BPr(DisasContext *dc, arg_BPr *a)
         return false;
     }
 
-    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 v2 13/21] target/sparc: Merge gen_branch2 into advance_pc
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (11 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 12/21] target/sparc: Do flush_cond in advance_jump_cond Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 14/21] target/sparc: Merge advance_jump_uncond_{never, always} into advance_jump_cond Richard Henderson
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 2e7deb5e33..e134ba8821 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -908,19 +908,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]);
@@ -2352,6 +2339,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:
@@ -2359,11 +2348,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 v2 14/21] target/sparc: Merge advance_jump_uncond_{never, always} into advance_jump_cond
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (12 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 13/21] target/sparc: Merge gen_branch2 into advance_pc Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 15/21] target/sparc: Pass displacement to advance_jump_cond Richard Henderson
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 | 74 ++++++++++++++++------------------------
 1 file changed, 30 insertions(+), 44 deletions(-)

diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index e134ba8821..cbee5435a3 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -2378,37 +2378,37 @@ 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;
 
+    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) {
+        npc = dc->npc;
+        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);
     npc = dc->npc;
 
@@ -2478,15 +2478,8 @@ static bool do_bpcc(DisasContext *dc, arg_bcc *a)
     target_long target = address_mask_i(dc, dc->pc + a->i * 4);
     DisasCompare cmp;
 
-    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(Bicc, ALL, do_bpcc, a)
@@ -2500,15 +2493,8 @@ static bool do_fbpfcc(DisasContext *dc, arg_bcc *a)
     if (gen_trap_ifnofpu(dc)) {
         return true;
     }
-    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 v2 15/21] target/sparc: Pass displacement to advance_jump_cond
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (13 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 14/21] target/sparc: Merge advance_jump_uncond_{never, always} into advance_jump_cond Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 16/21] target/sparc: Merge gen_op_next_insn into only caller Richard Henderson
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/sparc/translate.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index cbee5435a3..1233911b69 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -2379,8 +2379,9 @@ static bool advance_pc(DisasContext *dc)
  */
 
 static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
-                              bool annul, target_ulong dest)
+                              bool annul, int disp)
 {
+    target_ulong dest = address_mask_i(dc, dc->pc + disp * 4);
     target_ulong npc;
 
     if (cmp->cond == TCG_COND_ALWAYS) {
@@ -2475,11 +2476,10 @@ static bool gen_trap_float128(DisasContext *dc)
 
 static bool do_bpcc(DisasContext *dc, arg_bcc *a)
 {
-    target_long target = address_mask_i(dc, dc->pc + a->i * 4);
     DisasCompare cmp;
 
     gen_compare(&cmp, a->cc, a->cond, dc);
-    return advance_jump_cond(dc, &cmp, a->a, target);
+    return advance_jump_cond(dc, &cmp, a->a, a->i);
 }
 
 TRANS(Bicc, ALL, do_bpcc, a)
@@ -2487,14 +2487,13 @@ TRANS(BPcc,  64, do_bpcc, a)
 
 static bool do_fbpfcc(DisasContext *dc, arg_bcc *a)
 {
-    target_long target = address_mask_i(dc, dc->pc + a->i * 4);
     DisasCompare cmp;
 
     if (gen_trap_ifnofpu(dc)) {
         return true;
     }
     gen_fcompare(&cmp, a->cc, a->cond);
-    return advance_jump_cond(dc, &cmp, a->a, target);
+    return advance_jump_cond(dc, &cmp, a->a, a->i);
 }
 
 TRANS(FBPfcc,  64, do_fbpfcc, a)
@@ -2502,7 +2501,6 @@ TRANS(FBfcc,  ALL, do_fbpfcc, a)
 
 static bool trans_BPr(DisasContext *dc, arg_BPr *a)
 {
-    target_long target = address_mask_i(dc, dc->pc + a->i * 4);
     DisasCompare cmp;
 
     if (!avail_64(dc)) {
@@ -2513,7 +2511,7 @@ static bool trans_BPr(DisasContext *dc, arg_BPr *a)
     }
 
     gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1));
-    return advance_jump_cond(dc, &cmp, a->a, target);
+    return advance_jump_cond(dc, &cmp, a->a, a->i);
 }
 
 static bool trans_CALL(DisasContext *dc, arg_CALL *a)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 16/21] target/sparc: Merge gen_op_next_insn into only caller
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (14 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 15/21] target/sparc: Pass displacement to advance_jump_cond Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 17/21] target/sparc: Record entire jump condition in DisasContext Richard Henderson
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 1233911b69..0bbe4cff3b 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -1015,12 +1015,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)
 {
@@ -2346,7 +2340,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 v2 17/21] target/sparc: Record entire jump condition in DisasContext
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (15 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 16/21] target/sparc: Merge gen_op_next_insn into only caller Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 18/21] target/sparc: Discard cpu_cond at the end of each insn Richard Henderson
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 0bbe4cff3b..5c9a3d45fa 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -146,6 +146,12 @@ static TCGv_i64 cpu_fpr[TARGET_DPREGS];
 # define env64_field_offsetof(X)  ({ qemu_build_not_reached(); 0; })
 #endif
 
+typedef struct DisasCompare {
+    TCGCond cond;
+    TCGv c1;
+    int c2;
+} DisasCompare;
+
 typedef struct DisasDelayException {
     struct DisasDelayException *next;
     TCGLabel *lab;
@@ -159,7 +165,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;
@@ -178,12 +188,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))
@@ -912,9 +916,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
@@ -2347,7 +2351,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);
@@ -2434,9 +2438,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 v2 18/21] target/sparc: Discard cpu_cond at the end of each insn
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (16 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 17/21] target/sparc: Record entire jump condition in DisasContext Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 19/21] target/sparc: Implement UDIVX and SDIVX inline Richard Henderson
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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 5c9a3d45fa..3564c6032e 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -171,6 +171,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
@@ -912,6 +913,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]);
@@ -958,6 +972,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;
@@ -999,6 +1014,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:
@@ -2339,6 +2356,8 @@ static bool advance_pc(DisasContext *dc)
 {
     TCGLabel *l1;
 
+    finishing_insn(dc);
+
     if (dc->npc & 3) {
         switch (dc->npc) {
         case DYNAMIC_PC:
@@ -2383,6 +2402,8 @@ static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
     target_ulong dest = address_mask_i(dc, dc->pc + disp * 4);
     target_ulong npc;
 
+    finishing_insn(dc);
+
     if (cmp->cond == TCG_COND_ALWAYS) {
         if (annul) {
             dc->pc = dest;
@@ -2449,6 +2470,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;
@@ -2585,6 +2607,8 @@ static bool do_tcc(DisasContext *dc, int cond, int cc,
         tcg_gen_addi_i32(trap, trap, TT_TRAP);
     }
 
+    finishing_insn(dc);
+
     /* Trap always.  */
     if (cond == 8) {
         save_state(dc);
@@ -3201,6 +3225,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);
 }
@@ -5080,6 +5105,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 v2 19/21] target/sparc: Implement UDIVX and SDIVX inline
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (17 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 18/21] target/sparc: Discard cpu_cond at the end of each insn Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 20/21] target/sparc: Implement UDIV inline Richard Henderson
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 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/insns.decode |   4 +-
 target/sparc/helper.c     |  24 ---------
 target/sparc/translate.c  | 109 +++++++++++++++++++++++++++++++++-----
 4 files changed, 97 insertions(+), 44 deletions(-)

diff --git a/target/sparc/helper.h b/target/sparc/helper.h
index decd94c0d6..55eff66283 100644
--- a/target/sparc/helper.h
+++ b/target/sparc/helper.h
@@ -31,10 +31,6 @@ DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_WG, i64, env, tl, tl)
 DEF_HELPER_FLAGS_3(sdiv, TCG_CALL_NO_WG, i64, 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/insns.decode b/target/sparc/insns.decode
index 0552f1447d..52f54b87cc 100644
--- a/target/sparc/insns.decode
+++ b/target/sparc/insns.decode
@@ -182,8 +182,8 @@ UMUL        10 ..... 0.1010 ..... . .............          @r_r_ri_cc
 SMUL        10 ..... 0.1011 ..... . .............          @r_r_ri_cc
 MULScc      10 ..... 100100 ..... . .............          @r_r_ri_cc1
 
-UDIVX       10 ..... 001101 ..... . .............          @r_r_ri_cc0
-SDIVX       10 ..... 101101 ..... . .............          @r_r_ri_cc0
+UDIVX       10 ..... 001101 ..... . .............          @r_r_ri
+SDIVX       10 ..... 101101 ..... . .............          @r_r_ri
 UDIV        10 ..... 0.1110 ..... . .............          @r_r_ri_cc
 SDIV        10 ..... 0.1111 ..... . .............          @r_r_ri_cc
 
diff --git a/target/sparc/helper.c b/target/sparc/helper.c
index 6117e99b55..bd10b60e4b 100644
--- a/target/sparc/helper.c
+++ b/target/sparc/helper.c
@@ -129,30 +129,6 @@ uint64_t helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
     return (uint32_t)r;
 }
 
-#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 3564c6032e..95cc4c71f4 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -51,12 +51,10 @@
 # define gen_helper_restored(E)                 qemu_build_not_reached()
 # define gen_helper_retry(E)                    qemu_build_not_reached()
 # define gen_helper_saved(E)                    qemu_build_not_reached()
-# define gen_helper_sdivx(D, E, A, B)           qemu_build_not_reached()
 # define gen_helper_set_softint(E, S)           qemu_build_not_reached()
 # define gen_helper_tick_get_count(D, E, T, C)  qemu_build_not_reached()
 # define gen_helper_tick_set_count(P, S)        qemu_build_not_reached()
 # define gen_helper_tick_set_limit(P, S)        qemu_build_not_reached()
-# define gen_helper_udivx(D, E, A, B)           qemu_build_not_reached()
 # define gen_helper_wrccr(E, S)                 qemu_build_not_reached()
 # define gen_helper_wrcwp(E, S)                 qemu_build_not_reached()
 # define gen_helper_wrgl(E, S)                  qemu_build_not_reached()
@@ -579,16 +577,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)
 {
 #ifdef TARGET_SPARC64
@@ -3580,8 +3568,6 @@ TRANS(UMUL, MUL, do_logic, a, gen_op_umul, NULL)
 TRANS(SMUL, MUL, do_logic, a, gen_op_smul, NULL)
 TRANS(MULScc, ALL, do_arith, a, NULL, NULL, gen_op_mulscc)
 
-TRANS(UDIVX, 64, do_arith, a, gen_op_udivx, NULL, NULL)
-TRANS(SDIVX, 64, do_arith, a, gen_op_sdivx, NULL, NULL)
 TRANS(UDIV, DIV, do_arith, a, gen_op_udiv, NULL, gen_op_udivcc)
 TRANS(SDIV, DIV, do_arith, a, gen_op_sdiv, NULL, gen_op_sdivcc)
 
@@ -3605,6 +3591,101 @@ static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a)
     return do_logic(dc, a, tcg_gen_or_tl, tcg_gen_ori_tl);
 }
 
+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, t1, t1, tcg_constant_tl(0),
+                           tcg_constant_tl(1), src2);
+        src2 = t1;
+    }
+
+    tcg_gen_div_tl(dst, src1, src2);
+    gen_store_gpr(dc, a->rd, dst);
+    return advance_pc(dc);
+}
+
 static bool gen_edge(DisasContext *dc, arg_r_r_r *a,
                      int width, bool cc, bool left)
 {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 20/21] target/sparc: Implement UDIV inline
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (18 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 19/21] target/sparc: Implement UDIVX and SDIVX inline Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-01  4:11 ` [PATCH v2 21/21] target/sparc: Check for invalid cond in gen_compare_reg Richard Henderson
  2023-11-05 13:22 ` [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Mark Cave-Ayland
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/sparc/insns.decode |  3 +-
 target/sparc/translate.c  | 67 +++++++++++++++++++++++++++++++--------
 2 files changed, 56 insertions(+), 14 deletions(-)

diff --git a/target/sparc/insns.decode b/target/sparc/insns.decode
index 52f54b87cc..2d26404cb2 100644
--- a/target/sparc/insns.decode
+++ b/target/sparc/insns.decode
@@ -184,7 +184,8 @@ MULScc      10 ..... 100100 ..... . .............          @r_r_ri_cc1
 
 UDIVX       10 ..... 001101 ..... . .............          @r_r_ri
 SDIVX       10 ..... 101101 ..... . .............          @r_r_ri
-UDIV        10 ..... 0.1110 ..... . .............          @r_r_ri_cc
+UDIV        10 ..... 001110 ..... . .............          @r_r_ri
+UDIVcc      10 ..... 011110 ..... . .............          @r_r_ri_cc1
 SDIV        10 ..... 0.1111 ..... . .............          @r_r_ri_cc
 
 TADDcc      10 ..... 100000 ..... . .............          @r_r_ri_cc1
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 95cc4c71f4..4b7d943bae 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -577,18 +577,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)
-{
-#ifdef TARGET_SPARC64
-    gen_helper_udiv(dst, tcg_env, src1, src2);
-    tcg_gen_ext32u_tl(dst, dst);
-#else
-    TCGv_i64 t64 = tcg_temp_new_i64();
-    gen_helper_udiv(t64, tcg_env, src1, src2);
-    tcg_gen_trunc_i64_tl(dst, t64);
-#endif
-}
-
 static void gen_op_sdiv(TCGv dst, TCGv src1, TCGv src2)
 {
 #ifdef TARGET_SPARC64
@@ -3568,7 +3556,7 @@ TRANS(UMUL, MUL, do_logic, a, gen_op_umul, NULL)
 TRANS(SMUL, MUL, do_logic, a, gen_op_smul, NULL)
 TRANS(MULScc, ALL, do_arith, a, NULL, NULL, gen_op_mulscc)
 
-TRANS(UDIV, DIV, do_arith, a, gen_op_udiv, NULL, gen_op_udivcc)
+TRANS(UDIVcc, DIV, do_arith, a, NULL, NULL, gen_op_udivcc)
 TRANS(SDIV, DIV, do_arith, a, gen_op_sdiv, NULL, gen_op_sdivcc)
 
 /* TODO: Should have feature bit -- comes in with UltraSparc T2. */
@@ -3591,6 +3579,59 @@ static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a)
     return do_logic(dc, a, tcg_gen_or_tl, tcg_gen_ori_tl);
 }
 
+static bool trans_UDIV(DisasContext *dc, arg_r_r_ri *a)
+{
+    TCGv_i64 t1, t2;
+    TCGv dst;
+
+    if (!avail_DIV(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) {
+        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();
+#ifdef TARGET_SPARC64
+        tcg_gen_ext32u_i64(t2, cpu_regs[a->rs2_or_imm]);
+#else
+        tcg_gen_extu_i32_i64(t2, cpu_regs[a->rs2_or_imm]);
+#endif
+    }
+
+    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

* [PATCH v2 21/21] target/sparc: Check for invalid cond in gen_compare_reg
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (19 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 20/21] target/sparc: Implement UDIV inline Richard Henderson
@ 2023-11-01  4:11 ` Richard Henderson
  2023-11-05 13:22 ` [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Mark Cave-Ayland
  21 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2023-11-01  4:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: mark.cave-ayland

Consolidate the test here; drop the "inverted logic".
Fix MOVr and FMOVR, which were missing the invalid test.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/sparc/translate.c | 45 +++++++++++++++++++++++-----------------
 1 file changed, 26 insertions(+), 19 deletions(-)

diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 4b7d943bae..6fc333a6b8 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -1189,24 +1189,29 @@ static void gen_fcompare(DisasCompare *cmp, unsigned int cc, unsigned int cond)
     }
 }
 
-// Inverted logic
-static const TCGCond gen_tcg_cond_reg[8] = {
-    TCG_COND_NEVER,  /* reserved */
-    TCG_COND_NE,
-    TCG_COND_GT,
-    TCG_COND_GE,
-    TCG_COND_NEVER,  /* reserved */
-    TCG_COND_EQ,
-    TCG_COND_LE,
-    TCG_COND_LT,
-};
-
-static void gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src)
+static bool gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src)
 {
-    cmp->cond = tcg_invert_cond(gen_tcg_cond_reg[cond]);
+    static const TCGCond cond_reg[4] = {
+        TCG_COND_NEVER,  /* reserved */
+        TCG_COND_EQ,
+        TCG_COND_LE,
+        TCG_COND_LT,
+    };
+    TCGCond tcond;
+
+    if ((cond & 3) == 0) {
+        return false;
+    }
+    tcond = cond_reg[cond & 3];
+    if (cond & 4) {
+        tcond = tcg_invert_cond(tcond);
+    }
+
+    cmp->cond = tcond;
     cmp->c1 = tcg_temp_new();
     cmp->c2 = 0;
     tcg_gen_mov_tl(cmp->c1, r_src);
+    return true;
 }
 
 static void gen_op_clear_ieee_excp_and_FTT(void)
@@ -2504,11 +2509,9 @@ static bool trans_BPr(DisasContext *dc, arg_BPr *a)
     if (!avail_64(dc)) {
         return false;
     }
-    if (gen_tcg_cond_reg[a->cond] == TCG_COND_NEVER) {
+    if (!gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1))) {
         return false;
     }
-
-    gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1));
     return advance_jump_cond(dc, &cmp, a->a, a->i);
 }
 
@@ -4020,7 +4023,9 @@ static bool trans_MOVR(DisasContext *dc, arg_MOVR *a)
     if (src2 == NULL) {
         return false;
     }
-    gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1));
+    if (!gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1))) {
+        return false;
+    }
     return do_mov_cond(dc, &cmp, a->rd, src2);
 }
 
@@ -5007,6 +5012,9 @@ static bool do_fmovr(DisasContext *dc, arg_FMOVRs *a, bool is_128,
 {
     DisasCompare cmp;
 
+    if (!gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1))) {
+        return false;
+    }
     if (gen_trap_ifnofpu(dc)) {
         return true;
     }
@@ -5015,7 +5023,6 @@ static bool do_fmovr(DisasContext *dc, arg_FMOVRs *a, bool is_128,
     }
 
     gen_op_clear_ieee_excp_and_FTT();
-    gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1));
     func(dc, &cmp, a->rd, a->rs2);
     return advance_pc(dc);
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 00/21] target/sparc: Cleanup condition codes etc
  2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
                   ` (20 preceding siblings ...)
  2023-11-01  4:11 ` [PATCH v2 21/21] target/sparc: Check for invalid cond in gen_compare_reg Richard Henderson
@ 2023-11-05 13:22 ` Mark Cave-Ayland
  21 siblings, 0 replies; 23+ messages in thread
From: Mark Cave-Ayland @ 2023-11-05 13:22 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel

On 01/11/2023 04:11, Richard Henderson wrote:
> 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 more often that we'd like.
> 
> Since almost all Sparc instructions that set cc also have a version of
> the instruction that does not set cc, we can trust that the compiler
> has only used the cc-setting version when it is actually required.
> Thus, unlike CISC processors, there is very little scope for optimization
> of the flags -- we might as well compute them immediately.
> 
> 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.  (For "normal" setting of Z, we could share, but it is
> possible to set xcc.Z and !icc.Z via explicit write to %ccr, and for
> that we have to have two variables.)
> 
> 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~

I've tested this series by running through my OpenBIOS boot tests for SPARC32 and 
SPARC64 and didn't spot any obvious regressions, so:

Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

> Richard Henderson (21):
>    target/sparc: Introduce cpu_put_psr_icc
>    target/sparc: Split psr and xcc into components
>    target/sparc: Remove CC_OP_LOGIC
>    target/sparc: Remove CC_OP_DIV
>    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: Pass displacement to advance_jump_cond
>    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
>    target/sparc: Check for invalid cond in gen_compare_reg
> 
>   linux-user/sparc/target_cpu.h |   17 +-
>   target/sparc/cpu.h            |   58 +-
>   target/sparc/helper.h         |   12 +-
>   target/sparc/insns.decode     |    7 +-
>   linux-user/sparc/cpu_loop.c   |   11 +-
>   linux-user/sparc/signal.c     |    2 +-
>   target/sparc/cc_helper.c      |  471 ------------
>   target/sparc/cpu.c            |    1 -
>   target/sparc/helper.c         |  171 ++---
>   target/sparc/int32_helper.c   |    5 -
>   target/sparc/int64_helper.c   |    5 -
>   target/sparc/machine.c        |   45 +-
>   target/sparc/translate.c      | 1333 ++++++++++++++-------------------
>   target/sparc/win_helper.c     |   56 +-
>   target/sparc/meson.build      |    1 -
>   15 files changed, 789 insertions(+), 1406 deletions(-)
>   delete mode 100644 target/sparc/cc_helper.c
> 


ATB,

Mark.



^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2023-11-05 13:24 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-11-01  4:11 [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Richard Henderson
2023-11-01  4:11 ` [PATCH v2 01/21] target/sparc: Introduce cpu_put_psr_icc Richard Henderson
2023-11-01  4:11 ` [PATCH v2 02/21] target/sparc: Split psr and xcc into components Richard Henderson
2023-11-01  4:11 ` [PATCH v2 03/21] target/sparc: Remove CC_OP_LOGIC Richard Henderson
2023-11-01  4:11 ` [PATCH v2 04/21] target/sparc: Remove CC_OP_DIV Richard Henderson
2023-11-01  4:11 ` [PATCH v2 05/21] target/sparc: Remove CC_OP_ADD, CC_OP_ADDX, CC_OP_TADD Richard Henderson
2023-11-01  4:11 ` [PATCH v2 06/21] target/sparc: Remove CC_OP_SUB, CC_OP_SUBX, CC_OP_TSUB Richard Henderson
2023-11-01  4:11 ` [PATCH v2 07/21] target/sparc: Remove CC_OP_TADDTV, CC_OP_TSUBTV Richard Henderson
2023-11-01  4:11 ` [PATCH v2 08/21] target/sparc: Remove CC_OP leftovers Richard Henderson
2023-11-01  4:11 ` [PATCH v2 09/21] target/sparc: Remove DisasCompare.is_bool Richard Henderson
2023-11-01  4:11 ` [PATCH v2 10/21] target/sparc: Change DisasCompare.c2 to int Richard Henderson
2023-11-01  4:11 ` [PATCH v2 11/21] target/sparc: Always copy conditions into a new temporary Richard Henderson
2023-11-01  4:11 ` [PATCH v2 12/21] target/sparc: Do flush_cond in advance_jump_cond Richard Henderson
2023-11-01  4:11 ` [PATCH v2 13/21] target/sparc: Merge gen_branch2 into advance_pc Richard Henderson
2023-11-01  4:11 ` [PATCH v2 14/21] target/sparc: Merge advance_jump_uncond_{never, always} into advance_jump_cond Richard Henderson
2023-11-01  4:11 ` [PATCH v2 15/21] target/sparc: Pass displacement to advance_jump_cond Richard Henderson
2023-11-01  4:11 ` [PATCH v2 16/21] target/sparc: Merge gen_op_next_insn into only caller Richard Henderson
2023-11-01  4:11 ` [PATCH v2 17/21] target/sparc: Record entire jump condition in DisasContext Richard Henderson
2023-11-01  4:11 ` [PATCH v2 18/21] target/sparc: Discard cpu_cond at the end of each insn Richard Henderson
2023-11-01  4:11 ` [PATCH v2 19/21] target/sparc: Implement UDIVX and SDIVX inline Richard Henderson
2023-11-01  4:11 ` [PATCH v2 20/21] target/sparc: Implement UDIV inline Richard Henderson
2023-11-01  4:11 ` [PATCH v2 21/21] target/sparc: Check for invalid cond in gen_compare_reg Richard Henderson
2023-11-05 13:22 ` [PATCH v2 00/21] target/sparc: Cleanup condition codes etc Mark Cave-Ayland

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).