[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2 1/2] tcg/mips: detect available host instruct
From: |
li guang |
Subject: |
Re: [Qemu-devel] [PATCH v2 1/2] tcg/mips: detect available host instructions at runtime |
Date: |
Wed, 28 Aug 2013 11:57:33 +0800 |
Hi, Aurelien,
to nitpick,
use_mips32r2_instructions may already indicate
use_mips32_instructions,right?
so during ISA detection, we may first do mips32r2, then mips32
detection is unnecessary, I think.
在 2013-08-28三的 00:11 +0200,Aurelien Jarno写道:
> Now that TCG supports enabling and disabling ops at runtime, it's
> possible to detect the available host instructions at runtime, and
> enable the corresponding ops accordingly.
>
> Unfortunately it's not easy to probe for available instructions on
> MIPS, the information is partially available in /proc/cpuinfo, and
> not available in AUXV. This patch therefore probes for the instructions
> by trying to execute them and by catching a possible SIGILL signal.
>
> Signed-off-by: Aurelien Jarno <address@hidden>
> ---
> tcg/mips/tcg-target.c | 211
> ++++++++++++++++++++++++++++++++-----------------
> tcg/mips/tcg-target.h | 50 +++++++-----
> 2 files changed, 169 insertions(+), 92 deletions(-)
>
> diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
> index 793532e..a994b11 100644
> --- a/tcg/mips/tcg-target.c
> +++ b/tcg/mips/tcg-target.c
> @@ -422,83 +422,83 @@ static inline void tcg_out_movi(TCGContext *s, TCGType
> type,
>
> static inline void tcg_out_bswap16(TCGContext *s, TCGReg ret, TCGReg arg)
> {
> -#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
> - tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg);
> -#else
> - /* ret and arg can't be register at */
> - if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
> - tcg_abort();
> - }
> + if (use_mips32r2_instructions) {
> + tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg);
> + } else {
> + /* ret and arg can't be register at */
> + if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
> + tcg_abort();
> + }
>
> - tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
> - tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8);
> - tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00);
> - tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
> -#endif
> + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
> + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8);
> + tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00);
> + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
> + }
> }
>
> static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg)
> {
> -#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
> - tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg);
> - tcg_out_opc_reg(s, OPC_SEH, ret, 0, ret);
> -#else
> - /* ret and arg can't be register at */
> - if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
> - tcg_abort();
> - }
> + if (use_mips32r2_instructions) {
> + tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg);
> + tcg_out_opc_reg(s, OPC_SEH, ret, 0, ret);
> + } else {
> + /* ret and arg can't be register at */
> + if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
> + tcg_abort();
> + }
>
> - tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
> - tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
> - tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
> - tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
> -#endif
> + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
> + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
> + tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
> + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
> + }
> }
>
> static inline void tcg_out_bswap32(TCGContext *s, TCGReg ret, TCGReg arg)
> {
> -#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
> - tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg);
> - tcg_out_opc_sa(s, OPC_ROTR, ret, ret, 16);
> -#else
> - /* ret and arg must be different and can't be register at */
> - if (ret == arg || ret == TCG_REG_AT || arg == TCG_REG_AT) {
> - tcg_abort();
> - }
> + if (use_mips32r2_instructions) {
> + tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg);
> + tcg_out_opc_sa(s, OPC_ROTR, ret, ret, 16);
> + } else {
> + /* ret and arg must be different and can't be register at */
> + if (ret == arg || ret == TCG_REG_AT || arg == TCG_REG_AT) {
> + tcg_abort();
> + }
>
> - tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
> + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
>
> - tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 24);
> - tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
> + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 24);
> + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
>
> - tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, arg, 0xff00);
> - tcg_out_opc_sa(s, OPC_SLL, TCG_REG_AT, TCG_REG_AT, 8);
> - tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
> + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, arg, 0xff00);
> + tcg_out_opc_sa(s, OPC_SLL, TCG_REG_AT, TCG_REG_AT, 8);
> + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
>
> - tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
> - tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff00);
> - tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
> -#endif
> + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
> + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff00);
> + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
> + }
> }
>
> static inline void tcg_out_ext8s(TCGContext *s, TCGReg ret, TCGReg arg)
> {
> -#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
> - tcg_out_opc_reg(s, OPC_SEB, ret, 0, arg);
> -#else
> - tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
> - tcg_out_opc_sa(s, OPC_SRA, ret, ret, 24);
> -#endif
> + if (use_mips32r2_instructions) {
> + tcg_out_opc_reg(s, OPC_SEB, ret, 0, arg);
> + } else {
> + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
> + tcg_out_opc_sa(s, OPC_SRA, ret, ret, 24);
> + }
> }
>
> static inline void tcg_out_ext16s(TCGContext *s, TCGReg ret, TCGReg arg)
> {
> -#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
> - tcg_out_opc_reg(s, OPC_SEH, ret, 0, arg);
> -#else
> - tcg_out_opc_sa(s, OPC_SLL, ret, arg, 16);
> - tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
> -#endif
> + if (use_mips32r2_instructions) {
> + tcg_out_opc_reg(s, OPC_SEH, ret, 0, arg);
> + } else {
> + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 16);
> + tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
> + }
> }
>
> static inline void tcg_out_ldst(TCGContext *s, int opc, TCGArg arg,
> @@ -1406,12 +1406,12 @@ static inline void tcg_out_op(TCGContext *s,
> TCGOpcode opc,
> tcg_out_mov(s, TCG_TYPE_I32, args[0], TCG_REG_AT);
> break;
> case INDEX_op_mul_i32:
> -#if defined(__mips_isa_rev) && (__mips_isa_rev >= 1)
> - tcg_out_opc_reg(s, OPC_MUL, args[0], args[1], args[2]);
> -#else
> - tcg_out_opc_reg(s, OPC_MULT, 0, args[1], args[2]);
> - tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
> -#endif
> + if (use_mips32_instructions) {
> + tcg_out_opc_reg(s, OPC_MUL, args[0], args[1], args[2]);
> + } else {
> + tcg_out_opc_reg(s, OPC_MULT, 0, args[1], args[2]);
> + tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
> + }
> break;
> case INDEX_op_muls2_i32:
> tcg_out_opc_reg(s, OPC_MULT, 0, args[2], args[3]);
> @@ -1617,29 +1617,19 @@ static const TCGTargetOpDef mips_op_defs[] = {
> { INDEX_op_shl_i32, { "r", "rZ", "ri" } },
> { INDEX_op_shr_i32, { "r", "rZ", "ri" } },
> { INDEX_op_sar_i32, { "r", "rZ", "ri" } },
> -#if TCG_TARGET_HAS_rot_i32
> { INDEX_op_rotr_i32, { "r", "rZ", "ri" } },
> { INDEX_op_rotl_i32, { "r", "rZ", "ri" } },
> -#endif
>
> -#if TCG_TARGET_HAS_bswap16_i32
> { INDEX_op_bswap16_i32, { "r", "r" } },
> -#endif
> -#if TCG_TARGET_HAS_bswap32_i32
> { INDEX_op_bswap32_i32, { "r", "r" } },
> -#endif
>
> { INDEX_op_ext8s_i32, { "r", "rZ" } },
> { INDEX_op_ext16s_i32, { "r", "rZ" } },
>
> -#if TCG_TARGET_HAS_deposit_i32
> { INDEX_op_deposit_i32, { "r", "0", "rZ" } },
> -#endif
>
> { INDEX_op_brcond_i32, { "rZ", "rZ" } },
> -#if TCG_TARGET_HAS_movcond_i32
> { INDEX_op_movcond_i32, { "r", "rZ", "rZ", "rZ", "0" } },
> -#endif
> { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } },
> { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } },
>
> @@ -1688,6 +1678,84 @@ static int tcg_target_callee_save_regs[] = {
> TCG_REG_RA, /* should be last for ABI compliance */
> };
>
> +/* The Linux kernel doesn't provide any information about the available
> + instruction set. Probe it using a signal handler. */
> +
> +#include <signal.h>
> +
> +#ifndef use_movnz_instructions
> +bool use_movnz_instructions;
> +#endif
> +
> +#ifndef use_mips32_instructions
> +bool use_mips32_instructions;
> +#endif
> +
> +#ifndef use_mips32r2_instructions
> +bool use_mips32r2_instructions;
> +#endif
> +
> +static volatile sig_atomic_t got_sigill;
> +
> +static void sigill_handler(int signo, siginfo_t *si, void *data)
> +{
> + /* Skip the faulty instruction */
> + ucontext_t *uc = (ucontext_t *)data;
> + uc->uc_mcontext.pc += 4;
> +
> + got_sigill = 1;
> +}
> +
> +static void tcg_target_detect_isa(void)
> +{
> + struct sigaction sa_old, sa_new;
> +
> + memset(&sa_new, 0, sizeof(sa_new));
> + sa_new.sa_flags = SA_SIGINFO;
> + sa_new.sa_sigaction = sigill_handler;
> + sigaction(SIGILL, &sa_new, &sa_old);
> +
> + /* Probe for movn/movz, necessary to implement movcond. */
> +#ifndef use_movnz_instructions
> + got_sigill = 0;
> + asm volatile(".set push\n"
> + ".set mips32\n"
> + "movn $zero, $zero, $zero\n"
> + "movz $zero, $zero, $zero\n"
> + ".set pop\n"
> + : : : );
> + use_movnz_instructions = !got_sigill;
> +#endif
> +
> + /* Probe for MIPS32 instructions. As no subsetting is allowed
> + by the specification, it is only necessary to probe for one
> + of the instructions. */
> +#ifndef use_mips32_instructions
> + got_sigill = 0;
> + asm volatile(".set push\n"
> + ".set mips32\n"
> + "mul $zero, $zero\n"
> + ".set pop\n"
> + : : : );
> + use_mips32_instructions = !got_sigill;
> +#endif
> +
> + /* Probe for MIPS32r2 instructions. As no subsetting is allowed
> + by the specification, it is only necessary to probe for one
> + of the instructions. */
> +#ifndef use_mips32r2_instructions
> + got_sigill = 0;
> + asm volatile(".set push\n"
> + ".set mips32r2\n"
> + "seb $zero, $zero\n"
> + ".set pop\n"
> + : : : );
> + use_mips32r2_instructions = !got_sigill;
> +#endif
> +
> + sigaction(SIGILL, &sa_old, NULL);
> +}
> +
> /* Generate global QEMU prologue and epilogue code */
> static void tcg_target_qemu_prologue(TCGContext *s)
> {
> @@ -1727,6 +1795,7 @@ static void tcg_target_qemu_prologue(TCGContext *s)
>
> static void tcg_target_init(TCGContext *s)
> {
> + tcg_target_detect_isa();
> tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I32], 0xffffffff);
> tcg_regset_set(tcg_target_call_clobber_regs,
> (1 << TCG_REG_V0) |
> diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
> index a438950..43072e3 100644
> --- a/tcg/mips/tcg-target.h
> +++ b/tcg/mips/tcg-target.h
> @@ -77,6 +77,29 @@ typedef enum {
> #define TCG_TARGET_CALL_STACK_OFFSET 16
> #define TCG_TARGET_CALL_ALIGN_ARGS 1
>
> +/* MOVN/MOVZ instructions detection */
> +#if (defined(__mips_isa_rev) && (__mips_isa_rev >= 1)) || \
> + defined(_MIPS_ARCH_LOONGSON2E) || defined(_MIPS_ARCH_LOONGSON2F) || \
> + defined(_MIPS_ARCH_MIPS4)
> +#define use_movnz_instructions 1
> +#else
> +extern bool use_movnz_instructions;
> +#endif
> +
> +/* MIPS32 instruction set detection */
> +#if defined(__mips_isa_rev) && (__mips_isa_rev >= 1)
> +#define use_mips32_instructions 1
> +#else
> +extern bool use_mips32_instructions;
> +#endif
> +
> +/* MIPS32R2 instruction set detection */
> +#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
> +#define use_mips32r2_instructions 1
> +#else
> +extern bool use_mips32r2_instructions;
> +#endif
> +
> /* optional instructions */
> #define TCG_TARGET_HAS_div_i32 1
> #define TCG_TARGET_HAS_rem_i32 1
> @@ -90,27 +113,12 @@ typedef enum {
> #define TCG_TARGET_HAS_nand_i32 0
> #define TCG_TARGET_HAS_muls2_i32 1
>
> -/* optional instructions only implemented on MIPS4, MIPS32 and Loongson 2 */
> -#if (defined(__mips_isa_rev) && (__mips_isa_rev >= 1)) || \
> - defined(_MIPS_ARCH_LOONGSON2E) || defined(_MIPS_ARCH_LOONGSON2F) || \
> - defined(_MIPS_ARCH_MIPS4)
> -#define TCG_TARGET_HAS_movcond_i32 1
> -#else
> -#define TCG_TARGET_HAS_movcond_i32 0
> -#endif
> -
> -/* optional instructions only implemented on MIPS32R2 */
> -#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
> -#define TCG_TARGET_HAS_bswap16_i32 1
> -#define TCG_TARGET_HAS_bswap32_i32 1
> -#define TCG_TARGET_HAS_rot_i32 1
> -#define TCG_TARGET_HAS_deposit_i32 1
> -#else
> -#define TCG_TARGET_HAS_bswap16_i32 0
> -#define TCG_TARGET_HAS_bswap32_i32 0
> -#define TCG_TARGET_HAS_rot_i32 0
> -#define TCG_TARGET_HAS_deposit_i32 0
> -#endif
> +/* optional instructions detected at runtime */
> +#define TCG_TARGET_HAS_movcond_i32 use_movnz_instructions
> +#define TCG_TARGET_HAS_bswap16_i32 use_mips32r2_instructions
> +#define TCG_TARGET_HAS_bswap32_i32 use_mips32r2_instructions
> +#define TCG_TARGET_HAS_deposit_i32 use_mips32r2_instructions
> +#define TCG_TARGET_HAS_rot_i32 use_mips32r2_instructions
>
> /* optional instructions automatically implemented */
> #define TCG_TARGET_HAS_neg_i32 0 /* sub rd, zero, rt */