tcg-ppc64: Look through a constant function descriptor
Especially in the user-only configurations, a direct branch into the executable may be in range. Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
d40f3cb112
commit
b0940da012
|
@ -173,14 +173,17 @@ static const int tcg_target_callee_save_regs[] = {
|
||||||
TCG_REG_R31
|
TCG_REG_R31
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline bool in_range_b(tcg_target_long target)
|
||||||
|
{
|
||||||
|
return target == sextract64(target, 0, 26);
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t reloc_pc24_val(void *pc, tcg_target_long target)
|
static uint32_t reloc_pc24_val(void *pc, tcg_target_long target)
|
||||||
{
|
{
|
||||||
tcg_target_long disp;
|
tcg_target_long disp;
|
||||||
|
|
||||||
disp = target - (tcg_target_long)pc;
|
disp = target - (tcg_target_long)pc;
|
||||||
if ((disp << 38) >> 38 != disp) {
|
assert(in_range_b(disp));
|
||||||
tcg_abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
return disp & 0x3fffffc;
|
return disp & 0x3fffffc;
|
||||||
}
|
}
|
||||||
|
@ -694,7 +697,7 @@ static void tcg_out_b(TCGContext *s, int mask, tcg_target_long target)
|
||||||
tcg_target_long disp;
|
tcg_target_long disp;
|
||||||
|
|
||||||
disp = target - (tcg_target_long)s->code_ptr;
|
disp = target - (tcg_target_long)s->code_ptr;
|
||||||
if ((disp << 38) >> 38 == disp) {
|
if (in_range_b(disp)) {
|
||||||
tcg_out32(s, B | (disp & 0x3fffffc) | mask);
|
tcg_out32(s, B | (disp & 0x3fffffc) | mask);
|
||||||
} else {
|
} else {
|
||||||
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R0, (tcg_target_long)target);
|
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R0, (tcg_target_long)target);
|
||||||
|
@ -717,6 +720,18 @@ static void tcg_out_call(TCGContext *s, tcg_target_long arg, int const_arg)
|
||||||
int ofs = 0;
|
int ofs = 0;
|
||||||
|
|
||||||
if (const_arg) {
|
if (const_arg) {
|
||||||
|
/* Look through the descriptor. If the branch is in range, and we
|
||||||
|
don't have to spend too much effort on building the toc. */
|
||||||
|
intptr_t tgt = ((intptr_t *)arg)[0];
|
||||||
|
intptr_t toc = ((intptr_t *)arg)[1];
|
||||||
|
intptr_t diff = tgt - (intptr_t)s->code_ptr;
|
||||||
|
|
||||||
|
if (in_range_b(diff) && toc == (uint32_t)toc) {
|
||||||
|
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R2, toc);
|
||||||
|
tcg_out_b(s, LK, tgt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fold the low bits of the constant into the addresses below. */
|
/* Fold the low bits of the constant into the addresses below. */
|
||||||
ofs = (int16_t)arg;
|
ofs = (int16_t)arg;
|
||||||
if (ofs + 8 < 0x8000) {
|
if (ofs + 8 < 0x8000) {
|
||||||
|
|
Loading…
Reference in a new issue