diff options
-rw-r--r-- | linux-user/syscall.c | 2 | ||||
-rw-r--r-- | target-sparc/translate.c | 9 | ||||
-rw-r--r-- | tcg/hppa/tcg-target.c | 437 | ||||
-rw-r--r-- | tcg/hppa/tcg-target.h | 10 |
4 files changed, 223 insertions, 235 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 26c0fb4dc6..eb77ade9e7 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4021,7 +4021,7 @@ static inline abi_long host_to_target_stat64(void *cpu_env, } else #endif { -#if (TARGET_LONG_BITS == 64) && (!defined(TARGET_ALPHA)) +#if TARGET_ABI_BITS == 64 && !defined(TARGET_ALPHA) struct target_stat *target_st; #else struct target_stat64 *target_st; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index b54c520855..be2a116d8d 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -79,6 +79,7 @@ typedef struct DisasContext { int mem_idx; int fpu_enabled; int address_mask_32bit; + int singlestep; uint32_t cc_op; /* current CC operation */ struct TranslationBlock *tb; sparc_def_t *def; @@ -234,7 +235,8 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, tb = s->tb; if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) && - (npc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK)) { + (npc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) && + !s->singlestep) { /* jump to same page: we can use a direct jump */ tcg_gen_goto_tb(tb_num); tcg_gen_movi_tl(cpu_pc, pc); @@ -4694,6 +4696,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, #ifdef TARGET_SPARC64 dc->address_mask_32bit = env->pstate & PS_AM; #endif + dc->singlestep = (env->singlestep_enabled || singlestep); gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; cpu_tmp0 = tcg_temp_new(); @@ -4754,9 +4757,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, break; /* if single step mode, we generate only one instruction and generate an exception */ - if (env->singlestep_enabled || singlestep) { - tcg_gen_movi_tl(cpu_pc, dc->pc); - tcg_gen_exit_tb(0); + if (dc->singlestep) { break; } } while ((gen_opc_ptr < gen_opc_end) && diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index daddaab71d..cb605f1061 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -34,10 +34,6 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { /* This is an 8 byte temp slot in the stack frame. */ #define STACK_TEMP_OFS -16 -#ifndef GUEST_BASE -#define GUEST_BASE 0 -#endif - #ifdef CONFIG_USE_GUEST_BASE #define TCG_GUEST_BASE_REG TCG_REG_R16 #else @@ -97,6 +93,9 @@ static inline int check_fit_tl(tcg_target_long val, unsigned int bits) Copied from gcc sources. */ static inline int or_mask_p(tcg_target_ulong mask) { + if (mask == 0 || mask == -1) { + return 0; + } mask += mask & -mask; return (mask & (mask - 1)) == 0; } @@ -213,6 +212,12 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) case 'K': ct->ct |= TCG_CT_CONST_MS11; break; + case 'M': + ct->ct |= TCG_CT_CONST_AND; + break; + case 'O': + ct->ct |= TCG_CT_CONST_OR; + break; default: return -1; } @@ -236,6 +241,10 @@ static int tcg_target_const_match(tcg_target_long val, return check_fit_tl(val, 11); } else if (ct & TCG_CT_CONST_MS11) { return check_fit_tl(-val, 11); + } else if (ct & TCG_CT_CONST_AND) { + return and_mask_p(val); + } else if (ct & TCG_CT_CONST_OR) { + return or_mask_p(val); } return 0; } @@ -474,70 +483,54 @@ static void tcg_out_vshd(TCGContext *s, int ret, int hi, int lo, int creg) static void tcg_out_ori(TCGContext *s, int ret, int arg, tcg_target_ulong m) { - if (m == 0) { - tcg_out_mov(s, ret, arg); - } else if (m == -1) { - tcg_out_movi(s, TCG_TYPE_I32, ret, -1); - } else if (or_mask_p(m)) { - int bs0, bs1; - - for (bs0 = 0; bs0 < 32; bs0++) { - if ((m & (1u << bs0)) != 0) { - break; - } + int bs0, bs1; + + /* Note that the argument is constrained to match or_mask_p. */ + for (bs0 = 0; bs0 < 32; bs0++) { + if ((m & (1u << bs0)) != 0) { + break; } - for (bs1 = bs0; bs1 < 32; bs1++) { - if ((m & (1u << bs1)) == 0) { - break; - } + } + for (bs1 = bs0; bs1 < 32; bs1++) { + if ((m & (1u << bs1)) == 0) { + break; } - assert(bs1 == 32 || (1ul << bs1) > m); - - tcg_out_mov(s, ret, arg); - tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(-1) - | INSN_SHDEP_CP(31 - bs0) | INSN_DEP_LEN(bs1 - bs0)); - } else { - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R1, m); - tcg_out_arith(s, ret, arg, TCG_REG_R1, INSN_OR); } + assert(bs1 == 32 || (1ul << bs1) > m); + + tcg_out_mov(s, ret, arg); + tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(-1) + | INSN_SHDEP_CP(31 - bs0) | INSN_DEP_LEN(bs1 - bs0)); } static void tcg_out_andi(TCGContext *s, int ret, int arg, tcg_target_ulong m) { - if (m == 0) { - tcg_out_mov(s, ret, TCG_REG_R0); - } else if (m == -1) { - tcg_out_mov(s, ret, arg); - } else if (and_mask_p(m)) { - int ls0, ls1, ms0; + int ls0, ls1, ms0; - for (ls0 = 0; ls0 < 32; ls0++) { - if ((m & (1u << ls0)) == 0) { - break; - } + /* Note that the argument is constrained to match and_mask_p. */ + for (ls0 = 0; ls0 < 32; ls0++) { + if ((m & (1u << ls0)) == 0) { + break; } - for (ls1 = ls0; ls1 < 32; ls1++) { - if ((m & (1u << ls1)) != 0) { - break; - } + } + for (ls1 = ls0; ls1 < 32; ls1++) { + if ((m & (1u << ls1)) != 0) { + break; } - for (ms0 = ls1; ms0 < 32; ms0++) { - if ((m & (1u << ms0)) == 0) { - break; - } + } + for (ms0 = ls1; ms0 < 32; ms0++) { + if ((m & (1u << ms0)) == 0) { + break; } - assert (ms0 == 32); + } + assert (ms0 == 32); - if (ls1 == 32) { - tcg_out_extr(s, ret, arg, 0, ls0, 0); - } else { - tcg_out_mov(s, ret, arg); - tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(0) - | INSN_SHDEP_CP(31 - ls0) | INSN_DEP_LEN(ls1 - ls0)); - } + if (ls1 == 32) { + tcg_out_extr(s, ret, arg, 0, ls0, 0); } else { - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R1, m); - tcg_out_arith(s, ret, arg, TCG_REG_R1, INSN_AND); + tcg_out_mov(s, ret, arg); + tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(0) + | INSN_SHDEP_CP(31 - ls0) | INSN_DEP_LEN(ls1 - ls0)); } } @@ -730,8 +723,11 @@ static void tcg_out_branch(TCGContext *s, int label_index, int nul) tcg_out32(s, op | reassemble_17(val)); } else { + /* We need to keep the offset unchanged for retranslation. */ + uint32_t old_insn = *(uint32_t *)s->code_ptr; + tcg_out_reloc(s, s->code_ptr, R_PARISC_PCREL17F, label_index, 0); - tcg_out32(s, op); + tcg_out32(s, op | (old_insn & 0x1f1ffdu)); } } @@ -784,11 +780,14 @@ static void tcg_out_brcond(TCGContext *s, int cond, TCGArg c1, tcg_out32(s, op | reassemble_12(val)); tcg_out_nop(s); } else { + /* We need to keep the offset unchanged for retranslation. */ + uint32_t old_insn = *(uint32_t *)s->code_ptr; + tcg_out_reloc(s, s->code_ptr, R_PARISC_PCREL12F, label_index, 0); /* ??? Assume that all branches to undefined labels are forward. Which means that if the nul bit is set, the delay slot is not executed if the branch is taken, which is what we want. */ - tcg_out32(s, op | 2); + tcg_out32(s, op | 2 | (old_insn & 0x1ffdu)); } } @@ -911,7 +910,6 @@ static int tcg_out_tlb_read(TCGContext *s, int r0, int r1, int addrlo, CPU_TLB_ENTRY_BITS is > 3, so we can't merge that shift with the add that follows. */ tcg_out_extr(s, r1, addrlo, TARGET_PAGE_BITS, CPU_TLB_BITS, 0); - tcg_out_andi(s, r0, addrlo, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); tcg_out_shli(s, r1, r1, CPU_TLB_ENTRY_BITS); tcg_out_arith(s, r1, r1, TCG_AREG0, INSN_ADDL); @@ -934,6 +932,12 @@ static int tcg_out_tlb_read(TCGContext *s, int r0, int r1, int addrlo, tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, r1, offset); } + /* Compute the value that ought to appear in the TLB for a hit, namely, the page + of the address. We include the low N bits of the address to catch unaligned + accesses and force them onto the slow path. Do this computation after having + issued the load from the TLB slot to give the load time to complete. */ + tcg_out_andi(s, r0, addrlo, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + /* If not equal, jump to lab_miss. */ if (TARGET_LONG_BITS == 64) { tcg_out_brcond2(s, TCG_COND_NE, TCG_REG_R20, TCG_REG_R23, @@ -946,108 +950,97 @@ static int tcg_out_tlb_read(TCGContext *s, int r0, int r1, int addrlo, } #endif -static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) +static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo_reg, int datahi_reg, + int addr_reg, int addend_reg, int opc) { - int addr_reg, addr_reg2; - int data_reg, data_reg2; - int r0, r1, mem_index, s_bits, bswap; - tcg_target_long offset; -#if defined(CONFIG_SOFTMMU) - int lab1, lab2, argreg; -#endif - - data_reg = *args++; - data_reg2 = (opc == 3 ? *args++ : TCG_REG_R0); - addr_reg = *args++; - addr_reg2 = (TARGET_LONG_BITS == 64 ? *args++ : TCG_REG_R0); - mem_index = *args; - s_bits = opc & 3; - - r0 = TCG_REG_R26; - r1 = TCG_REG_R25; - -#if defined(CONFIG_SOFTMMU) - lab1 = gen_new_label(); - lab2 = gen_new_label(); - - offset = tcg_out_tlb_read(s, r0, r1, addr_reg, addr_reg2, s_bits, lab1, - offsetof(CPUState, - tlb_table[mem_index][0].addr_read)); - - /* TLB Hit. */ - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : r1), - offsetof(CPUState, tlb_table[mem_index][0].addend) - offset); - - tcg_out_arith(s, r0, addr_reg, TCG_REG_R20, INSN_ADDL); - offset = TCG_REG_R0; -#else - r0 = addr_reg; - offset = GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_R0; -#endif - #ifdef TARGET_WORDS_BIGENDIAN - bswap = 0; + const int bswap = 0; #else - bswap = 1; + const int bswap = 1; #endif + switch (opc) { case 0: - tcg_out_ldst_index(s, data_reg, r0, offset, INSN_LDBX); + tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDBX); break; case 0 | 4: - tcg_out_ldst_index(s, data_reg, r0, offset, INSN_LDBX); - tcg_out_ext8s(s, data_reg, data_reg); + tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDBX); + tcg_out_ext8s(s, datalo_reg, datalo_reg); break; case 1: - tcg_out_ldst_index(s, data_reg, r0, offset, INSN_LDHX); + tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDHX); if (bswap) { - tcg_out_bswap16(s, data_reg, data_reg, 0); + tcg_out_bswap16(s, datalo_reg, datalo_reg, 0); } break; case 1 | 4: - tcg_out_ldst_index(s, data_reg, r0, offset, INSN_LDHX); + tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDHX); if (bswap) { - tcg_out_bswap16(s, data_reg, data_reg, 1); + tcg_out_bswap16(s, datalo_reg, datalo_reg, 1); } else { - tcg_out_ext16s(s, data_reg, data_reg); + tcg_out_ext16s(s, datalo_reg, datalo_reg); } break; case 2: - tcg_out_ldst_index(s, data_reg, r0, offset, INSN_LDWX); + tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDWX); if (bswap) { - tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); + tcg_out_bswap32(s, datalo_reg, datalo_reg, TCG_REG_R20); } break; case 3: if (bswap) { - int t = data_reg2; - data_reg2 = data_reg; - data_reg = t; + int t = datahi_reg; + datahi_reg = datalo_reg; + datalo_reg = t; } - if (offset == TCG_REG_R0) { - /* Make sure not to clobber the base register. */ - if (data_reg2 == r0) { - tcg_out_ldst(s, data_reg, r0, 4, INSN_LDW); - tcg_out_ldst(s, data_reg2, r0, 0, INSN_LDW); - } else { - tcg_out_ldst(s, data_reg2, r0, 0, INSN_LDW); - tcg_out_ldst(s, data_reg, r0, 4, INSN_LDW); - } + /* We can't access the low-part with a reg+reg addressing mode, + so perform the addition now and use reg_ofs addressing mode. */ + if (addend_reg != TCG_REG_R0) { + tcg_out_arith(s, TCG_REG_R20, addr_reg, addend_reg, INSN_ADD); + addr_reg = TCG_REG_R20; + } + /* Make sure not to clobber the base register. */ + if (datahi_reg == addr_reg) { + tcg_out_ldst(s, datalo_reg, addr_reg, 4, INSN_LDW); + tcg_out_ldst(s, datahi_reg, addr_reg, 0, INSN_LDW); } else { - tcg_out_addi2(s, TCG_REG_R20, r0, 4); - tcg_out_ldst_index(s, data_reg2, r0, offset, INSN_LDWX); - tcg_out_ldst_index(s, data_reg, TCG_REG_R20, offset, INSN_LDWX); + tcg_out_ldst(s, datahi_reg, addr_reg, 0, INSN_LDW); + tcg_out_ldst(s, datalo_reg, addr_reg, 4, INSN_LDW); } if (bswap) { - tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20); - tcg_out_bswap32(s, data_reg2, data_reg2, TCG_REG_R20); + tcg_out_bswap32(s, datalo_reg, datalo_reg, TCG_REG_R20); + tcg_out_bswap32(s, datahi_reg, datahi_reg, TCG_REG_R20); } break; default: tcg_abort(); } +} + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) +{ + int datalo_reg = *args++; + /* Note that datahi_reg is only used for 64-bit loads. */ + int datahi_reg = (opc == 3 ? *args++ : TCG_REG_R0); + int addrlo_reg = *args++; #if defined(CONFIG_SOFTMMU) + /* Note that addrhi_reg is only used for 64-bit guests. */ + int addrhi_reg = (TARGET_LONG_BITS == 64 ? *args++ : TCG_REG_R0); + int mem_index = *args; + int lab1, lab2, argreg, offset; + + lab1 = gen_new_label(); + lab2 = gen_new_label(); + + offset = offsetof(CPUState, tlb_table[mem_index][0].addr_read); + offset = tcg_out_tlb_read(s, TCG_REG_R26, TCG_REG_R25, addrlo_reg, addrhi_reg, + opc & 3, lab1, offset); + + /* TLB Hit. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : TCG_REG_R25), + offsetof(CPUState, tlb_table[mem_index][0].addend) - offset); + tcg_out_qemu_ld_direct(s, datalo_reg, datahi_reg, addrlo_reg, TCG_REG_R20, opc); tcg_out_branch(s, lab2, 1); /* TLB Miss. */ @@ -1055,34 +1048,34 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) tcg_out_label(s, lab1, (tcg_target_long)s->code_ptr); argreg = TCG_REG_R26; - tcg_out_mov(s, argreg--, addr_reg); + tcg_out_mov(s, argreg--, addrlo_reg); if (TARGET_LONG_BITS == 64) { - tcg_out_mov(s, argreg--, addr_reg2); + tcg_out_mov(s, argreg--, addrhi_reg); } tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); - tcg_out_call(s, qemu_ld_helpers[s_bits]); + tcg_out_call(s, qemu_ld_helpers[opc & 3]); switch (opc) { case 0: - tcg_out_andi(s, data_reg, TCG_REG_RET0, 0xff); + tcg_out_andi(s, datalo_reg, TCG_REG_RET0, 0xff); break; case 0 | 4: - tcg_out_ext8s(s, data_reg, TCG_REG_RET0); + tcg_out_ext8s(s, datalo_reg, TCG_REG_RET0); break; case 1: - tcg_out_andi(s, data_reg, TCG_REG_RET0, 0xffff); + tcg_out_andi(s, datalo_reg, TCG_REG_RET0, 0xffff); break; case 1 | 4: - tcg_out_ext16s(s, data_reg, TCG_REG_RET0); + tcg_out_ext16s(s, datalo_reg, TCG_REG_RET0); break; case 2: case 2 | 4: - tcg_out_mov(s, data_reg, TCG_REG_RET0); + tcg_out_mov(s, datalo_reg, TCG_REG_RET0); break; case 3: - tcg_out_mov(s, data_reg, TCG_REG_RET0); - tcg_out_mov(s, data_reg2, TCG_REG_RET1); + tcg_out_mov(s, datahi_reg, TCG_REG_RET0); + tcg_out_mov(s, datalo_reg, TCG_REG_RET1); break; default: tcg_abort(); @@ -1090,92 +1083,83 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) /* label2: */ tcg_out_label(s, lab2, (tcg_target_long)s->code_ptr); +#else + tcg_out_qemu_ld_direct(s, datalo_reg, datahi_reg, addrlo_reg, + (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_R0), opc); #endif } -static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) +static void tcg_out_qemu_st_direct(TCGContext *s, int datalo_reg, int datahi_reg, + int addr_reg, int opc) { - int addr_reg, addr_reg2; - int data_reg, data_reg2; - int r0, r1, mem_index, s_bits, bswap; -#if defined(CONFIG_SOFTMMU) - tcg_target_long offset; - int lab1, lab2, argreg; -#endif - - data_reg = *args++; - data_reg2 = (opc == 3 ? *args++ : 0); - addr_reg = *args++; - addr_reg2 = (TARGET_LONG_BITS == 64 ? *args++ : 0); - mem_index = *args; - s_bits = opc; - - r0 = TCG_REG_R26; - r1 = TCG_REG_R25; - -#if defined(CONFIG_SOFTMMU) - lab1 = gen_new_label(); - lab2 = gen_new_label(); - - offset = tcg_out_tlb_read(s, r0, r1, addr_reg, addr_reg2, s_bits, lab1, - offsetof(CPUState, - tlb_table[mem_index][0].addr_write)); - - /* TLB Hit. */ - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : r1), - offsetof(CPUState, tlb_table[mem_index][0].addend) - offset); - - tcg_out_arith(s, r0, addr_reg, TCG_REG_R20, INSN_ADDL); -#else - /* There are no indexed stores, so if GUEST_BASE is set - we must do the add explicitly. Careful to avoid R20, - which is used for the bswaps to follow. */ - if (GUEST_BASE == 0) { - r0 = addr_reg; - } else { - tcg_out_arith(s, TCG_REG_R31, addr_reg, TCG_GUEST_BASE_REG, INSN_ADDL); - r0 = TCG_REG_R31; - } -#endif - #ifdef TARGET_WORDS_BIGENDIAN - bswap = 0; + const int bswap = 0; #else - bswap = 1; + const int bswap = 1; #endif + switch (opc) { case 0: - tcg_out_ldst(s, data_reg, r0, 0, INSN_STB); + tcg_out_ldst(s, datalo_reg, addr_reg, 0, INSN_STB); break; case 1: if (bswap) { - tcg_out_bswap16(s, TCG_REG_R20, data_reg, 0); - data_reg = TCG_REG_R20; + tcg_out_bswap16(s, TCG_REG_R20, datalo_reg, 0); + datalo_reg = TCG_REG_R20; } - tcg_out_ldst(s, data_reg, r0, 0, INSN_STH); + tcg_out_ldst(s, datalo_reg, addr_reg, 0, INSN_STH); break; case 2: if (bswap) { - tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20); - data_reg = TCG_REG_R20; + tcg_out_bswap32(s, TCG_REG_R20, datalo_reg, TCG_REG_R20); + datalo_reg = TCG_REG_R20; } - tcg_out_ldst(s, data_reg, r0, 0, INSN_STW); + tcg_out_ldst(s, datalo_reg, addr_reg, 0, INSN_STW); break; case 3: if (bswap) { - tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20); - tcg_out_bswap32(s, TCG_REG_R23, data_reg2, TCG_REG_R23); - data_reg2 = TCG_REG_R20; - data_reg = TCG_REG_R23; + tcg_out_bswap32(s, TCG_REG_R20, datalo_reg, TCG_REG_R20); + tcg_out_bswap32(s, TCG_REG_R23, datahi_reg, TCG_REG_R23); + datahi_reg = TCG_REG_R20; + datalo_reg = TCG_REG_R23; } - tcg_out_ldst(s, data_reg2, r0, 0, INSN_STW); - tcg_out_ldst(s, data_reg, r0, 4, INSN_STW); + tcg_out_ldst(s, datahi_reg, addr_reg, 0, INSN_STW); + tcg_out_ldst(s, datalo_reg, addr_reg, 4, INSN_STW); break; default: tcg_abort(); } +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) +{ + int datalo_reg = *args++; + /* Note that datahi_reg is only used for 64-bit loads. */ + int datahi_reg = (opc == 3 ? *args++ : TCG_REG_R0); + int addrlo_reg = *args++; + #if defined(CONFIG_SOFTMMU) + /* Note that addrhi_reg is only used for 64-bit guests. */ + int addrhi_reg = (TARGET_LONG_BITS == 64 ? *args++ : TCG_REG_R0); + int mem_index = *args; + int lab1, lab2, argreg, offset; + + lab1 = gen_new_label(); + lab2 = gen_new_label(); + + offset = offsetof(CPUState, tlb_table[mem_index][0].addr_write); + offset = tcg_out_tlb_read(s, TCG_REG_R26, TCG_REG_R25, addrlo_reg, addrhi_reg, + opc, lab1, offset); + + /* TLB Hit. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : TCG_REG_R25), + offsetof(CPUState, tlb_table[mem_index][0].addend) - offset); + + /* There are no indexed stores, so we must do this addition explitly. + Careful to avoid R20, which is used for the bswaps to follow. */ + tcg_out_arith(s, TCG_REG_R31, addrlo_reg, TCG_REG_R20, INSN_ADDL); + tcg_out_qemu_st_direct(s, datalo_reg, datahi_reg, TCG_REG_R31, opc); tcg_out_branch(s, lab2, 1); /* TLB Miss. */ @@ -1183,22 +1167,22 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) tcg_out_label(s, lab1, (tcg_target_long)s->code_ptr); argreg = TCG_REG_R26; - tcg_out_mov(s, argreg--, addr_reg); + tcg_out_mov(s, argreg--, addrlo_reg); if (TARGET_LONG_BITS == 64) { - tcg_out_mov(s, argreg--, addr_reg2); + tcg_out_mov(s, argreg--, addrhi_reg); } switch(opc) { case 0: - tcg_out_andi(s, argreg--, data_reg, 0xff); + tcg_out_andi(s, argreg--, datalo_reg, 0xff); tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); break; case 1: - tcg_out_andi(s, argreg--, data_reg, 0xffff); + tcg_out_andi(s, argreg--, datalo_reg, 0xffff); tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); break; case 2: - tcg_out_mov(s, argreg--, data_reg); + tcg_out_mov(s, argreg--, datalo_reg); tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); break; case 3: @@ -1212,8 +1196,8 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) argreg = TCG_REG_R20; tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); } - tcg_out_mov(s, TCG_REG_R23, data_reg2); - tcg_out_mov(s, TCG_REG_R24, data_reg); + tcg_out_mov(s, TCG_REG_R23, datahi_reg); + tcg_out_mov(s, TCG_REG_R24, datalo_reg); tcg_out_st(s, TCG_TYPE_I32, argreg, TCG_REG_SP, TCG_TARGET_CALL_STACK_OFFSET - 4); break; @@ -1221,10 +1205,18 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) tcg_abort(); } - tcg_out_call(s, qemu_st_helpers[s_bits]); + tcg_out_call(s, qemu_st_helpers[opc]); /* label2: */ tcg_out_label(s, lab2, (tcg_target_long)s->code_ptr); +#else + /* There are no indexed stores, so if GUEST_BASE is set we must do the add + explicitly. Careful to avoid R20, which is used for the bswaps to follow. */ + if (GUEST_BASE != 0) { + tcg_out_arith(s, TCG_REG_R31, addrlo_reg, TCG_GUEST_BASE_REG, INSN_ADDL); + addrlo_reg = TCG_REG_R31; + } + tcg_out_qemu_st_direct(s, datalo_reg, datahi_reg, addrlo_reg, opc); #endif } @@ -1439,19 +1431,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out_ext16s(s, args[0], args[1]); break; - /* These three correspond exactly to the fallback implementation. - But by including them we reduce the number of TCG ops that - need to be generated, and these opcodes are fairly common. */ - case INDEX_op_neg_i32: - tcg_out_arith(s, args[0], TCG_REG_R0, args[1], INSN_SUB); - break; - case INDEX_op_ext8u_i32: - tcg_out_andi(s, args[0], args[1], 0xff); - break; - case INDEX_op_ext16u_i32: - tcg_out_andi(s, args[0], args[1], 0xffff); - break; - case INDEX_op_brcond_i32: tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]); break; @@ -1539,10 +1518,13 @@ static const TCGTargetOpDef hppa_op_defs[] = { { INDEX_op_add_i32, { "r", "rZ", "ri" } }, { INDEX_op_sub_i32, { "r", "rI", "ri" } }, - { INDEX_op_and_i32, { "r", "rZ", "ri" } }, - { INDEX_op_or_i32, { "r", "rZ", "ri" } }, + { INDEX_op_and_i32, { "r", "rZ", "rM" } }, + { INDEX_op_or_i32, { "r", "rZ", "rO" } }, { INDEX_op_xor_i32, { "r", "rZ", "rZ" } }, - { INDEX_op_andc_i32, { "r", "rZ", "ri" } }, + /* Note that the second argument will be inverted, which means + we want a constant whose inversion matches M, and that O = ~M. + See the implementation of and_mask_p. */ + { INDEX_op_andc_i32, { "r", "rZ", "rO" } }, { INDEX_op_mul_i32, { "r", "r", "r" } }, { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, @@ -1555,13 +1537,10 @@ static const TCGTargetOpDef hppa_op_defs[] = { { INDEX_op_bswap16_i32, { "r", "r" } }, { INDEX_op_bswap32_i32, { "r", "r" } }, - { INDEX_op_neg_i32, { "r", "r" } }, { INDEX_op_not_i32, { "r", "r" } }, { INDEX_op_ext8s_i32, { "r", "r" } }, - { INDEX_op_ext8u_i32, { "r", "r" } }, { INDEX_op_ext16s_i32, { "r", "r" } }, - { INDEX_op_ext16u_i32, { "r", "r" } }, { INDEX_op_brcond_i32, { "rZ", "rJ" } }, { INDEX_op_brcond2_i32, { "rZ", "rZ", "rJ", "rJ" } }, @@ -1649,9 +1628,13 @@ void tcg_target_qemu_prologue(TCGContext *s) TCG_REG_SP, -frame_size + i * 4); } - if (GUEST_BASE != 0) { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, GUEST_BASE); - } +#ifdef CONFIG_USE_GUEST_BASE + /* Note that GUEST_BASE can change after the prologue is generated. + To combat that, load the value from the variable instead of + embedding a constant here. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, + TCG_REG_R0, (tcg_target_long)&guest_base); +#endif /* Jump to TB, and adjust R18 to be the return address. */ tcg_out32(s, INSN_BLE_SR4 | INSN_R2(TCG_REG_R26)); @@ -1696,9 +1679,9 @@ void tcg_target_init(TCGContext *s) tcg_regset_set_reg(s->reserved_regs, TCG_REG_DP); /* data pointer */ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R31); /* ble link reg */ - if (GUEST_BASE != 0) { - tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); - } +#ifdef CONFIG_USE_GUEST_BASE + tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); +#endif tcg_add_target_add_op_defs(hppa_op_defs); } diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h index b76e389c38..a5cc440d49 100644 --- a/tcg/hppa/tcg-target.h +++ b/tcg/hppa/tcg-target.h @@ -73,6 +73,8 @@ enum { #define TCG_CT_CONST_S5 0x0200 #define TCG_CT_CONST_S11 0x0400 #define TCG_CT_CONST_MS11 0x0800 +#define TCG_CT_CONST_AND 0x1000 +#define TCG_CT_CONST_OR 0x2000 /* used for function call generation */ #define TCG_REG_CALL_STACK TCG_REG_SP @@ -87,15 +89,17 @@ enum { #define TCG_TARGET_HAS_rot_i32 #define TCG_TARGET_HAS_ext8s_i32 #define TCG_TARGET_HAS_ext16s_i32 -#define TCG_TARGET_HAS_ext8u_i32 -#define TCG_TARGET_HAS_ext16u_i32 #define TCG_TARGET_HAS_bswap16_i32 #define TCG_TARGET_HAS_bswap32_i32 #define TCG_TARGET_HAS_not_i32 -#define TCG_TARGET_HAS_neg_i32 #define TCG_TARGET_HAS_andc_i32 // #define TCG_TARGET_HAS_orc_i32 +/* optional instructions automatically implemented */ +#undef TCG_TARGET_HAS_neg_i32 /* sub rd, 0, rs */ +#undef TCG_TARGET_HAS_ext8u_i32 /* and rd, rs, 0xff */ +#undef TCG_TARGET_HAS_ext16u_i32 /* and rd, rs, 0xffff */ + #define TCG_TARGET_HAS_GUEST_BASE /* Note: must be synced with dyngen-exec.h */ |