qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/3] mips setcond and movcond
@ 2009-12-19 22:32 Richard Henderson
  2009-12-19 22:32 ` [Qemu-devel] [PATCH 1/3] tcg: Add tcg_swap_cond Richard Henderson
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Richard Henderson @ 2009-12-19 22:32 UTC (permalink / raw)
  To: qemu-devel

It has been compile tested, but nothing else.

I'm moderately surprised at the implementation of brcond.  It's
missing the BLTZ, BLEZ, BGTZ, BGEZ branches.  It's could be 
improved with the SLTI and SLTIU insns used here with setcond.

Indeed, I suspect that a good implementation of brcond would be
to take care of the cases implementable directly by branches,
and then call into setcond to take care of the rest.  I don't
plan to do that.


r~



Richard Henderson (3):
  tcg: Add tcg_swap_cond.
  tcg-mips: Implement setcond, setcond2.
  tcg-mips: Implement movcond.

 tcg/mips/tcg-target.c |  296 ++++++++++++++++++++++++++++++++++++++++++++++++-
 tcg/tcg.h             |    8 ++
 2 files changed, 302 insertions(+), 2 deletions(-)

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

* [Qemu-devel] [PATCH 1/3] tcg: Add tcg_swap_cond.
  2009-12-19 22:32 [Qemu-devel] [PATCH 0/3] mips setcond and movcond Richard Henderson
@ 2009-12-19 22:32 ` Richard Henderson
  2009-12-19 22:32 ` [Qemu-devel] [PATCH 2/3] tcg-mips: Implement setcond, setcond2 Richard Henderson
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Richard Henderson @ 2009-12-19 22:32 UTC (permalink / raw)
  To: qemu-devel

Returns the condition as if with swapped comparison operands.
---
 tcg/tcg.h |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/tcg/tcg.h b/tcg/tcg.h
index 376d6af..ac38390 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -205,11 +205,19 @@ typedef enum {
     TCG_COND_GTU,
 } TCGCond;
 
+/* Invert the sense of the comparison.  */
 static inline TCGCond tcg_invert_cond(TCGCond c)
 {
     return (TCGCond)(c ^ 1);
 }
 
+/* Swap the operands in a comparison.  */
+static inline TCGCond tcg_swap_cond(TCGCond c)
+{
+    int mask = (c < TCG_COND_LT ? 0 : c < TCG_COND_LTU ? 7 : 15);
+    return (TCGCond)(c ^ mask);
+}
+
 #define TEMP_VAL_DEAD  0
 #define TEMP_VAL_REG   1
 #define TEMP_VAL_MEM   2
-- 
1.6.5.2

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

* [Qemu-devel] [PATCH 2/3] tcg-mips: Implement setcond, setcond2.
  2009-12-19 22:32 [Qemu-devel] [PATCH 0/3] mips setcond and movcond Richard Henderson
  2009-12-19 22:32 ` [Qemu-devel] [PATCH 1/3] tcg: Add tcg_swap_cond Richard Henderson
@ 2009-12-19 22:32 ` Richard Henderson
  2009-12-20  0:00   ` Aurelien Jarno
  2009-12-19 22:32 ` [Qemu-devel] [PATCH 3/3] tcg-mips: Implement movcond Richard Henderson
  2009-12-19 23:03 ` [Qemu-devel] [PATCH 0/3] mips setcond and movcond Aurelien Jarno
  3 siblings, 1 reply; 6+ messages in thread
From: Richard Henderson @ 2009-12-19 22:32 UTC (permalink / raw)
  To: qemu-devel

---
 tcg/mips/tcg-target.c |  177 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 177 insertions(+), 0 deletions(-)

diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 8fcb5c9..2a2913d 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -274,6 +274,8 @@ enum {
     OPC_BEQ      = 0x04 << 26,
     OPC_BNE      = 0x05 << 26,
     OPC_ADDIU    = 0x09 << 26,
+    OPC_SLTI     = 0x0A << 26,
+    OPC_SLTIU    = 0x0B << 26,
     OPC_ANDI     = 0x0C << 26,
     OPC_ORI      = 0x0D << 26,
     OPC_XORI     = 0x0E << 26,
@@ -583,6 +585,170 @@ static void tcg_out_brcond2(TCGContext *s, int cond, int arg1,
     reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr);
 }
 
+static void tcg_out_setcond(TCGContext *s, int cond, TCGArg arg0,
+                            TCGArg arg1, TCGArg arg2, int const_arg2)
+{
+    int do_swap = 0, do_inv = 0;
+
+    switch (cond) {
+    case TCG_COND_EQ:
+    case TCG_COND_NE:
+        /* Both of these forms require comparisons against zero.  */
+        if (arg2 != 0) {
+            if (const_arg2)
+                tcg_out_opc_imm(s, OPC_XORI, arg0, arg1, arg2);
+            else
+                tcg_out_opc_reg(s, OPC_XOR, arg0, arg1, arg2);
+            arg1 = arg0;
+        }
+        break;
+
+    case TCG_COND_GT:
+    case TCG_COND_GTU:
+        /* A > B  --> B < A */
+        do_swap = 1;
+        break;
+
+    case TCG_COND_GE:
+    case TCG_COND_GEU:
+        /* A >= B  --> !(A < B) */
+        cond = tcg_invert_cond(cond);
+        do_inv = 1;
+        break;
+
+    case TCG_COND_LE:
+    case TCG_COND_LEU:
+        if (const_arg2 && arg2 < 32767) {
+            /* A <= B  --> A < B+1, given that B+1 doesn't overflow.  */
+            arg2++;
+            cond = (cond == TCG_COND_LE ? TCG_COND_LT : TCG_COND_LTU);
+        } else {
+            /* A <= B  --> B >= A  --> !(B < A) */
+            do_swap = do_inv = 1;
+        }
+        break;
+    }
+
+    if (do_swap) {
+        TCGArg t;
+
+        /* Since we allow constants in arg2, we must load (non-zero)
+           constants into AT.  */
+        if (const_arg2 && arg2 != 0) {
+            tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, arg2);
+            arg2 = TCG_REG_AT;
+        }
+        t = arg1, arg1 = arg2, arg2 = arg1;
+        const_arg2 = 0;
+        cond = tcg_swap_cond(cond);
+    }
+
+    switch (cond) {
+    case TCG_COND_EQ:
+        /* X == 0 --> (unsigned)X < 1.  */
+        tcg_out_opc_imm(s, OPC_SLTIU, arg0, arg1, 1);
+        break;
+
+    case TCG_COND_NE:
+        /* X != 0 --> 0 < (unsigned)X.  */
+        tcg_out_opc_reg(s, OPC_SLTU, arg0, TCG_REG_ZERO, arg1);
+        break;
+
+    case TCG_COND_LT:
+        if (const_arg2)
+            tcg_out_opc_imm(s, OPC_SLTI, arg0, arg1, arg2);
+        else
+            tcg_out_opc_imm(s, OPC_SLT, arg0, arg1, arg2);
+        break;
+
+    case TCG_COND_LTU:
+        if (const_arg2)
+            tcg_out_opc_imm(s, OPC_SLTIU, arg0, arg1, arg2);
+        else
+            tcg_out_opc_imm(s, OPC_SLTU, arg0, arg1, arg2);
+        break;
+
+    default:
+        tcg_abort ();
+    }
+
+    if (do_inv) {
+        tcg_out_opc_imm(s, OPC_XORI, arg0, arg0, 1);
+    }
+}
+
+static void tcg_out_setcond2(TCGContext *s, int cond, int dest,
+                             int al, int ah, int bl, int bh,
+                             int blconst, int bhconst)
+{
+    int cl, ch;
+
+    /* If we were to implement this function with brcond2 and two sets,
+       we'd use 6-8 insns, including nops in the delay slots.  Here we
+       generate (excluding possible constant loads, which brcond does
+       not support) a minimum of 3 insns and a maximum of 5 insns.  */
+
+    switch (cond) {
+    case TCG_COND_NE:
+        /* (ah != bh || al != bl) */
+        tcg_out_setcond(s, TCG_COND_NE, TCG_REG_T0, al, bl, blconst);
+        tcg_out_setcond(s, TCG_COND_NE, dest, ah, bh, bhconst);
+        tcg_out_opc_reg(s, OPC_OR, dest, dest, TCG_REG_T0);
+        return;
+
+    case TCG_COND_EQ:
+        /* (ah == bh && al == bl) */
+        ch = -1;
+        cl = TCG_COND_EQ;
+        break;
+
+    case TCG_COND_LT:
+        /* (ah < bh || (ah == bh && al < bl)) */
+        ch = TCG_COND_LT;
+        cl = TCG_COND_LTU;
+        break;
+    case TCG_COND_LTU:
+        ch = (bh == 0 ? -1 : TCG_COND_LTU);
+        cl = TCG_COND_LTU;
+        break;
+
+    case TCG_COND_LE:
+        /* (ah < bh || (ah == bh && al <= bl) */
+        ch = TCG_COND_LT, cl = TCG_COND_LEU;
+        break;
+    case TCG_COND_LEU:
+        ch = (bh == 0 ? -1 : TCG_COND_LTU);
+        cl = TCG_COND_LEU;
+        break;
+
+    case TCG_COND_GT:
+    case TCG_COND_GTU:
+        /* (ah > bh || (ah == bh && al > bl)) */
+        ch = cond, cl = TCG_COND_GTU;
+        break;
+
+    case TCG_COND_GE:
+        /* (ah > bh || (ah == bh && al >= bl)) */
+        ch = TCG_COND_GT, cl = TCG_COND_GEU;
+        break;
+    case TCG_COND_GEU:
+        ch = TCG_COND_GTU, cl = TCG_COND_GEU;
+        break;
+
+    default:
+        tcg_abort ();
+    }
+
+    tcg_out_setcond(s, cl, TCG_REG_AT, al, bl, blconst);
+    tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_T0, ah, bh, bhconst);
+    tcg_out_opc_reg(s, OPC_AND, (ch == -1 ? dest : TCG_REG_T0),
+                    TCG_REG_T0, TCG_REG_AT);
+    if (ch != -1) {
+        tcg_out_setcond(s, ch, dest, ah, bh, bhconst);
+        tcg_out_opc_reg(s, OPC_OR, dest, dest, TCG_REG_T0);
+    }
+}
+
 #if defined(CONFIG_SOFTMMU)
 
 #include "../../softmmu_defs.h"
