On T4 and newer Sparc chips we have an add-with-carry insn that takes its input from %xcc instead of %icc.
Signed-off-by: Richard Henderson <r...@twiddle.net> --- disas/sparc.c | 3 +++ include/elf.h | 37 +++++++++++++++++++++++++++++-------- tcg/sparc/tcg-target.c | 28 +++++++++++++++++++++++----- tcg/sparc/tcg-target.h | 6 ++++++ 4 files changed, 61 insertions(+), 13 deletions(-) diff --git a/disas/sparc.c b/disas/sparc.c index 8eb22e6..092e1b6 100644 --- a/disas/sparc.c +++ b/disas/sparc.c @@ -2042,6 +2042,9 @@ IMPDEP ("impdep2", 0x37), #undef IMPDEP +{ "addxc", F3F(2, 0x36, 0x011), F3F(~2, ~0x36, ~0x011), "1,2,d", 0, v9b }, +{ "addxccc", F3F(2, 0x36, 0x013), F3F(~2, ~0x36, ~0x013), "1,2,d", 0, v9b }, + }; static const int sparc_num_opcodes = ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0])); diff --git a/include/elf.h b/include/elf.h index 70107f0..a516584 100644 --- a/include/elf.h +++ b/include/elf.h @@ -473,14 +473,35 @@ typedef struct { #define PPC_FEATURE_TRUE_LE 0x00000002 #define PPC_FEATURE_PPC_LE 0x00000001 -/* Bits present in AT_HWCAP, primarily for Sparc32. */ - -#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */ -#define HWCAP_SPARC_STBAR 2 -#define HWCAP_SPARC_SWAP 4 -#define HWCAP_SPARC_MULDIV 8 -#define HWCAP_SPARC_V9 16 -#define HWCAP_SPARC_ULTRA3 32 +/* Bits present in AT_HWCAP for Sparc. */ + +#define HWCAP_SPARC_FLUSH 0x00000001 +#define HWCAP_SPARC_STBAR 0x00000002 +#define HWCAP_SPARC_SWAP 0x00000004 +#define HWCAP_SPARC_MULDIV 0x00000008 +#define HWCAP_SPARC_V9 0x00000010 +#define HWCAP_SPARC_ULTRA3 0x00000020 +#define HWCAP_SPARC_BLKINIT 0x00000040 +#define HWCAP_SPARC_N2 0x00000080 +#define HWCAP_SPARC_MUL32 0x00000100 +#define HWCAP_SPARC_DIV32 0x00000200 +#define HWCAP_SPARC_FSMULD 0x00000400 +#define HWCAP_SPARC_V8PLUS 0x00000800 +#define HWCAP_SPARC_POPC 0x00001000 +#define HWCAP_SPARC_VIS 0x00002000 +#define HWCAP_SPARC_VIS2 0x00004000 +#define HWCAP_SPARC_ASI_BLK_INIT 0x00008000 +#define HWCAP_SPARC_FMAF 0x00010000 +#define HWCAP_SPARC_VIS3 0x00020000 +#define HWCAP_SPARC_HPC 0x00040000 +#define HWCAP_SPARC_RANDOM 0x00080000 +#define HWCAP_SPARC_TRANS 0x00100000 +#define HWCAP_SPARC_FJFMAU 0x00200000 +#define HWCAP_SPARC_IMA 0x00400000 +#define HWCAP_SPARC_ASI_CACHE_SPARING 0x00800000 +#define HWCAP_SPARC_PAUSE 0x01000000 +#define HWCAP_SPARC_CBCOND 0x02000000 +#define HWCAP_SPARC_CRYPTO 0x04000000 /* Bits present in AT_HWCAP for s390. */ diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 21981d8..08ca482 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -209,6 +209,8 @@ static const int tcg_target_call_oarg_regs[] = { #define ARITH_MOVCC (INSN_OP(2) | INSN_OP3(0x2c)) #define ARITH_MOVR (INSN_OP(2) | INSN_OP3(0x2f)) +#define ARITH_ADDXC (INSN_OP(2) | INSN_OP3(0x36) | INSN_OPF(0x11)) + #define SHIFT_SLL (INSN_OP(2) | INSN_OP3(0x25)) #define SHIFT_SRL (INSN_OP(2) | INSN_OP3(0x26)) #define SHIFT_SRA (INSN_OP(2) | INSN_OP3(0x27)) @@ -262,6 +264,10 @@ static const int tcg_target_call_oarg_regs[] = { #define STW_LE (STWA | INSN_ASI(ASI_PRIMARY_LITTLE)) #define STX_LE (STXA | INSN_ASI(ASI_PRIMARY_LITTLE)) +#ifndef use_vis3_instructions +bool use_vis3_instructions; +#endif + static inline int check_fit_i64(int64_t val, unsigned int bits) { return val == sextract64(val, 0, bits); @@ -748,11 +754,14 @@ static void tcg_out_addsub2_i64(TCGContext *s, TCGReg rl, TCGReg rh, tcg_out_arithc(s, tmp, al, bl, blconst, is_sub ? ARITH_SUBCC : ARITH_ADDCC); - /* Note that ADDX/SUBX take the carry-in from %icc, the 32-bit carry, - while we want %xcc, the 64-bit carry. */ - /* ??? There is a 2011 VIS3 ADDXC insn that does take a 64-bit carry. */ - - if (bh == TCG_REG_G0) { + if (use_vis3_instructions && !is_sub) { + /* Note that ADDXC doesn't accept immediates. */ + if (bhconst && bh != 0) { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_T2, bh); + bh = TCG_REG_T2; + } + tcg_out_arith(s, rh, ah, bh, ARITH_ADDXC); + } else if (bh == TCG_REG_G0) { /* If we have a zero, we can perform the operation in two insns, with the arithmetic first, and a conditional move into place. */ if (rh == ah) { @@ -1517,6 +1526,15 @@ static const TCGTargetOpDef sparc_op_defs[] = { static void tcg_target_init(TCGContext *s) { + /* Only probe for the platform and capabilities if we havn't already + determined maximum values at compile time. */ +#ifndef use_vis3_instructions + { + unsigned long hwcap = qemu_getauxval(AT_HWCAP); + use_vis3_instructions = (hwcap & HWCAP_SPARC_VIS3) != 0; + } +#endif + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, ALL_64); diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index a44d34f..099b308 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -85,6 +85,12 @@ typedef enum { #define TCG_TARGET_EXTEND_ARGS 1 #endif +#if defined(__VIS__) && __VIS__ >= 0x300 +#define use_vis3_instructions 1 +#else +extern bool use_vis3_instructions; +#endif + /* optional instructions */ #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 0 -- 1.9.3