Skip to contentSkip to conversation

tcg conditional set, round 5

PATCH In review Richard Henderson 2 participants 9 messages Jan 7, 2010 – Feb 6, 2010

lore
Share & tools
lore
#0 lore raw

cover tcg conditional set, round 5

Changes since round 4:

* Document double-word support opcodes in a new section of the README, as requested by Aurelien.

* Shorten the branch-to-next in the EQ case of i386 brcond2, as pointed out by Laurent.

r~

Richard Henderson (6):
tcg: Document double-word support opcodes.
tcg: Generic support for conditional set
tcg: Add tcg_invert_cond.
tcg-i386: Implement small forward branches.
tcg-i386: Implement setcond.
tcg-x86_64: Implement setcond.

 elf.h                   |    2 +
 tcg/README              |   36 +++++++++
 tcg/i386/tcg-target.c   |  187 +++++++++++++++++++++++++++++++++++++----------
 tcg/tcg-op.h            |   47 ++++++++++++
 tcg/tcg-opc.h           |    3 +
 tcg/tcg.c               |   21 ++++--
 tcg/tcg.h               |    5 +
 tcg/x86_64/tcg-target.c |   38 ++++++++-
 8 files changed, 288 insertions(+), 51 deletions(-)
#1 lore raw

PATCH 1/6 tcg: Document double-word support opcodes.

The internal opcodes brcond2, add2, sub2, mulu2 were undocumented. Place these in a new section that clearly indicates that they are not to be emitted by translators.

---
 tcg/README |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)
tcg/README +23 -0
index e672258..3d6c170 100644
@@ -323,6 +323,29 @@ st32_i64 t0, t1, offset
 write(t0, t1 + offset)
 Write 8, 16, 32 or 64 bits to host memory.
 
+********* 64-bit target on 32-bit host support
+
+The following opcodes are internal to TCG.  Thus they are to be implemented by
+32-bit host code generators, but are not to be emitted by guest translators.
+They are emitted as needed by inline functions within "tcg-op.h".
+
+* brcond2_i32 cond, t0_low, t0_high, t1_low, t1_high, label
+
+Similar to brcond, except that the 64-bit values T0 and T1
+are formed from two 32-bit arguments.
+
+* add2_i32 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high
+* sub2_i32 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high
+
+Similar to add/sub, except that the 64-bit inputs T1 and T2 are
+formed from two 32-bit arguments, and the 64-bit output T0
+is returned in two 32-bit outputs.
+
+* mulu2_i32 t0_low, t0_high, t1, t2
+
+Similar to mul, except two 32-bit (unsigned) inputs T1 and T2 yielding
+the full 64-bit product T0.  The later is returned in two 32-bit outputs.
+
 ********* QEMU specific operations
 
 * tb_exit t0
Signature · 1 line
1.6.5.2
#2 lore raw

PATCH 2/6 tcg: Generic support for conditional set

In reply to Richard Henderson

Defines setcond_{i32,i64} and setcond2_i32 for 64-on-32-bit.

---
 tcg/README    |   13 +++++++++++++
 tcg/tcg-op.h  |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 tcg/tcg-opc.h |    3 +++
 tcg/tcg.c     |   21 +++++++++++++++------
 4 files changed, 78 insertions(+), 6 deletions(-)
tcg/README +13 -0
index 3d6c170..f0e21a1 100644
@@ -282,6 +282,14 @@ order bytes must be set to zero.
 Indicate that the value of t0 won't be used later. It is useful to
 force dead code elimination.
 
+********* Conditional moves
+
+* setcond_i32/i64 cond, dest, t1, t2
+
+dest = (t1 cond t2)
+
+Set DEST to 1 if (T1 cond T2) is true, otherwise set to 0.
+
 ********* Type conversions
 
 * ext_i32_i64 t0, t1
@@ -346,6 +354,11 @@ is returned in two 32-bit outputs.
 Similar to mul, except two 32-bit (unsigned) inputs T1 and T2 yielding
 the full 64-bit product T0.  The later is returned in two 32-bit outputs.
 
