From patchwork Mon Jan 11 19:09:05 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 42658 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 CD7941007D8 for ; Tue, 12 Jan 2010 07:03:53 +1100 (EST) Received: from localhost ([127.0.0.1]:43454 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NUQSD-0001tN-3U for incoming@patchwork.ozlabs.org; Mon, 11 Jan 2010 15:01:33 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NUQGq-0005JJ-8Y for qemu-devel@nongnu.org; Mon, 11 Jan 2010 14:49:48 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NUQGn-0005GA-FM for qemu-devel@nongnu.org; Mon, 11 Jan 2010 14:49:45 -0500 Received: from [199.232.76.173] (port=33987 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NUQGm-0005FS-Bl for qemu-devel@nongnu.org; Mon, 11 Jan 2010 14:49:44 -0500 Received: from are.twiddle.net ([75.149.56.221]:34146) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NUQGl-0002zF-I2 for qemu-devel@nongnu.org; Mon, 11 Jan 2010 14:49:44 -0500 Received: by are.twiddle.net (Postfix, from userid 5000) id E08DFCEC; Mon, 11 Jan 2010 11:49:41 -0800 (PST) Message-Id: <89dafaffa4df925094d2d43acc985cb040d6161c.1263237726.git.rth@twiddle.net> In-Reply-To: References: From: Richard Henderson Date: Mon, 11 Jan 2010 11:09:05 -0800 To: qemu-devel@nongnu.org X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: blauwirbel@gmail.com Subject: [Qemu-devel] [PATCH 4/5] tcg-sparc: Implement division properly. 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 The {div,divu}2 opcodes are intended for systems for which the division instruction produces both quotient and remainder. Sparc is not such a system. Indeed, the remainder must be computed as quot = a / b rem = a - (quot * b) Split out a tcg_out_div32 function that properly initializes Y with the extension of the input to 64-bits. Discard the code that used the 64-bit DIVX on sparc9/sparcv8plus without extending the inputs to 64-bits. Implement remainders in terms of division followed by multiplication. Signed-off-by: Richard Henderson --- tcg/sparc/tcg-target.c | 82 ++++++++++++++++++++++++++++++----------------- tcg/sparc/tcg-target.h | 3 ++ 2 files changed, 55 insertions(+), 30 deletions(-) diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 8675fce..1bef2fb 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -243,7 +243,7 @@ static inline int tcg_target_const_match(tcg_target_long val, #define SHIFT_SRAX (INSN_OP(2) | INSN_OP3(0x27) | (1 << 12)) #define RDY (INSN_OP(2) | INSN_OP3(0x28) | INSN_RS1(0)) -#define WRY (INSN_OP(2) | INSN_OP3(0x30)) +#define WRY (INSN_OP(2) | INSN_OP3(0x30) | INSN_RD(0)) #define JMPL (INSN_OP(2) | INSN_OP3(0x38)) #define SAVE (INSN_OP(2) | INSN_OP3(0x3c)) #define RESTORE (INSN_OP(2) | INSN_OP3(0x3d)) @@ -407,12 +407,9 @@ static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, tcg_out_ldst(s, arg, arg1, arg2, STX); } -static inline void tcg_out_sety(TCGContext *s, tcg_target_long val) +static inline void tcg_out_sety(TCGContext *s, int rs) { - if (val == 0 || val == -1) - tcg_out32(s, WRY | INSN_IMM13(val)); - else - fprintf(stderr, "unimplemented sety %ld\n", (long)val); + tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs)); } static inline void tcg_out_rdy(TCGContext *s, int rd) @@ -444,6 +441,21 @@ static inline void tcg_out_andi(TCGContext *s, int reg, tcg_target_long val) } } +static void tcg_out_div32(TCGContext *s, int rd, int rs1, + int val2, int val2const, int uns) +{ + /* Load Y with the sign/zero extension of RS1 to 64-bits. */ + if (uns) { + tcg_out_sety(s, TCG_REG_G0); + } else { + tcg_out_arith(s, TCG_REG_I5, rs1, 31, SHIFT_SRA); + tcg_out_sety(s, TCG_REG_I5); + } + + tcg_out_arithc(s, rd, rs1, val2, val2const, + uns ? ARITH_UDIV : ARITH_SDIV); +} + static inline void tcg_out_nop(TCGContext *s) { tcg_out_sethi(s, TCG_REG_G0, 0); @@ -1113,24 +1125,22 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, case INDEX_op_mul_i32: c = ARITH_UMUL; goto gen_arith; - case INDEX_op_div2_i32: -#if defined(__sparc_v9__) || defined(__sparc_v8plus__) - c = ARITH_SDIVX; - goto gen_arith; -#else - tcg_out_sety(s, 0); - c = ARITH_SDIV; - goto gen_arith; -#endif - case INDEX_op_divu2_i32: -#if defined(__sparc_v9__) || defined(__sparc_v8plus__) - c = ARITH_UDIVX; - goto gen_arith; -#else - tcg_out_sety(s, 0); - c = ARITH_UDIV; - goto gen_arith; -#endif + + case INDEX_op_div_i32: + tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 0); + break; + case INDEX_op_divu_i32: + tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 1); + break; + + case INDEX_op_rem_i32: + case INDEX_op_remu_i32: + tcg_out_div32(s, TCG_REG_I5, args[1], args[2], const_args[2], + opc == INDEX_op_remu_i32); + tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2], + ARITH_UMUL); + tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB); + break; case INDEX_op_brcond_i32: tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1], @@ -1214,12 +1224,20 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, case INDEX_op_mul_i64: c = ARITH_MULX; goto gen_arith; - case INDEX_op_div2_i64: + case INDEX_op_div_i64: c = ARITH_SDIVX; goto gen_arith; - case INDEX_op_divu2_i64: + case INDEX_op_divu_i64: c = ARITH_UDIVX; goto gen_arith; + case INDEX_op_rem_i64: + case INDEX_op_remu_i64: + tcg_out_arithc(s, TCG_REG_I5, args[1], args[2], const_args[2], + opc == INDEX_op_rem_i64 ? ARITH_SDIVX : ARITH_UDIVX); + tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2], + ARITH_MULX); + tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB); + break; case INDEX_op_brcond_i64: tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1], @@ -1263,8 +1281,10 @@ static const TCGTargetOpDef sparc_op_defs[] = { { INDEX_op_add_i32, { "r", "r", "rJ" } }, { INDEX_op_mul_i32, { "r", "r", "rJ" } }, - { INDEX_op_div2_i32, { "r", "r", "0", "1", "r" } }, - { INDEX_op_divu2_i32, { "r", "r", "0", "1", "r" } }, + { INDEX_op_div_i32, { "r", "r", "rJ" } }, + { INDEX_op_divu_i32, { "r", "r", "rJ" } }, + { INDEX_op_rem_i32, { "r", "r", "rJ" } }, + { INDEX_op_remu_i32, { "r", "r", "rJ" } }, { INDEX_op_sub_i32, { "r", "r", "rJ" } }, { INDEX_op_and_i32, { "r", "r", "rJ" } }, { INDEX_op_or_i32, { "r", "r", "rJ" } }, @@ -1312,8 +1332,10 @@ static const TCGTargetOpDef sparc_op_defs[] = { { INDEX_op_add_i64, { "r", "r", "rJ" } }, { INDEX_op_mul_i64, { "r", "r", "rJ" } }, - { INDEX_op_div2_i64, { "r", "r", "0", "1", "r" } }, - { INDEX_op_divu2_i64, { "r", "r", "0", "1", "r" } }, + { INDEX_op_div_i64, { "r", "r", "rJ" } }, + { INDEX_op_divu_i64, { "r", "r", "rJ" } }, + { INDEX_op_rem_i64, { "r", "r", "rJ" } }, + { INDEX_op_remu_i64, { "r", "r", "rJ" } }, { INDEX_op_sub_i64, { "r", "r", "rJ" } }, { INDEX_op_and_i64, { "r", "r", "rJ" } }, { INDEX_op_or_i64, { "r", "r", "rJ" } }, diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index e8f8f65..e00707b 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -88,6 +88,9 @@ enum { #endif /* optional instructions */ +#define TCG_TARGET_HAS_div_i32 +#define TCG_TARGET_HAS_div_i64 + //#define TCG_TARGET_HAS_bswap32_i32 //#define TCG_TARGET_HAS_bswap64_i64 //#define TCG_TARGET_HAS_neg_i32