Instead of assuming only small immediates are available for AND,
consult the backend in order to decide between SHL/SHR and SHR/AND.

Signed-off-by: Paolo Bonzini <[email protected]>
---
 include/tcg/tcg.h |  2 ++
 tcg/tcg-op.c      | 30 ++++++++++++++----------------
 tcg/tcg.c         | 23 +++++++++++++++++++----
 3 files changed, 35 insertions(+), 20 deletions(-)

diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index a6d9aa50d47..6ca5bf7f67b 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -795,6 +795,8 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned 
flags);
  */
 bool tcg_op_deposit_valid(TCGType type, unsigned ofs, unsigned len);
 
+bool tcg_op_imm_match(TCGOpcode op, TCGType type, tcg_target_ulong imm);
+
 void tcg_gen_call0(void *func, TCGHelperInfo *, TCGTemp *ret);
 void tcg_gen_call1(void *func, TCGHelperInfo *, TCGTemp *ret, TCGTemp *);
 void tcg_gen_call2(void *func, TCGHelperInfo *, TCGTemp *ret,
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index ab7b409be61..ccf66382623 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -995,18 +995,17 @@ void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg,
         return;
     }
 
-    /* ??? Ideally we'd know what values are available for immediate AND.
-       Assume that 8 bits are available, plus the special case of 16,
-       so that we get ext8u, ext16u.  */
-    switch (len) {
-    case 1 ... 8: case 16:
+    /*
+     * Use TCG_TARGET_extract_valid to check for 8- and 16-bit extension
+     * opcodes, which tcg_gen_andi_i32 can produce.
+     */
+    if (TCG_TARGET_extract_valid(TCG_TYPE_I32, 0, len) ||
+        tcg_op_imm_match(INDEX_op_and, TCG_TYPE_I32, (1u << len) - 1)) {
         tcg_gen_shri_i32(ret, arg, ofs);
         tcg_gen_andi_i32(ret, ret, (1u << len) - 1);
-        break;
-    default:
+    } else {
         tcg_gen_shli_i32(ret, arg, 32 - len - ofs);
         tcg_gen_shri_i32(ret, ret, 32 - len);
-        break;
     }
 }
 
@@ -2690,18 +2689,17 @@ void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg,
         return;
     }
 
-    /* ??? Ideally we'd know what values are available for immediate AND.
-       Assume that 8 bits are available, plus the special cases of 16 and 32,
-       so that we get ext8u, ext16u, and ext32u.  */
-    switch (len) {
-    case 1 ... 8: case 16: case 32:
+    /*
+     * Use TCG_TARGET_extract_valid to check for 8-, 16- and 32-bit extension
+     * opcodes, which tcg_gen_andi_i64 can produce.
+     */
+    if (TCG_TARGET_extract_valid(TCG_TYPE_I64, 0, len) ||
+        tcg_op_imm_match(INDEX_op_and, TCG_TYPE_I64, (1ull << len) - 1)) {
         tcg_gen_shri_i64(ret, arg, ofs);
         tcg_gen_andi_i64(ret, ret, (1ull << len) - 1);
-        break;
-    default:
+    } else {
         tcg_gen_shli_i64(ret, arg, 64 - len - ofs);
         tcg_gen_shri_i64(ret, ret, 64 - len);
-        break;
     }
 }
 
diff --git a/tcg/tcg.c b/tcg/tcg.c
index fbf09f5c826..79ca49154a2 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -3509,11 +3509,8 @@ static void process_constraint_sets(void)
     }
 }
 
-static const TCGArgConstraint *opcode_args_ct(const TCGOp *op)
+static const TCGArgConstraint *op_args_ct(TCGOpcode opc, TCGType type, 
unsigned flags)
 {
-    TCGOpcode opc = op->opc;
-    TCGType type = TCGOP_TYPE(op);
-    unsigned flags = TCGOP_FLAGS(op);
     const TCGOpDef *def = &tcg_op_defs[opc];
     const TCGOutOp *outop = all_outop[opc];
     TCGConstraintSetIndex con_set;
@@ -3540,6 +3537,24 @@ static const TCGArgConstraint *opcode_args_ct(const 
TCGOp *op)
     return all_cts[con_set];
 }
 
+static const TCGArgConstraint *opcode_args_ct(const TCGOp *op)
+{
+    return op_args_ct(op->opc, TCGOP_TYPE(op), TCGOP_FLAGS(op));
+}
+
+/* Return true if the backend can efficiently handle IMM as an immediate
+   for OP.  */
+bool tcg_op_imm_match(TCGOpcode opc, TCGType type, tcg_target_ulong imm)
+{
+    const TCGOpDef * const def = &tcg_op_defs[opc];
+    const TCGArgConstraint *args_ct = op_args_ct(opc, type, 0);
+
+    tcg_debug_assert(def->nb_iargs == 2);
+    return tcg_target_const_match(
+        imm, args_ct[def->nb_oargs + 2].ct,
+        type, 0, 0);
+}
+
 static void remove_label_use(TCGOp *op, int idx)
 {
     TCGLabel *label = arg_label(op->args[idx]);
-- 
2.52.0


Reply via email to