+* setcond2_i32 cond, dest, t1_low, t1_high, t2_low, t2_high
+
+Similar to setcond, except that the 64-bit values T1 and T2 are
+formed from two 32-bit arguments.  The result is a 32-bit value.
+
 ********* QEMU specific operations
 
 * tb_exit t0
tcg/tcg-op.h +47 -0

71 lines not on this page · raw message

tcg/tcg-opc.h +3 -0
index b7f3fd7..89db3b4 100644
@@ -42,6 +42,7 @@ DEF2(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
 
 DEF2(mov_i32, 1, 1, 0, 0)
 DEF2(movi_i32, 1, 0, 1, 0)
+DEF2(setcond_i32, 1, 2, 1, 0)
 /* load/store */
 DEF2(ld8u_i32, 1, 1, 1, 0)
 DEF2(ld8s_i32, 1, 1, 1, 0)
@@ -82,6 +83,7 @@ DEF2(add2_i32, 2, 4, 0, 0)
 DEF2(sub2_i32, 2, 4, 0, 0)
 DEF2(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
 DEF2(mulu2_i32, 2, 2, 0, 0)
+DEF2(setcond2_i32, 1, 4, 1, 0)
 #endif
 #ifdef TCG_TARGET_HAS_ext8s_i32
 DEF2(ext8s_i32, 1, 1, 0, 0)
@@ -111,6 +113,7 @@ DEF2(neg_i32, 1, 1, 0, 0)
 #if TCG_TARGET_REG_BITS == 64
 DEF2(mov_i64, 1, 1, 0, 0)
 DEF2(movi_i64, 1, 0, 1, 0)
+DEF2(setcond_i64, 1, 2, 1, 0)
 /* load/store */
 DEF2(ld8u_i64, 1, 1, 1, 0)
 DEF2(ld8s_i64, 1, 1, 1, 0)
tcg/tcg.c +15 -6
index 3c0e296..9949814 100644
@@ -670,6 +670,7 @@ void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
 }
 #endif
 
+
 static void tcg_reg_alloc_start(TCGContext *s)
 {
     int i;
@@ -888,21 +889,29 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile)
                 fprintf(outfile, "%s",
                         tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
             }
-            if (c == INDEX_op_brcond_i32
+            switch (c) {
+            case INDEX_op_brcond_i32:
+#if TCG_TARGET_REG_BITS == 32
+            case INDEX_op_brcond2_i32:
+#elif TCG_TARGET_REG_BITS == 64
+            case INDEX_op_brcond_i64:
+#endif
+            case INDEX_op_setcond_i32:
 #if TCG_TARGET_REG_BITS == 32
-                || c == INDEX_op_brcond2_i32
+            case INDEX_op_setcond2_i32:
 #elif TCG_TARGET_REG_BITS == 64
-                || c == INDEX_op_brcond_i64
+            case INDEX_op_setcond_i64:
 #endif
-                ) {
                 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
                     fprintf(outfile, ",%s", cond_name[args[k++]]);
                 else
                     fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
                 i = 1;
-            }
-            else
+                break;
+            default:
                 i = 0;
+                break;
+            }
             for(; i < nb_cargs; i++) {
                 if (k != 0)
                     fprintf(outfile, ",");
Signature · 1 line
1.6.5.2
#3 lore raw

PATCH 3/6 tcg: Add tcg_invert_cond.

In reply to Richard Henderson

It is very handy to have a reliable mapping of a condition to its inverse.

---
 tcg/tcg.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
tcg/tcg.h +5 -0
index 121b17c..b218abe 100644
@@ -205,6 +205,11 @@ typedef enum {
     TCG_COND_GTU,
 } TCGCond;
 
+static inline TCGCond tcg_invert_cond(TCGCond c)
+{
+    return (TCGCond)(c ^ 1);
+}
+
 static inline TCGCond tcg_unsigned_cond(TCGCond c)
 {
     return (c >= TCG_COND_LT && c <= TCG_COND_GT ? c + 4 : c);
Signature · 1 line
1.6.5.2
#4 lore raw

PATCH 4/6 tcg-i386: Implement small forward branches.

In reply to Richard Henderson

There are places, like brcond2, where we know that the destination of a forward branch will be within 127 bytes.

Add the R_386_PC8 relocation type to support this. Add a flag to tcg_out_jxx and tcg_out_brcond* to enable it. Set the flag in the brcond2 label_next branches; pass along the input flag otherwise.

---
 elf.h                 |    2 +
 tcg/i386/tcg-target.c |  116 +++++++++++++++++++++++++++++++++----------------
 2 files changed, 80 insertions(+), 38 deletions(-)
elf.h +2 -0
index 11674d7..c84c8ab 100644
@@ -243,6 +243,8 @@ typedef struct {
 #define R_386_GOTOFF	9
 #define R_386_GOTPC	10
 #define R_386_NUM	11
+/* Not a dynamic reloc, so not included in R_386_NUM.  Used in TCG.  */
+#define R_386_PC8	23
 
 #define R_MIPS_NONE		0
 #define R_MIPS_16		1
tcg/i386/tcg-target.c +78 -38

197 lines not on this page · raw message

Signature · 1 line
1.6.5.2
#5 lore raw

Re: [Qemu-devel] [PATCH 4/6] tcg-i386: Implement small forward branches.

Quoted 31 lines · Richard Henderson

There are places, like brcond2, where we know that the destination of a forward branch will be within 127 bytes.

Add the R_386_PC8 relocation type to support this. Add a flag to tcg_out_jxx and tcg_out_brcond* to enable it. Set the flag in the brcond2 label_next branches; pass along the input flag otherwise.

---
 elf.h                 |    2 +
 tcg/i386/tcg-target.c |  116 +++++++++++++++++++++++++++++++++----------------
 2 files changed, 80 insertions(+), 38 deletions(-)
elf.h +2 -0
index 11674d7..c84c8ab 100644
@@ -243,6 +243,8 @@ typedef struct {
 #define R_386_GOTOFF	9
 #define R_386_GOTPC	10
 #define R_386_NUM	11
+/* Not a dynamic reloc, so not included in R_386_NUM.  Used in TCG.  */
+#define R_386_PC8	23
 
 #define R_MIPS_NONE		0
 #define R_MIPS_16		1
tcg/i386/tcg-target.c +0 -0
index 972b102..e1691b3 100644

tcg/i386/tcg-target.c static void patch_reloc(uint8_t *code_ptr, int type, · line 67

Quoted 7 lines
tcg/i386/tcg-target.c +4 -0
@@ -61,6 +61,12 @@ static void patch_reloc(uint8_t *code_ptr, int type,
     case R_386_PC32:
         *(uint32_t *)code_ptr = value - (long)code_ptr;
         break;
+    case R_386_PC8:
+        value -= (long)code_ptr;
+        if (value != (int8_t)value)
+            tcg_abort();

This does not conforms to CODING_STYLE, curly brackets are missing.

Signature · 2 lines
Aurelien Jarno                          GPG: 1024D/F1BCDB73
[email protected]                 http://www.aurel32.net
#6 lore raw

PATCH 5/6 tcg-i386: Implement setcond.

In reply to Richard Henderson
---
 tcg/i386/tcg-target.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 70 insertions(+), 3 deletions(-)
tcg/i386/tcg-target.c +70 -3
index e1691b3..3914570 100644
@@ -360,9 +360,8 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small)
     }
 }
 
-static void tcg_out_brcond(TCGContext *s, int cond, 
-                           TCGArg arg1, TCGArg arg2, int const_arg2,
-                           int label_index, int small)
+static void tcg_out_cmp(TCGContext *s, TCGArg arg1, TCGArg arg2,
+                        int const_arg2)
 {
     if (const_arg2) {
         if (arg2 == 0) {
@@ -374,6 +373,13 @@ static void tcg_out_brcond(TCGContext *s, int cond,
     } else {
         tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3), arg2, arg1);
     }
+}
+
+static void tcg_out_brcond(TCGContext *s, int cond,
+                           TCGArg arg1, TCGArg arg2, int const_arg2,
+                           int label_index, int small)
+{
+    tcg_out_cmp(s, arg1, arg2, const_arg2);
     tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index, small);
 }
 
@@ -459,6 +465,57 @@ static void tcg_out_brcond2(TCGContext *s, const TCGArg *args,
     tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr);
 }
 
+static void tcg_out_setcond(TCGContext *s, int cond, TCGArg dest,
+                            TCGArg arg1, TCGArg arg2, int const_arg2)
+{
+    tcg_out_cmp(s, arg1, arg2, const_arg2);
+    /* setcc */
+    tcg_out_modrm(s, 0x90 | tcg_cond_to_jcc[cond] | P_EXT, 0, dest);
+    tgen_arithi(s, ARITH_AND, dest, 0xff, 0);
+}
+
+static void tcg_out_setcond2(TCGContext *s, const TCGArg *args,
+                             const int *const_args)
+{
+    TCGArg new_args[6];
+    int label_true, label_over;
+
+    memcpy(new_args, args+1, 5*sizeof(TCGArg));
+
+    if (args[0] == args[1] || args[0] == args[2]
+        || (!const_args[3] && args[0] == args[3])
+        || (!const_args[4] && args[0] == args[4])) {
+        /* When the destination overlaps with one of the argument
+           registers, don't do anything tricky.  */
+        label_true = gen_new_label();
+        label_over = gen_new_label();
+
+        new_args[5] = label_true;
+        tcg_out_brcond2(s, new_args, const_args+1, 1);
+
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], 0);
+        tcg_out_jxx(s, JCC_JMP, label_over, 1);
+        tcg_out_label(s, label_true, (tcg_target_long)s->code_ptr);
+
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], 1);
+        tcg_out_label(s, label_over, (tcg_target_long)s->code_ptr);
+    } else {
+        /* When the destination does not overlap one of the arguments,
+           clear the destination first, jump if cond false, and emit an
+           increment in the true case.  This results in smaller code.  */
+
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], 0);
+
+        label_over = gen_new_label();
+        new_args[4] = tcg_invert_cond(new_args[4]);
+        new_args[5] = label_over;
+        tcg_out_brcond2(s, new_args, const_args+1, 1);
+
+        tgen_arithi(s, ARITH_ADD, args[0], 1, 0);
+        tcg_out_label(s, label_over, (tcg_target_long)s->code_ptr);
+    }
+}
+
 #if defined(CONFIG_SOFTMMU)
 
 #include "../../softmmu_defs.h"
