diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2021-08-12 13:31:13 -1000 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2021-09-14 12:00:21 -0700 |
commit | b87c1add03232889d5a464ef29f1d8f1ad2ebe9b (patch) | |
tree | 012559823e9bbb5b1a611cdb3abbf07339dedbe5 /tcg/arm | |
parent | 4ae82ca7eb3913a575646dacdc0d151723e54d1d (diff) |
tcg/arm: Support armv4t in tcg_out_goto and tcg_out_call
ARMv4T has BX as its only interworking instruction. In order
to support testing of different architecture revisions with a
qemu binary that may have been built for, say ARMv6T2, fill in
the blank required to make calls to helpers in thumb mode.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'tcg/arm')
-rw-r--r-- | tcg/arm/tcg-target.c.inc | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 7d15c36f85..852100bb80 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1211,7 +1211,8 @@ static inline void tcg_out_st8(TCGContext *s, int cond, tcg_out_st8_12(s, cond, rd, rn, offset); } -/* The _goto case is normally between TBs within the same code buffer, and +/* + * The _goto case is normally between TBs within the same code buffer, and * with the code buffer limited to 16MB we wouldn't need the long case. * But we also use it for the tail-call to the qemu_ld/st helpers, which does. */ @@ -1219,38 +1220,56 @@ static void tcg_out_goto(TCGContext *s, int cond, const tcg_insn_unit *addr) { intptr_t addri = (intptr_t)addr; ptrdiff_t disp = tcg_pcrel_diff(s, addr); + bool arm_mode = !(addri & 1); - if ((addri & 1) == 0 && disp - 8 < 0x01fffffd && disp - 8 > -0x01fffffd) { + if (arm_mode && disp - 8 < 0x01fffffd && disp - 8 > -0x01fffffd) { tcg_out_b_imm(s, cond, disp); return; } - tcg_out_movi_pool(s, cond, TCG_REG_PC, addri); + + /* LDR is interworking from v5t. */ + if (arm_mode || use_armv5t_instructions) { + tcg_out_movi_pool(s, cond, TCG_REG_PC, addri); + return; + } + + /* else v4t */ + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addri); + tcg_out_bx_reg(s, COND_AL, TCG_REG_TMP); } -/* The call case is mostly used for helpers - so it's not unreasonable - * for them to be beyond branch range */ +/* + * The call case is mostly used for helpers - so it's not unreasonable + * for them to be beyond branch range. + */ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr) { intptr_t addri = (intptr_t)addr; ptrdiff_t disp = tcg_pcrel_diff(s, addr); + bool arm_mode = !(addri & 1); if (disp - 8 < 0x02000000 && disp - 8 >= -0x02000000) { - if (addri & 1) { - /* Use BLX if the target is in Thumb mode */ - if (!use_armv5t_instructions) { - tcg_abort(); - } - tcg_out_blx_imm(s, disp); - } else { + if (arm_mode) { tcg_out_bl_imm(s, COND_AL, disp); + return; } - } else if (use_armv7_instructions) { + if (use_armv5t_instructions) { + tcg_out_blx_imm(s, disp); + return; + } + } + + if (use_armv5t_instructions) { tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addri); tcg_out_blx_reg(s, COND_AL, TCG_REG_TMP); - } else { + } else if (arm_mode) { /* ??? Know that movi_pool emits exactly 1 insn. */ - tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R14, TCG_REG_PC, 0); + tcg_out_mov_reg(s, COND_AL, TCG_REG_R14, TCG_REG_PC); tcg_out_movi_pool(s, COND_AL, TCG_REG_PC, addri); + } else { + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addri); + tcg_out_mov_reg(s, COND_AL, TCG_REG_R14, TCG_REG_PC); + tcg_out_bx_reg(s, COND_AL, TCG_REG_TMP); } } |