[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 04/11] target/arm: Introduce add_reg_for_lit
From: |
Philippe Mathieu-Daudé |
Subject: |
Re: [Qemu-devel] [PATCH 04/11] target/arm: Introduce add_reg_for_lit |
Date: |
Thu, 8 Aug 2019 07:43:24 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.7.0 |
On 8/7/19 6:53 AM, Richard Henderson wrote:
> Provide a common routine for the places that require ALIGN(PC, 4)
> as the base address as opposed to plain PC. The two are always
> the same for A32, but the difference is meaningful for thumb mode.
>
> Signed-off-by: Richard Henderson <address@hidden>
> ---
> Note: This patch is easier to read with -b, as there are several
> large-ish indentation changes as the if statements fold together.
> ---
> target/arm/translate-vfp.inc.c | 38 ++------
> target/arm/translate.c | 166 +++++++++++++++------------------
> 2 files changed, 82 insertions(+), 122 deletions(-)
>
> diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c
> index 092eb5ec53..262d4177e5 100644
> --- a/target/arm/translate-vfp.inc.c
> +++ b/target/arm/translate-vfp.inc.c
> @@ -941,14 +941,8 @@ static bool trans_VLDR_VSTR_sp(DisasContext *s,
> arg_VLDR_VSTR_sp *a)
> offset = -offset;
> }
>
> - if (s->thumb && a->rn == 15) {
> - /* This is actually UNPREDICTABLE */
> - addr = tcg_temp_new_i32();
> - tcg_gen_movi_i32(addr, s->pc & ~2);
> - } else {
> - addr = load_reg(s, a->rn);
> - }
> - tcg_gen_addi_i32(addr, addr, offset);
> + /* For thumb, use of PC is UNPREDICTABLE. */
> + addr = add_reg_for_lit(s, a->rn, offset);
> tmp = tcg_temp_new_i32();
> if (a->l) {
> gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
> @@ -983,14 +977,8 @@ static bool trans_VLDR_VSTR_dp(DisasContext *s,
> arg_VLDR_VSTR_dp *a)
> offset = -offset;
> }
>
> - if (s->thumb && a->rn == 15) {
> - /* This is actually UNPREDICTABLE */
> - addr = tcg_temp_new_i32();
> - tcg_gen_movi_i32(addr, s->pc & ~2);
> - } else {
> - addr = load_reg(s, a->rn);
> - }
> - tcg_gen_addi_i32(addr, addr, offset);
> + /* For thumb, use of PC is UNPREDICTABLE. */
> + addr = add_reg_for_lit(s, a->rn, offset);
> tmp = tcg_temp_new_i64();
> if (a->l) {
> gen_aa32_ld64(s, tmp, addr, get_mem_index(s));
> @@ -1029,13 +1017,8 @@ static bool trans_VLDM_VSTM_sp(DisasContext *s,
> arg_VLDM_VSTM_sp *a)
> return true;
> }
>
> - if (s->thumb && a->rn == 15) {
> - /* This is actually UNPREDICTABLE */
> - addr = tcg_temp_new_i32();
> - tcg_gen_movi_i32(addr, s->pc & ~2);
> - } else {
> - addr = load_reg(s, a->rn);
> - }
> + /* For thumb, use of PC is UNPREDICTABLE. */
> + addr = add_reg_for_lit(s, a->rn, 0);
> if (a->p) {
> /* pre-decrement */
> tcg_gen_addi_i32(addr, addr, -(a->imm << 2));
> @@ -1112,13 +1095,8 @@ static bool trans_VLDM_VSTM_dp(DisasContext *s,
> arg_VLDM_VSTM_dp *a)
> return true;
> }
>
> - if (s->thumb && a->rn == 15) {
> - /* This is actually UNPREDICTABLE */
> - addr = tcg_temp_new_i32();
> - tcg_gen_movi_i32(addr, s->pc & ~2);
> - } else {
> - addr = load_reg(s, a->rn);
> - }
> + /* For thumb, use of PC is UNPREDICTABLE. */
> + addr = add_reg_for_lit(s, a->rn, 0);
> if (a->p) {
> /* pre-decrement */
> tcg_gen_addi_i32(addr, addr, -(a->imm << 2));
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index 61933865d5..71d94c053b 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -220,6 +220,23 @@ static inline TCGv_i32 load_reg(DisasContext *s, int reg)
> return tmp;
> }
>
> +/*
> + * Create a new temp, REG + OFS, except PC is ALIGN(PC, 4).
> + * This is used for load/store for which use of PC implies (literal),
> + * or ADD that implies ADR.
> + */
> +static TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs)
> +{
> + TCGv_i32 tmp = tcg_temp_new_i32();
> +
> + if (reg == 15) {
> + tcg_gen_movi_i32(tmp, (read_pc(s) & ~3) + ofs);
> + } else {
> + tcg_gen_addi_i32(tmp, cpu_R[reg], ofs);
> + }
> + return tmp;
> +}
> +
> /* Set a CPU register. The source must be a temporary and will be
> marked as dead. */
> static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
> @@ -9472,16 +9489,12 @@ static void disas_thumb2_insn(DisasContext *s,
> uint32_t insn)
> */
> bool wback = extract32(insn, 21, 1);
>
> - if (rn == 15) {
> - if (insn & (1 << 21)) {
> - /* UNPREDICTABLE */
> - goto illegal_op;
> - }
> - addr = tcg_temp_new_i32();
> - tcg_gen_movi_i32(addr, s->pc & ~3);
> - } else {
> - addr = load_reg(s, rn);
> + if (rn == 15 && (insn & (1 << 21))) {
> + /* UNPREDICTABLE */
> + goto illegal_op;
> }
> +
> + addr = add_reg_for_lit(s, rn, 0);
> offset = (insn & 0xff) * 4;
> if ((insn & (1 << 23)) == 0) {
> offset = -offset;
> @@ -10682,27 +10695,15 @@ static void disas_thumb2_insn(DisasContext *s,
> uint32_t insn)
> store_reg(s, rd, tmp);
> } else {
> /* Add/sub 12-bit immediate. */
> - if (rn == 15) {
> - offset = s->pc & ~(uint32_t)3;
> - if (insn & (1 << 23))
> - offset -= imm;
> - else
> - offset += imm;
> - tmp = tcg_temp_new_i32();
> - tcg_gen_movi_i32(tmp, offset);
> - store_reg(s, rd, tmp);
> + if (insn & (1 << 23)) {
> + imm = -imm;
:)
> + }
> + tmp = add_reg_for_lit(s, rn, imm);
> + if (rn == 13 && rd == 13) {
> + /* ADD SP, SP, imm or SUB SP, SP, imm */
> + store_sp_checked(s, tmp);
> } else {
> - tmp = load_reg(s, rn);
> - if (insn & (1 << 23))
> - tcg_gen_subi_i32(tmp, tmp, imm);
> - else
> - tcg_gen_addi_i32(tmp, tmp, imm);
> - if (rn == 13 && rd == 13) {
> - /* ADD SP, SP, imm or SUB SP, SP, imm */
> - store_sp_checked(s, tmp);
> - } else {
> - store_reg(s, rd, tmp);
> - }
> + store_reg(s, rd, tmp);
> }
> }
> }
> @@ -10816,61 +10817,53 @@ static void disas_thumb2_insn(DisasContext *s,
> uint32_t insn)
> }
> }
> memidx = get_mem_index(s);
> - if (rn == 15) {
> - addr = tcg_temp_new_i32();
> - /* PC relative. */
> - /* s->pc has already been incremented by 4. */
> - imm = s->pc & 0xfffffffc;
> - if (insn & (1 << 23))
> - imm += insn & 0xfff;
> - else
> - imm -= insn & 0xfff;
> - tcg_gen_movi_i32(addr, imm);
> + imm = insn & 0xfff;
> + if (insn & (1 << 23)) {
> + /* PC relative or Positive offset. */
> + addr = add_reg_for_lit(s, rn, imm);
> + } else if (rn == 15) {
> + /* PC relative with negative offset. */
> + addr = add_reg_for_lit(s, rn, -imm);
> } else {
> addr = load_reg(s, rn);
> - if (insn & (1 << 23)) {
> - /* Positive offset. */
> - imm = insn & 0xfff;
> - tcg_gen_addi_i32(addr, addr, imm);
> - } else {
> - imm = insn & 0xff;
> - switch ((insn >> 8) & 0xf) {
> - case 0x0: /* Shifted Register. */
> - shift = (insn >> 4) & 0xf;
> - if (shift > 3) {
> - tcg_temp_free_i32(addr);
> - goto illegal_op;
> - }
> - tmp = load_reg(s, rm);
> - if (shift)
'diff -b' shows me you removed this 'if (shift)' but ...
> - tcg_gen_shli_i32(tmp, tmp, shift);
> - tcg_gen_add_i32(addr, addr, tmp);
> - tcg_temp_free_i32(tmp);
> - break;
> - case 0xc: /* Negative offset. */
> - tcg_gen_addi_i32(addr, addr, -imm);
> - break;
> - case 0xe: /* User privilege. */
> - tcg_gen_addi_i32(addr, addr, imm);
> - memidx = get_a32_user_mem_index(s);
> - break;
> - case 0x9: /* Post-decrement. */
> - imm = -imm;
> - /* Fall through. */
> - case 0xb: /* Post-increment. */
> - postinc = 1;
> - writeback = 1;
> - break;
> - case 0xd: /* Pre-decrement. */
> - imm = -imm;
> - /* Fall through. */
> - case 0xf: /* Pre-increment. */
> - writeback = 1;
> - break;
> - default:
> + imm = insn & 0xff;
> + switch ((insn >> 8) & 0xf) {
> + case 0x0: /* Shifted Register. */
> + shift = (insn >> 4) & 0xf;
> + if (shift > 3) {
> tcg_temp_free_i32(addr);
> goto illegal_op;
> }
> + tmp = load_reg(s, rm);
> + if (shift) {
... I'm seeing it here. Odd.
> + tcg_gen_shli_i32(tmp, tmp, shift);
> + }
> + tcg_gen_add_i32(addr, addr, tmp);
> + tcg_temp_free_i32(tmp);
> + break;
> + case 0xc: /* Negative offset. */
> + tcg_gen_addi_i32(addr, addr, -imm);
> + break;
> + case 0xe: /* User privilege. */
> + tcg_gen_addi_i32(addr, addr, imm);
> + memidx = get_a32_user_mem_index(s);
> + break;
> + case 0x9: /* Post-decrement. */
> + imm = -imm;
> + /* Fall through. */
> + case 0xb: /* Post-increment. */
> + postinc = 1;
> + writeback = 1;
> + break;
> + case 0xd: /* Pre-decrement. */
> + imm = -imm;
> + /* Fall through. */
> + case 0xf: /* Pre-increment. */
> + writeback = 1;
> + break;
> + default:
> + tcg_temp_free_i32(addr);
> + goto illegal_op;
> }
> }
>
> @@ -11066,10 +11059,7 @@ static void disas_thumb_insn(DisasContext *s,
> uint32_t insn)
> if (insn & (1 << 11)) {
> rd = (insn >> 8) & 7;
> /* load pc-relative. Bit 1 of PC is ignored. */
> - val = read_pc(s) + ((insn & 0xff) * 4);
> - val &= ~(uint32_t)2;
> - addr = tcg_temp_new_i32();
> - tcg_gen_movi_i32(addr, val);
> + addr = add_reg_for_lit(s, 15, (insn & 0xff) * 4);
> tmp = tcg_temp_new_i32();
> gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s),
> rd | ISSIs16Bit);
> @@ -11447,16 +11437,8 @@ static void disas_thumb_insn(DisasContext *s,
> uint32_t insn)
> * - Add PC/SP (immediate)
> */
> rd = (insn >> 8) & 7;
> - if (insn & (1 << 11)) {
> - /* SP */
> - tmp = load_reg(s, 13);
> - } else {
> - /* PC. bit 1 is ignored. */
> - tmp = tcg_temp_new_i32();
> - tcg_gen_movi_i32(tmp, read_pc(s) & ~(uint32_t)2);
> - }
> val = (insn & 0xff) * 4;
> - tcg_gen_addi_i32(tmp, tmp, val);
> + tmp = add_reg_for_lit(s, insn & (1 << 11) ? 13 : 15, val);
> store_reg(s, rd, tmp);
> break;
Reviewed-by: Philippe Mathieu-Daudé <address@hidden>
- [Qemu-devel] [PATCH 01/11] target/arm: Pass in pc to thumb_insn_is_16bit, (continued)
[Qemu-devel] [PATCH 05/11] target/arm: Remove redundant s->pc & ~1, Richard Henderson, 2019/08/07
[Qemu-devel] [PATCH 04/11] target/arm: Introduce add_reg_for_lit, Richard Henderson, 2019/08/07
- Re: [Qemu-devel] [PATCH 04/11] target/arm: Introduce add_reg_for_lit,
Philippe Mathieu-Daudé <=
[Qemu-devel] [PATCH 07/11] target/arm: Replace offset with pc in gen_exception_insn, Richard Henderson, 2019/08/07
[Qemu-devel] [PATCH 08/11] target/arm: Replace offset with pc in gen_exception_internal_insn, Richard Henderson, 2019/08/07
[Qemu-devel] [PATCH 09/11] target/arm: Remove offset argument to gen_exception_bkpt_insn, Richard Henderson, 2019/08/07
[Qemu-devel] [PATCH 10/11] target/arm: Use unallocated_encoding for aarch32, Richard Henderson, 2019/08/07
[Qemu-devel] [PATCH 11/11] target/arm: Remove helper_double_saturate, Richard Henderson, 2019/08/07
[Qemu-devel] [PATCH 06/11] target/arm: Replace s->pc with s->base.pc_next, Richard Henderson, 2019/08/07
Re: [Qemu-devel] [PATCH 00/11] target/arm: decodetree prep patches, Peter Maydell, 2019/08/07