@@ -1120,6 +1177,13 @@ static inline void tcg_out_op(TCGContext *s, int opc,
         tcg_out_modrm(s, 0xb7 | P_EXT, args[0], args[1]);
         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, const_args);
+        break;
+
     case INDEX_op_qemu_ld8u:
         tcg_out_qemu_ld(s, args, 0);
         break;
@@ -1208,6 +1272,9 @@ static const TCGTargetOpDef x86_op_defs[] = {
     { INDEX_op_ext8u_i32, { "r", "q"} },
     { INDEX_op_ext16u_i32, { "r", "r"} },
 
+    { INDEX_op_setcond_i32, { "q", "r", "ri" } },
+    { INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } },
+
 #if TARGET_LONG_BITS == 32
     { INDEX_op_qemu_ld8u, { "r", "L" } },
     { INDEX_op_qemu_ld8s, { "r", "L" } },
Signature · 1 line
1.6.5.2
#7 lore raw

PATCH 6/6 tcg-x86_64: Implement setcond.

In reply to Richard Henderson
---
 tcg/x86_64/tcg-target.c |   38 +++++++++++++++++++++++++++++++++-----
 1 files changed, 33 insertions(+), 5 deletions(-)
tcg/x86_64/tcg-target.c +33 -5
index 2339091..33dc452 100644
@@ -491,26 +491,42 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index)
     }
 }
 