@@ -1155,6 +1321,14 @@ static inline void tcg_out_op(TCGContext *s, int opc,
         tcg_out_brcond2(s, args[4], args[0], args[1], args[2], args[3], args[5]);
         break;
 
+    case INDEX_op_setcond_i32:
+        tcg_out_setcond(s, args[3], args[0], args[1], args[2], const_args[2]);
+        break;
+    case INDEX_op_setcond2_i32:
+        tcg_out_setcond2(s, args[5], args[0], args[1], args[2],
+                         args[3], args[4], const_args[3], const_args[4]);
+        break;
+
     case INDEX_op_qemu_ld8u:
         tcg_out_qemu_ld(s, args, 0);
         break;
@@ -1233,6 +1407,9 @@ static const TCGTargetOpDef mips_op_defs[] = {
     { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } },
     { INDEX_op_brcond2_i32, { "rZ", "rZ", "rZ", "rZ" } },
 
+    { INDEX_op_setcond_i32, { "r", "r", "rJ" } },
+    { INDEX_op_setcond2_i32, { "r", "r", "r", "rJ", "rJ" } },
+
 #if TARGET_LONG_BITS == 32
     { INDEX_op_qemu_ld8u, { "L", "lZ" } },
     { INDEX_op_qemu_ld8s, { "L", "lZ" } },
-- 
1.6.5.2

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

* [Qemu-devel] [PATCH 3/3] tcg-mips: Implement movcond.
  2009-12-19 22:32 [Qemu-devel] [PATCH 0/3] mips setcond and movcond Richard Henderson
  2009-12-19 22:32 ` [Qemu-devel] [PATCH 1/3] tcg: Add tcg_swap_cond Richard Henderson
  2009-12-19 22:32 ` [Qemu-devel] [PATCH 2/3] tcg-mips: Implement setcond, setcond2 Richard Henderson
@ 2009-12-19 22:32 ` Richard Henderson
  2009-12-19 23:03 ` [Qemu-devel] [PATCH 0/3] mips setcond and movcond Aurelien Jarno
  3 siblings, 0 replies; 6+ messages in thread
From: Richard Henderson @ 2009-12-19 22:32 UTC (permalink / raw)
  To: qemu-devel

---
 tcg/mips/tcg-target.c |  119 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 117 insertions(+), 2 deletions(-)

diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 2a2913d..123a7af 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -297,6 +297,8 @@ enum {
     OPC_SRAV     = OPC_SPECIAL | 0x07,
     OPC_JR       = OPC_SPECIAL | 0x08,
     OPC_JALR     = OPC_SPECIAL | 0x09,
+    OPC_MOVZ     = OPC_SPECIAL | 0x0A,
+    OPC_MOVN     = OPC_SPECIAL | 0x0B,
     OPC_MFHI     = OPC_SPECIAL | 0x10,
     OPC_MFLO     = OPC_SPECIAL | 0x12,
     OPC_MULT     = OPC_SPECIAL | 0x18,
@@ -464,8 +466,8 @@ static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
     }
 }
 
