diff mbox series

[21/30] tcg/loongarch: Implement tcg_out_call

Message ID 20210920080451.408655-22-git@xen0n.name (mailing list archive)
State New, archived
Headers show
Series 64-bit LoongArch port of QEMU TCG | expand

Commit Message

WANG Xuerui Sept. 20, 2021, 8:04 a.m. UTC
Signed-off-by: WANG Xuerui <git@xen0n.name>
---
 tcg/loongarch/tcg-target.c.inc | 37 ++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

Comments

Richard Henderson Sept. 20, 2021, 4:31 p.m. UTC | #1
On 9/20/21 1:04 AM, WANG Xuerui wrote:
> +    } else if (TCG_TARGET_REG_BITS == 32 || offset == (int32_t)offset) {
> +        /* long jump: +/- 2GiB */
> +        tcg_out_opc_pcaddu12i(s, TCG_REG_TMP0, 0);
> +        tcg_out_opc_jirl(s, link, TCG_REG_TMP0, 0);
> +        ret = reloc_call(s->code_ptr - 2, arg);
> +        tcg_debug_assert(ret == true);

Just inline reloc_call here, so that you can provide the correct offsets to the pcadd and 
jirl instructions directly.  The assert will vanish, because you've already done the range 
check with "offset == (int32_t)offset".


r~
Richard Henderson Sept. 20, 2021, 4:35 p.m. UTC | #2
On 9/20/21 9:31 AM, Richard Henderson wrote:
> On 9/20/21 1:04 AM, WANG Xuerui wrote:
>> +    } else if (TCG_TARGET_REG_BITS == 32 || offset == (int32_t)offset) {
>> +        /* long jump: +/- 2GiB */
>> +        tcg_out_opc_pcaddu12i(s, TCG_REG_TMP0, 0);
>> +        tcg_out_opc_jirl(s, link, TCG_REG_TMP0, 0);
>> +        ret = reloc_call(s->code_ptr - 2, arg);
>> +        tcg_debug_assert(ret == true);
> 
> Just inline reloc_call here, so that you can provide the correct offsets to the pcadd and 
> jirl instructions directly.  The assert will vanish, because you've already done the range 
> check with "offset == (int32_t)offset".

Actually, don't you want offset == sextract64(offset, 0, 34), and use pcaddu18i? 
Depending on the memory map of qemu, those extra bits could make the difference in 
directly reaching the main executable.


r~
WANG Xuerui Sept. 21, 2021, 6:42 a.m. UTC | #3
Hi Richard,

On 9/21/21 00:35, Richard Henderson wrote:
> On 9/20/21 9:31 AM, Richard Henderson wrote:
>> On 9/20/21 1:04 AM, WANG Xuerui wrote:
>>> +    } else if (TCG_TARGET_REG_BITS == 32 || offset == 
>>> (int32_t)offset) {
>>> +        /* long jump: +/- 2GiB */
>>> +        tcg_out_opc_pcaddu12i(s, TCG_REG_TMP0, 0);
>>> +        tcg_out_opc_jirl(s, link, TCG_REG_TMP0, 0);
>>> +        ret = reloc_call(s->code_ptr - 2, arg);
>>> +        tcg_debug_assert(ret == true);
>>
>> Just inline reloc_call here, so that you can provide the correct 
>> offsets to the pcadd and jirl instructions directly.  The assert will 
>> vanish, because you've already done the range check with "offset == 
>> (int32_t)offset".
>
> Actually, don't you want offset == sextract64(offset, 0, 34), and use 
> pcaddu18i? Depending on the memory map of qemu, those extra bits could 
> make the difference in directly reaching the main executable.
>
Whoa, silly me, I actually didn't realize a single expected use case of 
pcaddu18i until I read this, the low 2 bits are always clear so 18 is 
exactly the amount of shift needed when paired with jirl!

I'll of course rework this to use pcaddu18i+jirl instead.

>
> r~
diff mbox series

Patch

diff --git a/tcg/loongarch/tcg-target.c.inc b/tcg/loongarch/tcg-target.c.inc
index fb0143474a..01c6002fdb 100644
--- a/tcg/loongarch/tcg-target.c.inc
+++ b/tcg/loongarch/tcg-target.c.inc
@@ -457,6 +457,42 @@  static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1,
     tcg_out32(s, encode_djsk16_insn(op, arg1, arg2, 0));
 }
 
+static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
+{
+    TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA;
+    ptrdiff_t offset = tcg_pcrel_diff(s, arg);
+    int ret;
+
+    tcg_debug_assert((offset & 2) == 0);
+    if (offset == sextreg(offset, 0, 28)) {
+        /* short jump: +/- 256MiB */
+        if (tail) {
+            tcg_out_opc_b(s, offset >> 2);
+        } else {
+            tcg_out_opc_bl(s, offset >> 2);
+        }
+    } else if (TCG_TARGET_REG_BITS == 32 || offset == (int32_t)offset) {
+        /* long jump: +/- 2GiB */
+        tcg_out_opc_pcaddu12i(s, TCG_REG_TMP0, 0);
+        tcg_out_opc_jirl(s, link, TCG_REG_TMP0, 0);
+        ret = reloc_call(s->code_ptr - 2, arg);
+        tcg_debug_assert(ret == true);
+    } else if (TCG_TARGET_REG_BITS == 64) {
+        /* far jump: 64-bit */
+        tcg_target_long imm = sextreg((tcg_target_long)arg, 0, 12);
+        tcg_target_long base = (tcg_target_long)arg - imm;
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, base);
+        tcg_out_opc_jirl(s, link, TCG_REG_TMP0, imm >> 2);
+    } else {
+        g_assert_not_reached();
+    }
+}
+
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
+{
+    tcg_out_call_int(s, arg, false);
+}
+
 /*
  * Entry-points
  */
@@ -779,6 +815,7 @@  static void tcg_out_op(TCGContext *s, TCGOpcode opc,
 
     case INDEX_op_mov_i32:  /* Always emitted via tcg_out_mov.  */
     case INDEX_op_mov_i64:
+    case INDEX_op_call:     /* Always emitted via tcg_out_call.  */
     default:
         g_assert_not_reached();
     }