Patchwork [33/62] tcg-s390: Implement immediate ORs.

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

Comments

Richard Henderson - May 27, 2010, 8:46 p.m.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 tcg/s390/tcg-target.c |   63 +++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 59 insertions(+), 4 deletions(-)

Patch

diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index 2fd58bd..2a9d64d 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -53,6 +53,8 @@  typedef enum S390Opcode {
     RIL_LLILF   = 0xc00f,
     RIL_NIHF    = 0xc00a,
     RIL_NILF    = 0xc00b,
+    RIL_OIHF    = 0xc00c,
+    RIL_OILF    = 0xc00d,
 
     RI_AGHI     = 0xa70b,
     RI_AHI      = 0xa70a,
@@ -70,6 +72,10 @@  typedef enum S390Opcode {
     RI_NIHL     = 0xa505,
     RI_NILH     = 0xa506,
     RI_NILL     = 0xa507,
+    RI_OIHH     = 0xa508,
+    RI_OIHL     = 0xa509,
+    RI_OILH     = 0xa50a,
+    RI_OILL     = 0xa50b,
 
     RRE_AGR     = 0xb908,
     RRE_CGR     = 0xb920,
@@ -668,6 +674,47 @@  static void tgen64_andi(TCGContext *s, TCGReg dest, tcg_target_ulong val)
     tgen64_andi(s, dest, val | 0x00000000ffffffffull);
 }
 
+static void tgen64_ori(TCGContext *s, TCGReg dest, tcg_target_ulong val)
+{
+    static const S390Opcode oi_insns[4] = {
+        RI_OILL, RI_OILH, RI_OIHL, RI_OIHH
+    };
+    static const S390Opcode nif_insns[2] = {
+        RIL_OILF, RIL_OIHF
+    };
+
+    int i;
+
+    /* Zero-th, look for no-op.  */
+    if (val == 0) {
+        return;
+    }
+
+    /* First, try all 32-bit insns that can perform it in one go.  */
+    for (i = 0; i < 4; i++) {
+        tcg_target_ulong mask = (0xffffull << i*16);
+        if ((val & mask) != 0 && (val & ~mask) == 0) {
+            tcg_out_insn_RI(s, oi_insns[i], dest, val >> i*16);
+            return;
+        }
+    }
+
+    /* Second, try all 48-bit insns that can perform it in one go.  */
+    for (i = 0; i < 2; i++) {
+        tcg_target_ulong mask = (0xffffffffull << i*32);
+        if ((val & mask) != 0 && (val & ~mask) == 0) {
+            tcg_out_insn_RIL(s, nif_insns[i], dest, val >> i*32);
+            return;
+        }
+    }
+
+    /* Last, perform the OR via sequential modifications to the
+       high and low parts.  Do this via recursion to handle 16-bit
+       vs 32-bit masks in each half.  */
+    tgen64_ori(s, dest, val & 0x00000000ffffffffull);
+    tgen64_ori(s, dest, val & 0xffffffff00000000ull);
+}
+
 static void tgen32_cmp(TCGContext *s, TCGCond c, TCGReg r1, TCGReg r2)
 {
     if (c > TCG_COND_GT) {
@@ -1144,7 +1191,11 @@  static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
         }
         break;
     case INDEX_op_or_i32:
-        tcg_out_insn(s, RR, OR, args[0], args[2]);
+        if (const_args[2]) {
+            tgen64_ori(s, args[0], args[2] & 0xffffffff);
+        } else {
+            tcg_out_insn(s, RR, OR, args[0], args[2]);
+        }
         break;
     case INDEX_op_xor_i32:
         tcg_out_insn(s, RR, XR, args[0], args[2]);
@@ -1158,7 +1209,11 @@  static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
         }
         break;
     case INDEX_op_or_i64:
-        tcg_out_insn(s, RRE, OGR, args[0], args[2]);
+        if (const_args[2]) {
+            tgen64_ori(s, args[0], args[2]);
+        } else {
+            tcg_out_insn(s, RRE, OGR, args[0], args[2]);
+        }
         break;
     case INDEX_op_xor_i64:
         tcg_out_insn(s, RRE, XGR, args[0], args[2]);
@@ -1414,7 +1469,7 @@  static const TCGTargetOpDef s390_op_defs[] = {
     { INDEX_op_divu2_i32, { "b", "a", "0", "1", "r" } },
 
     { INDEX_op_and_i32, { "r", "0", "ri" } },
-    { INDEX_op_or_i32, { "r", "0", "r" } },
+    { INDEX_op_or_i32, { "r", "0", "ri" } },
     { INDEX_op_xor_i32, { "r", "0", "r" } },
     { INDEX_op_neg_i32, { "r", "r" } },
 
@@ -1475,7 +1530,7 @@  static const TCGTargetOpDef s390_op_defs[] = {
     { INDEX_op_divu2_i64, { "b", "a", "0", "1", "r" } },
 
     { INDEX_op_and_i64, { "r", "0", "ri" } },
-    { INDEX_op_or_i64, { "r", "0", "r" } },
+    { INDEX_op_or_i64, { "r", "0", "ri" } },
     { INDEX_op_xor_i64, { "r", "0", "r" } },
     { INDEX_op_neg_i64, { "r", "r" } },