-static void tcg_out_brcond(TCGContext *s, int cond, 
-                           TCGArg arg1, TCGArg arg2, int const_arg2,
-                           int label_index, int rexw)
+static void tcg_out_cmp(TCGContext *s, TCGArg arg1, TCGArg arg2,
+                        int const_arg2, int rexw)
 {
     if (const_arg2) {
         if (arg2 == 0) {
             /* test r, r */
             tcg_out_modrm(s, 0x85 | rexw, arg1, arg1);
         } else {
-            if (rexw)
+            if (rexw) {
                 tgen_arithi64(s, ARITH_CMP, arg1, arg2);
-            else
+            } else {
                 tgen_arithi32(s, ARITH_CMP, arg1, arg2);
+            }
         }
     } else {
         tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3) | rexw, arg2, arg1);
     }
+}
+
+static void tcg_out_brcond(TCGContext *s, int cond,
+                           TCGArg arg1, TCGArg arg2, int const_arg2,
+                           int label_index, int rexw)
+{
+    tcg_out_cmp(s, arg1, arg2, const_arg2, rexw);
     tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index);
 }
 
+static void tcg_out_setcond(TCGContext *s, int cond, TCGArg dest,
+                            TCGArg arg1, TCGArg arg2, int const_arg2, int rexw)
+{
+    tcg_out_cmp(s, arg1, arg2, const_arg2, rexw);
+    /* setcc */
+    tcg_out_modrm(s, 0x90 | tcg_cond_to_jcc[cond] | P_EXT | P_REXB, 0, dest);
+    tgen_arithi32(s, ARITH_AND, dest, 0xff);
+}
+
 #if defined(CONFIG_SOFTMMU)
 
 #include "../../softmmu_defs.h"
