From patchwork Tue Jan 11 03:23:46 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 78273 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id F0BF3B70E2 for ; Tue, 11 Jan 2011 14:33:46 +1100 (EST) Received: from localhost ([127.0.0.1]:46133 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PcUzE-00041c-5g for incoming@patchwork.ozlabs.org; Mon, 10 Jan 2011 22:33:32 -0500 Received: from [140.186.70.92] (port=47429 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PcUqF-0006yl-Q3 for qemu-devel@nongnu.org; Mon, 10 Jan 2011 22:24:17 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PcUqB-0005YW-Qf for qemu-devel@nongnu.org; Mon, 10 Jan 2011 22:24:15 -0500 Received: from a.mail.sonic.net ([64.142.16.245]:48605) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PcUqB-0005Y4-GG for qemu-devel@nongnu.org; Mon, 10 Jan 2011 22:24:11 -0500 Received: from are.twiddle.net (are.twiddle.net [75.101.38.216]) by a.mail.sonic.net (8.13.8.Beta0-Sonic/8.13.7) with ESMTP id p0B3Nq08030818 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 10 Jan 2011 19:23:52 -0800 Received: from are.twiddle.net (localhost [127.0.0.1]) by are.twiddle.net (8.14.4/8.14.4) with ESMTP id p0B3NqpI009361; Mon, 10 Jan 2011 19:23:52 -0800 Received: (from rth@localhost) by are.twiddle.net (8.14.4/8.14.4/Submit) id p0B3NqsW009360; Mon, 10 Jan 2011 19:23:52 -0800 From: Richard Henderson To: qemu-devel@nongnu.org Date: Mon, 10 Jan 2011 19:23:46 -0800 Message-Id: <1294716228-9299-6-git-send-email-rth@twiddle.net> X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <1294716228-9299-1-git-send-email-rth@twiddle.net> References: <1294716228-9299-1-git-send-email-rth@twiddle.net> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 Cc: agraf@suse.de, aurelien@aurel32.net Subject: [Qemu-devel] [PATCH 5/7] tcg-i386: Implement deposit operation. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Special case deposits that are implementable with byte and word stores. Otherwise implement with double-word shift plus rotates. Expose tcg_scratch_alloc to the backend for allocation of scratch registers. Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++-- tcg/i386/tcg-target.h | 2 + tcg/tcg.c | 11 ++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index bb19a95..ba1c45a 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -258,7 +258,8 @@ static inline int tcg_target_const_match(tcg_target_long val, #define OPC_JMP_long (0xe9) #define OPC_JMP_short (0xeb) #define OPC_LEA (0x8d) -#define OPC_MOVB_EvGv (0x88) /* stores, more or less */ +#define OPC_MOVB_EbGb (0x88) /* stores, more or less */ +#define OPC_MOVB_GbEb (0x8a) /* loads, more or less */ #define OPC_MOVL_EvGv (0x89) /* stores, more or less */ #define OPC_MOVL_GvEv (0x8b) /* loads, more or less */ #define OPC_MOVL_EvIz (0xc7) @@ -277,6 +278,7 @@ static inline int tcg_target_const_match(tcg_target_long val, #define OPC_SHIFT_1 (0xd1) #define OPC_SHIFT_Ib (0xc1) #define OPC_SHIFT_cl (0xd3) +#define OPC_SHRD_Ib (0xac | P_EXT) #define OPC_TESTL (0x85) #define OPC_XCHG_ax_r32 (0x90) @@ -710,6 +712,59 @@ static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) } } +static void tcg_out_deposit(TCGContext *s, int inout, int val, + unsigned ofs, unsigned len, int rexw) +{ + /* Look for MOVW special case. */ + if (ofs == 0 && len == 16) { + tcg_out_modrm(s, OPC_MOVL_GvEv + P_DATA16, inout, val); + return; + } + + /* Look for MOVB w/ %reg_l special case. */ + if (ofs == 0 && len == 8 + && (TCG_TARGET_REG_BITS == 64 || (inout < 4 && val < 4))) { + tcg_out_modrm(s, OPC_MOVB_GbEb + P_REXB_R + P_REXB_RM, inout, val); + return; + } + + /* Look for MOVB w/ %reg_h special case. */ + if (ofs == 8 && len == 8 && inout < 4 && val < 4) { + tcg_out_modrm(s, OPC_MOVB_GbEb, inout + 4, val); + return; + } + + /* If we have a real deposit from self, we need a temporary. */ + if (inout == val) { + TCGType type = rexw ? TCG_TYPE_I64 : TCG_TYPE_I32; + TCGRegSet live; + + tcg_regset_clear(live); + tcg_regset_set_reg(live, inout); + val = tcg_scratch_alloc(s, type, live); + + tcg_out_mov(s, type, val, inout); + } + + /* Arrange for the field to be at offset 0. */ + if (ofs != 0) { + tcg_out_shifti(s, SHIFT_ROR + rexw, inout, ofs); + } + + /* Shift the value into the top of the word. This shifts the old + field out of the bottom of the word and leaves us with the whole + word rotated right by the size of the field. */ + tcg_out_modrm(s, OPC_SHRD_Ib + rexw, val, inout); + tcg_out8(s, len); + + /* Restore the field to its proper location. */ + ofs = (len + ofs) & (rexw ? 63 : 31); + if (ofs != 0) { + tcg_out_shifti(s, SHIFT_ROL + rexw, inout, ofs); + } +} + + /* Use SMALL != 0 to force a short forward branch. */ static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small) { @@ -1266,7 +1321,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi, switch (sizeop) { case 0: - tcg_out_modrm_offset(s, OPC_MOVB_EvGv + P_REXB_R, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVB_EbGb + P_REXB_R, datalo, base, ofs); break; case 1: if (bswap) { @@ -1504,7 +1559,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; OP_32_64(st8): - tcg_out_modrm_offset(s, OPC_MOVB_EvGv | P_REXB_R, + tcg_out_modrm_offset(s, OPC_MOVB_EbGb | P_REXB_R, args[0], args[1], args[2]); break; OP_32_64(st16): @@ -1603,6 +1658,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, } break; + OP_32_64(deposit): + tcg_out_deposit(s, args[0], args[2], args[3], args[4], rexw); + break; + case INDEX_op_brcond_i32: tcg_out_brcond32(s, args[2], args[0], args[1], const_args[1], args[3], 0); @@ -1783,6 +1842,7 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_sar_i32, { "r", "0", "ci" } }, { INDEX_op_rotl_i32, { "r", "0", "ci" } }, { INDEX_op_rotr_i32, { "r", "0", "ci" } }, + { INDEX_op_deposit_i32, { "r", "0", "r" } }, { INDEX_op_brcond_i32, { "r", "ri" } }, @@ -1835,6 +1895,7 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_sar_i64, { "r", "0", "ci" } }, { INDEX_op_rotl_i64, { "r", "0", "ci" } }, { INDEX_op_rotr_i64, { "r", "0", "ci" } }, + { INDEX_op_deposit_i64, { "r", "0", "r" } }, { INDEX_op_brcond_i64, { "r", "re" } }, { INDEX_op_setcond_i64, { "r", "r", "re" } }, diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index bfafbfc..9f90d17 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -77,6 +77,7 @@ enum { /* optional instructions */ #define TCG_TARGET_HAS_div2_i32 #define TCG_TARGET_HAS_rot_i32 +#define TCG_TARGET_HAS_deposit_i32 #define TCG_TARGET_HAS_ext8s_i32 #define TCG_TARGET_HAS_ext16s_i32 #define TCG_TARGET_HAS_ext8u_i32 @@ -94,6 +95,7 @@ enum { #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div2_i64 #define TCG_TARGET_HAS_rot_i64 +#define TCG_TARGET_HAS_deposit_i64 #define TCG_TARGET_HAS_ext8s_i64 #define TCG_TARGET_HAS_ext16s_i64 #define TCG_TARGET_HAS_ext32s_i64 diff --git a/tcg/tcg.c b/tcg/tcg.c index 5dd6a2c..d190a20 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -156,6 +156,17 @@ int gen_new_label(void) return idx; } +static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2); + +/* For use by backends, allocate a scratch register of TYPE, avoiding + any that are present in live. */ + +static inline int tcg_scratch_alloc(TCGContext *s, TCGType type, TCGRegSet live) +{ + tcg_regset_or (live, s->reserved_regs, live); + return tcg_reg_alloc(s, tcg_target_available_regs[type], live); +} + #include "tcg-target.c" /* pool based memory allocation */