Patchwork [56/62] tcg-s390: Use the LOAD AND TEST instruction for compares.

login
register
mail settings
Submitter Richard Henderson
Date May 27, 2010, 8:46 p.m.
Message ID <1274993204-30766-57-git-send-email-rth@twiddle.net>
Download mbox | patch
Permalink /patch/53847/
State New
Headers show

Comments

Richard Henderson - May 27, 2010, 8:46 p.m.
This instruction is always available, and nicely eliminates
the constant load for comparisons against zero.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 tcg/s390/tcg-target.c |  133 +++++++++++++++++++++++++++++++++---------------
 1 files changed, 91 insertions(+), 42 deletions(-)

Patch

diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index 697c5e4..edae6a8 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -45,6 +45,7 @@ 
 #define TCG_CT_CONST_ANDI  0x1000
 #define TCG_CT_CONST_ORI   0x2000
 #define TCG_CT_CONST_XORI  0x4000
+#define TCG_CT_CONST_CMPI  0x8000
 
 #define TCG_TMP0           TCG_REG_R14
 
@@ -126,6 +127,7 @@  typedef enum S390Opcode {
     RRE_LLGHR   = 0xb985,
     RRE_LRVR    = 0xb91f,
     RRE_LRVGR   = 0xb90f,
+    RRE_LTGR    = 0xb902,
     RRE_MSGR    = 0xb90c,
     RRE_MSR     = 0xb252,
     RRE_NGR     = 0xb980,
@@ -141,6 +143,7 @@  typedef enum S390Opcode {
     RR_DR       = 0x1d,
     RR_LCR      = 0x13,
     RR_LR       = 0x18,
+    RR_LTR      = 0x12,
     RR_NR       = 0x14,
     RR_OR       = 0x16,
     RR_SR       = 0x1b,
@@ -242,9 +245,6 @@  static const int tcg_target_call_oarg_regs[] = {
     TCG_REG_R3,
 };
 
-/* signed/unsigned is handled by using COMPARE and COMPARE LOGICAL,
-   respectively */
-
 #define S390_CC_EQ      8
 #define S390_CC_LT      4
 #define S390_CC_GT      2
@@ -252,19 +252,37 @@  static const int tcg_target_call_oarg_regs[] = {
 #define S390_CC_NE      (S390_CC_LT | S390_CC_GT)
 #define S390_CC_LE      (S390_CC_LT | S390_CC_EQ)
 #define S390_CC_GE      (S390_CC_GT | S390_CC_EQ)
+#define S390_CC_NEVER   0
 #define S390_CC_ALWAYS  15
 
+/* Condition codes that result from a COMPARE and COMPARE LOGICAL.  */
 static const uint8_t tcg_cond_to_s390_cond[10] = {
     [TCG_COND_EQ]  = S390_CC_EQ,
+    [TCG_COND_NE]  = S390_CC_NE,
     [TCG_COND_LT]  = S390_CC_LT,
-    [TCG_COND_LTU] = S390_CC_LT,
     [TCG_COND_LE]  = S390_CC_LE,
-    [TCG_COND_LEU] = S390_CC_LE,
     [TCG_COND_GT]  = S390_CC_GT,
-    [TCG_COND_GTU] = S390_CC_GT,
     [TCG_COND_GE]  = S390_CC_GE,
+    [TCG_COND_LTU] = S390_CC_LT,
+    [TCG_COND_LEU] = S390_CC_LE,
+    [TCG_COND_GTU] = S390_CC_GT,
     [TCG_COND_GEU] = S390_CC_GE,
+};
+
+/* Condition codes that result from a LOAD AND TEST.  Here, we have no
+   unsigned instruction variation, however since the test is vs zero we
+   can re-map the outcomes appropriately.  */
+static const uint8_t tcg_cond_to_ltr_cond[10] = {
+    [TCG_COND_EQ]  = S390_CC_EQ,
     [TCG_COND_NE]  = S390_CC_NE,
+    [TCG_COND_LT]  = S390_CC_LT,
+    [TCG_COND_LE]  = S390_CC_LE,
+    [TCG_COND_GT]  = S390_CC_GT,
+    [TCG_COND_GE]  = S390_CC_GE,
+    [TCG_COND_LTU] = S390_CC_NEVER,
+    [TCG_COND_LEU] = S390_CC_EQ,
+    [TCG_COND_GTU] = S390_CC_NE,
+    [TCG_COND_GEU] = S390_CC_ALWAYS,
 };
 
 #ifdef CONFIG_SOFTMMU
@@ -381,6 +399,10 @@  static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
         ct->ct &= ~TCG_CT_REG;
         ct->ct |= TCG_CT_CONST_XORI;
         break;
+    case 'C':
+        ct->ct &= ~TCG_CT_REG;
+        ct->ct |= TCG_CT_CONST_CMPI;
+        break;
     default:
         break;
     }
@@ -501,6 +523,13 @@  static int tcg_match_xori(int ct, tcg_target_long val)
     return 1;
 }
 
+/* Imediates to be used with comparisons.  */
+
+static int tcg_match_cmpi(int ct, tcg_target_long val)
+{
+    return (val == 0);
+}
+
 /* Test if a constant matches the constraint. */
 static int tcg_target_const_match(tcg_target_long val,
                                   const TCGArgConstraint *arg_ct)
@@ -546,6 +575,8 @@  static int tcg_target_const_match(tcg_target_long val,
         return tcg_match_ori(ct, val);
     } else if (ct & TCG_CT_CONST_XORI) {
         return tcg_match_xori(ct, val);
+    } else if (ct & TCG_CT_CONST_CMPI) {
+        return tcg_match_cmpi(ct, val);
     }
 
     return 0;
@@ -1040,39 +1071,48 @@  static void tgen64_xori(TCGContext *s, TCGReg dest, tcg_target_ulong val)
     }
 }
 
