summaryrefslogtreecommitdiff
path: root/tcg/arm
diff options
context:
space:
mode:
Diffstat (limited to 'tcg/arm')
-rw-r--r--tcg/arm/tcg-target.c35
1 files changed, 26 insertions, 9 deletions
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 918e2f73cb..fb858d8634 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -375,6 +375,12 @@ static inline void tcg_out_blx(TCGContext *s, int cond, int rn)
tcg_out32(s, (cond << 28) | 0x012fff30 | rn);
}
+static inline void tcg_out_blx_imm(TCGContext *s, int32_t offset)
+{
+ tcg_out32(s, 0xfa000000 | ((offset & 2) << 23) |
+ (((offset - 8) >> 2) & 0x00ffffff));
+}
+
static inline void tcg_out_dat_reg(TCGContext *s,
int cond, int opc, int rd, int rn, int rm, int shift)
{
@@ -840,6 +846,11 @@ static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr)
{
int32_t val;
+ if (addr & 1) {
+ /* goto to a Thumb destination isn't supported */
+ tcg_abort();
+ }
+
val = addr - (tcg_target_long) s->code_ptr;
if (val - 8 < 0x01fffffd && val - 8 > -0x01fffffd)
tcg_out_b(s, cond, val);
@@ -860,14 +871,22 @@ static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr)
}
}
-static inline void tcg_out_call(TCGContext *s, int cond, uint32_t addr)
+static inline void tcg_out_call(TCGContext *s, uint32_t addr)
{
int32_t val;
val = addr - (tcg_target_long) s->code_ptr;
- if (val < 0x01fffffd && val > -0x01fffffd)
- tcg_out_bl(s, cond, val);
- else {
+ if (val - 8 < 0x02000000 && val - 8 >= -0x02000000) {
+ if (addr & 1) {
+ /* Use BLX if the target is in Thumb mode */
+ if (!use_armv5_instructions) {
+ tcg_abort();
+ }
+ tcg_out_blx_imm(s, val);
+ } else {
+ tcg_out_bl(s, COND_AL, val);
+ }
+ } else {
#if 1
tcg_abort();
#else
@@ -1063,8 +1082,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
# endif
- tcg_out_bl(s, COND_AL, (tcg_target_long) qemu_ld_helpers[s_bits] -
- (tcg_target_long) s->code_ptr);
+ tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]);
switch (opc) {
case 0 | 4:
@@ -1330,8 +1348,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
}
# endif
- tcg_out_bl(s, COND_AL, (tcg_target_long) qemu_st_helpers[s_bits] -
- (tcg_target_long) s->code_ptr);
+ tcg_out_call(s, (tcg_target_long) qemu_st_helpers[s_bits]);
if (opc == 3)
tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
@@ -1443,7 +1460,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
break;
case INDEX_op_call:
if (const_args[0])
- tcg_out_call(s, COND_AL, args[0]);
+ tcg_out_call(s, args[0]);
else
tcg_out_callr(s, COND_AL, args[0]);
break;