qemu-devel
[Top][All Lists]
Advanced

[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   */





reply via email to

[Prev in Thread] Current Thread [Next in Thread]