-static void tgen32_cmp(TCGContext *s, TCGCond c, TCGReg r1, TCGReg r2)
-{
-    if (c > TCG_COND_GT) {
-        /* unsigned */
-        tcg_out_insn(s, RR, CLR, r1, r2);
-    } else {
-        /* signed */
-        tcg_out_insn(s, RR, CR, r1, r2);
-    }
-}
-
-static void tgen64_cmp(TCGContext *s, TCGCond c, TCGReg r1, TCGReg r2)
+static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
+                    TCGArg c2, int c2const)
 {
-    if (c > TCG_COND_GT) {
-        /* unsigned */
-        tcg_out_insn(s, RRE, CLGR, r1, r2);
+    if (c2const) {
+        if (c2 == 0) {
+            if (type == TCG_TYPE_I32) {
+                tcg_out_insn(s, RR, LTR, r1, r1);
+            } else {
+                tcg_out_insn(s, RRE, LTGR, r1, r1);
+            }
+            return tcg_cond_to_ltr_cond[c];
+        } else {
+            tcg_abort();
+        }
     } else {
-        /* signed */
-        tcg_out_insn(s, RRE, CGR, r1, r2);
+        if (c > TCG_COND_GT) {
+            /* unsigned */
+            if (type == TCG_TYPE_I32) {
+                tcg_out_insn(s, RR, CLR, r1, c2);
+            } else {
+                tcg_out_insn(s, RRE, CLGR, r1, c2);
+            }
+        } else {
+            /* signed */
+            if (type == TCG_TYPE_I32) {
+                tcg_out_insn(s, RR, CR, r1, c2);
+            } else {
+                tcg_out_insn(s, RRE, CGR, r1, c2);
+            }
+        }
     }
+    return tcg_cond_to_s390_cond[c];
 }
 
 static void tgen_setcond(TCGContext *s, TCGType type, TCGCond c,
-                         TCGReg dest, TCGReg r1, TCGReg r2)
+                         TCGReg dest, TCGReg r1, TCGArg c2, int c2const)
 {
-    if (type == TCG_TYPE_I32) {
-        tgen32_cmp(s, c, r1, r2);
-    } else {
-        tgen64_cmp(s, c, r1, r2);
-    }
+    int cc = tgen_cmp(s, type, c, r1, c2, c2const);
+
     /* Emit: r1 = 1; if (cc) goto over; r1 = 0; over:  */
     tcg_out_movi(s, type, dest, 1);
-    tcg_out_insn(s, RI, BRC, tcg_cond_to_s390_cond[c], (4 + 4) >> 1);
+    tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1);
     tcg_out_movi(s, type, dest, 0);
 }
 
@@ -1105,6 +1145,13 @@  static void tgen_branch(TCGContext *s, int cc, int labelno)
     }
 }
 
+static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
+                        TCGReg r1, TCGArg c2, int c2const, int labelno)
+{
+    int cc = tgen_cmp(s, type, c, r1, c2, c2const);
+    tgen_branch(s, cc, labelno);
+}
+
 static void tgen_calli(TCGContext *s, tcg_target_long dest)
 {
     tcg_target_long off = (dest - (tcg_target_long)s->code_ptr) >> 1;
@@ -1739,20 +1786,22 @@  static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
         tgen_branch(s, S390_CC_ALWAYS, args[0]);
         break;
 
-    case INDEX_op_brcond_i64:
-        tgen64_cmp(s, args[2], args[0], args[1]);
-        goto do_brcond;
     case INDEX_op_brcond_i32:
-        tgen32_cmp(s, args[2], args[0], args[1]);
-    do_brcond:
-        tgen_branch(s, tcg_cond_to_s390_cond[args[2]], args[3]);
+        tgen_brcond(s, TCG_TYPE_I32, args[2], args[0],
+                    args[1], const_args[1], args[3]);
+        break;
+    case INDEX_op_brcond_i64:
+        tgen_brcond(s, TCG_TYPE_I64, args[2], args[0],
+                    args[1], const_args[1], args[3]);
         break;
 
     case INDEX_op_setcond_i32:
-        tgen_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], args[2]);
+        tgen_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1],
+                     args[2], const_args[2]);
         break;
     case INDEX_op_setcond_i64:
-        tgen_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], args[2]);
+        tgen_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1],
+                     args[2], const_args[2]);
         break;
 
     case INDEX_op_qemu_ld8u:
@@ -1863,8 +1912,8 @@  static const TCGTargetOpDef s390_op_defs[] = {
     { INDEX_op_bswap16_i32, { "r", "r" } },
     { INDEX_op_bswap32_i32, { "r", "r" } },
 
-    { INDEX_op_brcond_i32, { "r", "r" } },
-    { INDEX_op_setcond_i32, { "r", "r", "r" } },
+    { INDEX_op_brcond_i32, { "r", "rWC" } },
+    { INDEX_op_setcond_i32, { "r", "r", "rWC" } },
 
     { INDEX_op_qemu_ld8u, { "r", "L" } },
     { INDEX_op_qemu_ld8s, { "r", "L" } },
@@ -1927,8 +1976,8 @@  static const TCGTargetOpDef s390_op_defs[] = {
     { INDEX_op_bswap32_i64, { "r", "r" } },
     { INDEX_op_bswap64_i64, { "r", "r" } },
 
-    { INDEX_op_brcond_i64, { "r", "r" } },
-    { INDEX_op_setcond_i64, { "r", "r", "r" } },
+    { INDEX_op_brcond_i64, { "r", "rC" } },
+    { INDEX_op_setcond_i64, { "r", "r", "rC" } },
 #endif
 
     { -1 },