@@ -1197,6 +1213,15 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
         tcg_out_modrm(s, 0x8b, args[0], args[1]);
         break;
 
+    case INDEX_op_setcond_i32:
+        tcg_out_setcond(s, args[3], args[0], args[1], args[2],
+                        const_args[2], 0);
+        break;
+    case INDEX_op_setcond_i64:
+        tcg_out_setcond(s, args[3], args[0], args[1], args[2],
+                        const_args[2], P_REXW);
+        break;
+
     case INDEX_op_qemu_ld8u:
         tcg_out_qemu_ld(s, args, 0);
         break;
@@ -1376,6 +1401,9 @@ static const TCGTargetOpDef x86_64_op_defs[] = {
     { INDEX_op_ext16u_i64, { "r", "r"} },
     { INDEX_op_ext32u_i64, { "r", "r"} },
 
+    { INDEX_op_setcond_i32, { "r", "r", "ri" } },
+    { INDEX_op_setcond_i64, { "r", "r", "re" } },
+
     { INDEX_op_qemu_ld8u, { "r", "L" } },
     { INDEX_op_qemu_ld8s, { "r", "L" } },
     { INDEX_op_qemu_ld16u, { "r", "L" } },
Signature · 1 line
1.6.5.2
#8 lore raw
In reply to Richard Henderson
Quoted 8 lines · Richard Henderson

Changes since round 4:

* Document double-word support opcodes in a new section of the README, as requested by Aurelien.

* Shorten the branch-to-next in the EQ case of i386 brcond2, as pointed out by Laurent.

Quoted 8 lines

Richard Henderson (6):
tcg: Document double-word support opcodes.
tcg: Generic support for conditional set
tcg: Add tcg_invert_cond.
tcg-i386: Implement small forward branches.
tcg-i386: Implement setcond.
tcg-x86_64: Implement setcond.

Thanks, I have applied patches 1, 2, 3 and 6, and made a comment on patch 4.

Signature · 2 lines
Aurelien Jarno                          GPG: 1024D/F1BCDB73
[email protected]                 http://www.aurel32.net