-static void tcg_out_brcond(TCGContext *s, int cond, int arg1,
-                           int arg2, int label_index)
+static void tcg_out_brcond_nodelay(TCGContext *s, int cond, int arg1,
+                                   int arg2, int label_index)
 {
     TCGLabel *l = &s->labels[label_index];
 
@@ -517,6 +519,12 @@ static void tcg_out_brcond(TCGContext *s, int cond, int arg1,
     } else {
         tcg_out_reloc(s, s->code_ptr - 4, R_MIPS_PC16, label_index, 0);
     }
+}
+
+static void tcg_out_brcond(TCGContext *s, int cond, int arg1,
+                           int arg2, int label_index)
+{
+    tcg_out_brcond_nodelay(s, cond, arg1, arg2, label_index);
     tcg_out_nop(s);
 }
 
@@ -749,6 +757,108 @@ static void tcg_out_setcond2(TCGContext *s, int cond, int dest,
     }
 }
 
+static inline int have_movz(void)
+{
+    /* ??? It's unclear what we want to do with different mips isa's.
+       We appear to already be assuming HILO interlocks on the MUL/DIV
+       instructions, which (according to gcc) implies MIPS{32,64} plus
+       the r5500.  All of these also have MUL3, which would elide the
+       use of the LO register for simple multiply.  MIPS{4,32,64} have
+       the conditional moves, but the r5500 doesn't.  */
+#if defined(__mips) && __mips >= 32
+    /* Use MOVZ on MIPS{32,64}.  */
+    return 1;
+#else
+    /* Mips has no architected cpuid.  We could probably look at
+       /proc/cpuinfo or similar to figure out what's running.  */
+    return 0;
+#endif
+}
+
+static void tcg_out_movcond(TCGContext *s, int cond, int dest,
+                            int c1, int c2, int c2const, int vt, int vf)
+{
+    int condr;
+
+    if (vt == vf) {
+        tcg_out_mov(s, dest, vt);
+        return;
+    }
+
+    if (dest == vt) {
+        vt = vf, vf = dest;
+        cond = tcg_invert_cond(cond);
+    }
+
+    condr = TCG_COND_NE;
+    switch (cond) {
+    case TCG_COND_EQ:
+        condr = TCG_COND_EQ;
+        /* FALLTHRU */
+    case TCG_COND_NE:
+        if (c2 != 0) {
+            if (c2const)
+                tcg_out_opc_imm(s, OPC_XORI, TCG_REG_T0, c1, c2);
+            else
+                tcg_out_opc_reg(s, OPC_XOR, TCG_REG_T0, c1, c2);
+            c1 = TCG_REG_T0;
+        }
+        break;
+
+    case TCG_COND_LE:
+    case TCG_COND_LEU:
+        if (c2const && c2 < 32767) {
+            c2++;
+            cond = (cond == TCG_COND_LE ? TCG_COND_LT : TCG_COND_LTU);
+            goto do_setcond;
+        }
+        /* FALLTHRU */
+
+    case TCG_COND_GE:
+    case TCG_COND_GEU:
+        cond = tcg_invert_cond(cond);
+        condr = TCG_COND_EQ;
+        /* FALLTHRU */
+
+    case TCG_COND_LT:
+    case TCG_COND_LTU:
+    case TCG_COND_GT:
+    case TCG_COND_GTU:
+    do_setcond:
+        tcg_out_setcond(s, cond, TCG_REG_T0, c1, c2, c2const);
+        c1 = TCG_REG_T0;
+        break;
+
+    default:
+        tcg_abort();
+    }
+
+    if (have_movz()) {
+        if (dest != vf) {
+            if (dest == c1) {
+                tcg_out_mov(s, TCG_REG_AT, c1);
+                c1 = TCG_REG_AT;
+            }
+            tcg_out_mov(s, dest, vf);
+        }
+        tcg_out_opc_reg(s, (condr == TCG_COND_NE ? OPC_MOVN : OPC_MOVZ),
+                        dest, vt, c1);
+    } else {
+        int label_over = gen_new_label();
+
+        tcg_out_brcond_nodelay(s, tcg_invert_cond(condr),
+                               c1, TCG_REG_ZERO, label_over);
+        if (dest != vf) {
+            tcg_out_mov(s, dest, vf);
+        } else {
+            tcg_out_nop(s);
+        }
+
+        tcg_out_mov(s, dest, vt);
+        tcg_out_label(s, label_over, (tcg_target_long)s->code_ptr);
+    }
+}
+
 #if defined(CONFIG_SOFTMMU)
 
 #include "../../softmmu_defs.h"
