This instruction is always available, and nicely eliminates
the constant load for comparisons against zero.

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

diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index 81d5ad3..8bc82b4 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
 
 /* Several places within the instruction set 0 means "no register"
    rather than TCG_REG_R0.  */
@@ -131,6 +132,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,
@@ -146,6 +148,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,
@@ -248,9 +251,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
@@ -258,19 +258,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
@@ -387,6 +405,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;
     }
@@ -507,6 +529,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)
@@ -552,6 +581,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;
@@ -1050,39 +1081,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);
 }
 
@@ -1115,6 +1155,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;
@@ -1755,20 +1802,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:
@@ -1880,8 +1929,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" } },
@@ -1945,8 +1994,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 },
-- 
1.7.0.1


Reply via email to