diff options
author | Richard Henderson <rth@twiddle.net> | 2010-01-12 19:59:33 +0000 |
---|---|---|
committer | Blue Swirl <blauwirbel@gmail.com> | 2010-01-12 19:59:33 +0000 |
commit | 583d121520a81d07bacee7ebe9366d107c8b18b6 (patch) | |
tree | edaa4e9824a7b3e99886da07c3fe1a6bb0c61b25 /tcg/sparc | |
parent | 5e143c43a686d5563b3a8c9d46b338967cc8d09c (diff) |
tcg-sparc: Implement division properly.
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 <rth@twiddle.net>
[blauwirbel@gmail.com: applied rth's typo fix in tcg_out_div32]
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Diffstat (limited to 'tcg/sparc')
-rw-r--r-- | tcg/sparc/tcg-target.c | 82 | ||||
-rw-r--r-- | 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 8675fcee11..f6262d0f30 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_arithi(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 e8f8f65ee1..e00707b273 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 |