aboutsummaryrefslogtreecommitdiff
path: root/tcg/arm
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2019-04-25 10:39:39 -0700
committerRichard Henderson <richard.henderson@linaro.org>2019-04-25 10:39:39 -0700
commitb4b82d7e9caff7ccca5c621817b5a4b8e95eb9b1 (patch)
tree15e31c7944b7db44e30fdeeac25430d13d45771d /tcg/arm
parenta7cdaf710f2aaaf0be855a338dd67463d4bb99e2 (diff)
tcg/arm: Restrict constant pool displacement to 12 bits
This will not necessarily restrict the size of the TB, since for v7 the majority of constant pool usage is for calls from the out-of-line ldst code, which is already at the end of the TB. But this does allow us to save one insn per reference on the off-chance. Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'tcg/arm')
-rw-r--r--tcg/arm/tcg-target.inc.c57
1 files changed, 21 insertions, 36 deletions
diff --git a/tcg/arm/tcg-target.inc.c b/tcg/arm/tcg-target.inc.c
index 12a65cc9a6..abf0c444b4 100644
--- a/tcg/arm/tcg-target.inc.c
+++ b/tcg/arm/tcg-target.inc.c
@@ -197,6 +197,24 @@ static inline bool reloc_pc24(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
return false;
}
+static inline bool reloc_pc13(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+{
+ ptrdiff_t offset = tcg_ptr_byte_diff(target, code_ptr) - 8;
+
+ if (offset >= -0xfff && offset <= 0xfff) {
+ tcg_insn_unit insn = *code_ptr;
+ bool u = (offset >= 0);
+ if (!u) {
+ offset = -offset;
+ }
+ insn = deposit32(insn, 23, 1, u);
+ insn = deposit32(insn, 0, 12, offset);
+ *code_ptr = insn;
+ return true;
+ }
+ return false;
+}
+
static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend)
{
@@ -205,39 +223,10 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
if (type == R_ARM_PC24) {
return reloc_pc24(code_ptr, (tcg_insn_unit *)value);
} else if (type == R_ARM_PC13) {
- intptr_t diff = value - (uintptr_t)(code_ptr + 2);
- tcg_insn_unit insn = *code_ptr;
- bool u;
-
- if (diff >= -0xfff && diff <= 0xfff) {
- u = (diff >= 0);
- if (!u) {
- diff = -diff;
- }
- } else {
- int rd = extract32(insn, 12, 4);
- int rt = rd == TCG_REG_PC ? TCG_REG_TMP : rd;
-
- if (diff < 0x1000 || diff >= 0x100000) {
- return false;
- }
-
- /* add rt, pc, #high */
- *code_ptr++ = ((insn & 0xf0000000) | (1 << 25) | ARITH_ADD
- | (TCG_REG_PC << 16) | (rt << 12)
- | (20 << 7) | (diff >> 12));
- /* ldr rd, [rt, #low] */
- insn = deposit32(insn, 12, 4, rt);
- diff &= 0xfff;
- u = 1;
- }
- insn = deposit32(insn, 23, 1, u);
- insn = deposit32(insn, 0, 12, diff);
- *code_ptr = insn;
+ return reloc_pc13(code_ptr, (tcg_insn_unit *)value);
} else {
g_assert_not_reached();
}
- return true;
}
#define TCG_CT_CONST_ARM 0x100
@@ -605,12 +594,8 @@ static inline void tcg_out_ld8s_r(TCGContext *s, int cond, TCGReg rt,
static void tcg_out_movi_pool(TCGContext *s, int cond, int rd, uint32_t arg)
{
- /* The 12-bit range on the ldr insn is sometimes a bit too small.
- In order to get around that we require two insns, one of which
- will usually be a nop, but may be replaced in patch_reloc. */
new_pool_label(s, arg, R_ARM_PC13, s->code_ptr, 0);
tcg_out_ld32_12(s, cond, rd, TCG_REG_PC, 0);
- tcg_out_nop(s);
}
static void tcg_out_movi32(TCGContext *s, int cond, int rd, uint32_t arg)
@@ -1069,8 +1054,8 @@ static void tcg_out_call(TCGContext *s, tcg_insn_unit *addr)
tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addri);
tcg_out_blx(s, COND_AL, TCG_REG_TMP);
} else {
- /* ??? Know that movi_pool emits exactly 2 insns. */
- tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R14, TCG_REG_PC, 4);
+ /* ??? 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_movi_pool(s, COND_AL, TCG_REG_PC, addri);
}
}