@@ -1328,6 +1438,10 @@ static inline void tcg_out_op(TCGContext *s, int opc,
         tcg_out_setcond2(s, args[5], args[0], args[1], args[2],
                          args[3], args[4], const_args[3], const_args[4]);
         break;
+    case INDEX_OP_movcond_i32:
+        tcg_out_movcond(s, args[5], args[0], args[1], args[2], const_args[2],
+                        args[3], args[4]);
+        break;
 
     case INDEX_op_qemu_ld8u:
         tcg_out_qemu_ld(s, args, 0);
@@ -1409,6 +1523,7 @@ static const TCGTargetOpDef mips_op_defs[] = {
 
     { INDEX_op_setcond_i32, { "r", "r", "rJ" } },
     { INDEX_op_setcond2_i32, { "r", "r", "r", "rJ", "rJ" } },
+    { INDEX_op_movcond_i32, { "r", "r", "rJ", "rZ", "rZ" } },
 
 #if TARGET_LONG_BITS == 32
     { INDEX_op_qemu_ld8u, { "L", "lZ" } },
-- 
1.6.5.2

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

* Re: [Qemu-devel] [PATCH 0/3] mips setcond and movcond
  2009-12-19 22:32 [Qemu-devel] [PATCH 0/3] mips setcond and movcond Richard Henderson
                   ` (2 preceding siblings ...)
  2009-12-19 22:32 ` [Qemu-devel] [PATCH 3/3] tcg-mips: Implement movcond Richard Henderson
@ 2009-12-19 23:03 ` Aurelien Jarno
  3 siblings, 0 replies; 6+ messages in thread
From: Aurelien Jarno @ 2009-12-19 23:03 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Sat, Dec 19, 2009 at 10:43:31PM +0000, Richard Henderson wrote:
> It has been compile tested, but nothing else.
> 
> I'm moderately surprised at the implementation of brcond.  It's
> missing the BLTZ, BLEZ, BGTZ, BGEZ branches.  It's could be 
> improved with the SLTI and SLTIU insns used here with setcond.

The MIPS TCG support is really new, and the goal was to make it working,
not to get it as optimized as possible. Anyway I doubt it will make a
big difference in speed.

> Indeed, I suspect that a good implementation of brcond would be
> to take care of the cases implementable directly by branches,
> and then call into setcond to take care of the rest.  I don't
> plan to do that.
> 
> 
> r~
> 
> 
> 
> Richard Henderson (3):
>   tcg: Add tcg_swap_cond.
>   tcg-mips: Implement setcond, setcond2.
>   tcg-mips: Implement movcond.
> 
>  tcg/mips/tcg-target.c |  296 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  tcg/tcg.h             |    8 ++
>  2 files changed, 302 insertions(+), 2 deletions(-)
> 
> 
> 
> 

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH 2/3] tcg-mips: Implement setcond, setcond2.
  2009-12-19 22:32 ` [Qemu-devel] [PATCH 2/3] tcg-mips: Implement setcond, setcond2 Richard Henderson
@ 2009-12-20  0:00   ` Aurelien Jarno
  0 siblings, 0 replies; 6+ messages in thread
From: Aurelien Jarno @ 2009-12-20  0:00 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Sat, Dec 19, 2009 at 10:38:01PM +0000, Richard Henderson wrote:
> ---
>  tcg/mips/tcg-target.c |  177 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 177 insertions(+), 0 deletions(-)

While this code is surely highly optimized, it is not easily readable. I
think dropping support for constant argument as it is currently done in
brcond/brcond2 would help to make it more readable.

I'll work on that in the next days.

> diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
> index 8fcb5c9..2a2913d 100644
> --- a/tcg/mips/tcg-target.c
> +++ b/tcg/mips/tcg-target.c
> @@ -274,6 +274,8 @@ enum {
>      OPC_BEQ      = 0x04 << 26,
>      OPC_BNE      = 0x05 << 26,
>      OPC_ADDIU    = 0x09 << 26,
> +    OPC_SLTI     = 0x0A << 26,
> +    OPC_SLTIU    = 0x0B << 26,
>      OPC_ANDI     = 0x0C << 26,
>      OPC_ORI      = 0x0D << 26,
>      OPC_XORI     = 0x0E << 26,
> @@ -583,6 +585,170 @@ static void tcg_out_brcond2(TCGContext *s, int cond, int arg1,
>      reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr);
>  }
>  
> +static void tcg_out_setcond(TCGContext *s, int cond, TCGArg arg0,
> +                            TCGArg arg1, TCGArg arg2, int const_arg2)
> +{
> +    int do_swap = 0, do_inv = 0;
> +
> +    switch (cond) {
> +    case TCG_COND_EQ:
> +    case TCG_COND_NE:
> +        /* Both of these forms require comparisons against zero.  */
> +        if (arg2 != 0) {
> +            if (const_arg2)
> +                tcg_out_opc_imm(s, OPC_XORI, arg0, arg1, arg2);
> +            else
> +                tcg_out_opc_reg(s, OPC_XOR, arg0, arg1, arg2);
> +            arg1 = arg0;
> +        }
> +        break;
> +
> +    case TCG_COND_GT:
> +    case TCG_COND_GTU:
> +        /* A > B  --> B < A */
> +        do_swap = 1;
> +        break;
> +
> +    case TCG_COND_GE:
> +    case TCG_COND_GEU:
> +        /* A >= B  --> !(A < B) */
> +        cond = tcg_invert_cond(cond);
> +        do_inv = 1;
> +        break;
> +
> +    case TCG_COND_LE:
> +    case TCG_COND_LEU:
> +        if (const_arg2 && arg2 < 32767) {
> +            /* A <= B  --> A < B+1, given that B+1 doesn't overflow.  */
> +            arg2++;
> +            cond = (cond == TCG_COND_LE ? TCG_COND_LT : TCG_COND_LTU);
> +        } else {
> +            /* A <= B  --> B >= A  --> !(B < A) */
> +            do_swap = do_inv = 1;
> +        }
> +        break;
> +    }
> +
> +    if (do_swap) {
> +        TCGArg t;
> +
> +        /* Since we allow constants in arg2, we must load (non-zero)
> +           constants into AT.  */
> +        if (const_arg2 && arg2 != 0) {
> +            tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, arg2);
> +            arg2 = TCG_REG_AT;
> +        }
> +        t = arg1, arg1 = arg2, arg2 = arg1;
> +        const_arg2 = 0;
> +        cond = tcg_swap_cond(cond);
> +    }
> +
> +    switch (cond) {
> +    case TCG_COND_EQ:
> +        /* X == 0 --> (unsigned)X < 1.  */
> +        tcg_out_opc_imm(s, OPC_SLTIU, arg0, arg1, 1);
> +        break;
> +
> +    case TCG_COND_NE:
> +        /* X != 0 --> 0 < (unsigned)X.  */
> +        tcg_out_opc_reg(s, OPC_SLTU, arg0, TCG_REG_ZERO, arg1);
> +        break;
> +
> +    case TCG_COND_LT:
> +        if (const_arg2)
> +            tcg_out_opc_imm(s, OPC_SLTI, arg0, arg1, arg2);
> +        else
> +            tcg_out_opc_imm(s, OPC_SLT, arg0, arg1, arg2);
> +        break;
> +
> +    case TCG_COND_LTU:
> +        if (const_arg2)
> +            tcg_out_opc_imm(s, OPC_SLTIU, arg0, arg1, arg2);
> +        else
> +            tcg_out_opc_imm(s, OPC_SLTU, arg0, arg1, arg2);
> +        break;
> +
> +    default:
> +        tcg_abort ();
> +    }
> +
> +    if (do_inv) {
> +        tcg_out_opc_imm(s, OPC_XORI, arg0, arg0, 1);
> +    }
> +}
> +
> +static void tcg_out_setcond2(TCGContext *s, int cond, int dest,
> +                             int al, int ah, int bl, int bh,
> +                             int blconst, int bhconst)
> +{
> +    int cl, ch;
> +
> +    /* If we were to implement this function with brcond2 and two sets,
> +       we'd use 6-8 insns, including nops in the delay slots.  Here we
> +       generate (excluding possible constant loads, which brcond does
> +       not support) a minimum of 3 insns and a maximum of 5 insns.  */
> +
> +    switch (cond) {
> +    case TCG_COND_NE:
> +        /* (ah != bh || al != bl) */
> +        tcg_out_setcond(s, TCG_COND_NE, TCG_REG_T0, al, bl, blconst);
> +        tcg_out_setcond(s, TCG_COND_NE, dest, ah, bh, bhconst);
> +        tcg_out_opc_reg(s, OPC_OR, dest, dest, TCG_REG_T0);
> +        return;
> +
> +    case TCG_COND_EQ:
> +        /* (ah == bh && al == bl) */
> +        ch = -1;
> +        cl = TCG_COND_EQ;
> +        break;
> +
> +    case TCG_COND_LT:
> +        /* (ah < bh || (ah == bh && al < bl)) */
> +        ch = TCG_COND_LT;
> +        cl = TCG_COND_LTU;
> +        break;
> +    case TCG_COND_LTU:
> +        ch = (bh == 0 ? -1 : TCG_COND_LTU);
> +        cl = TCG_COND_LTU;
> +        break;
> +
> +    case TCG_COND_LE:
> +        /* (ah < bh || (ah == bh && al <= bl) */
> +        ch = TCG_COND_LT, cl = TCG_COND_LEU;
> +        break;
> +    case TCG_COND_LEU:
> +        ch = (bh == 0 ? -1 : TCG_COND_LTU);
> +        cl = TCG_COND_LEU;
> +        break;
> +
> +    case TCG_COND_GT:
> +    case TCG_COND_GTU:
> +        /* (ah > bh || (ah == bh && al > bl)) */
> +        ch = cond, cl = TCG_COND_GTU;
> +        break;
> +
> +    case TCG_COND_GE:
> +        /* (ah > bh || (ah == bh && al >= bl)) */
> +        ch = TCG_COND_GT, cl = TCG_COND_GEU;
> +        break;
> +    case TCG_COND_GEU:
> +        ch = TCG_COND_GTU, cl = TCG_COND_GEU;
> +        break;
> +
> +    default:
> +        tcg_abort ();
> +    }
> +
> +    tcg_out_setcond(s, cl, TCG_REG_AT, al, bl, blconst);
> +    tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_T0, ah, bh, bhconst);
> +    tcg_out_opc_reg(s, OPC_AND, (ch == -1 ? dest : TCG_REG_T0),
> +                    TCG_REG_T0, TCG_REG_AT);
> +    if (ch != -1) {
> +        tcg_out_setcond(s, ch, dest, ah, bh, bhconst);
> +        tcg_out_opc_reg(s, OPC_OR, dest, dest, TCG_REG_T0);
> +    }
> +}
> +
>  #if defined(CONFIG_SOFTMMU)
>  
>  #include "../../softmmu_defs.h"
> @@ -1155,6 +1321,14 @@ static inline void tcg_out_op(TCGContext *s, int opc,
>          tcg_out_brcond2(s, args[4], args[0], args[1], args[2], args[3], args[5]);
>          break;
>  
> +    case INDEX_op_setcond_i32:
> +        tcg_out_setcond(s, args[3], args[0], args[1], args[2], const_args[2]);
> +        break;
> +    case INDEX_op_setcond2_i32:
> +        tcg_out_setcond2(s, args[5], args[0], args[1], args[2],
> +                         args[3], args[4], const_args[3], const_args[4]);
> +        break;
> +
>      case INDEX_op_qemu_ld8u:
>          tcg_out_qemu_ld(s, args, 0);
>          break;
> @@ -1233,6 +1407,9 @@ static const TCGTargetOpDef mips_op_defs[] = {
>      { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } },
>      { INDEX_op_brcond2_i32, { "rZ", "rZ", "rZ", "rZ" } },
>  
> +    { INDEX_op_setcond_i32, { "r", "r", "rJ" } },
> +    { INDEX_op_setcond2_i32, { "r", "r", "r", "rJ", "rJ" } },
> +
>  #if TARGET_LONG_BITS == 32
>      { INDEX_op_qemu_ld8u, { "L", "lZ" } },
>      { INDEX_op_qemu_ld8s, { "L", "lZ" } },
> -- 
> 1.6.5.2
> 
> 
> 
> 

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

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

end of thread, other threads:[~2009-12-20  0:00 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-12-19 22:32 [Qemu-devel] [PATCH 0/3] mips setcond and movcond Richard Henderson
2009-12-19 22:32 ` [Qemu-devel] [PATCH 1/3] tcg: Add tcg_swap_cond Richard Henderson
2009-12-19 22:32 ` [Qemu-devel] [PATCH 2/3] tcg-mips: Implement setcond, setcond2 Richard Henderson
2009-12-20  0:00   ` Aurelien Jarno
2009-12-19 22:32 ` [Qemu-devel] [PATCH 3/3] tcg-mips: Implement movcond Richard Henderson
2009-12-19 23:03 ` [Qemu-devel] [PATCH 0/3] mips setcond and movcond Aurelien Jarno

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