Invent tcg_out_ld_abs, using LOAD RELATIVE instructions, and use it.

Signed-off-by: Richard Henderson <r...@twiddle.net>
---
 tcg/s390/tcg-target.c |   37 +++++++++++++++++++++++++------------
 1 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index f1e00e9..822835b 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -59,12 +59,14 @@ typedef enum S390Opcode {
     RIL_ALGFI   = 0xc20a,
     RIL_BRASL   = 0xc005,
     RIL_BRCL    = 0xc004,
-    RIL_LARL    = 0xc000,
     RIL_IIHF    = 0xc008,
     RIL_IILF    = 0xc009,
+    RIL_LARL    = 0xc000,
     RIL_LGFI    = 0xc001,
+    RIL_LGRL    = 0xc408,
     RIL_LLIHF   = 0xc00e,
     RIL_LLILF   = 0xc00f,
+    RIL_LRL     = 0xc40d,
     RIL_MSFI    = 0xc201,
     RIL_MSGFI   = 0xc200,
     RIL_NIHF    = 0xc00a,
@@ -755,6 +757,27 @@ static inline void tcg_out_st(TCGContext *s, TCGType type, 
TCGReg data,
     }
 }
 
+/* load data from an absolute host address */
+static void tcg_out_ld_abs(TCGContext *s, TCGType type, TCGReg dest, void *abs)
+{
+    tcg_target_long addr = (tcg_target_long)abs;
+
+    if (facilities & FACILITY_GEN_INST_EXT) {
+        tcg_target_long disp = (addr - (tcg_target_long)s->code_ptr) >> 1;
+        if (disp == (int32_t)disp) {
+            if (type == TCG_TYPE_I32) {
+                tcg_out_insn(s, RIL, LRL, dest, disp);
+            } else {
+                tcg_out_insn(s, RIL, LGRL, dest, disp);
+            }
+            return;
+        }
+    }
+
+    tcg_out_movi(s, TCG_TYPE_PTR, dest, addr & ~0xffff);
+    tcg_out_ld(s, type, dest, dest, addr & 0xffff);
+}
+
 static void tgen_ext8s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
 {
     if (facilities & FACILITY_EXT_IMM) {
@@ -1360,18 +1383,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode 
opc,
         if (s->tb_jmp_offset) {
             tcg_abort();
         } else {
-            tcg_target_long off = ((tcg_target_long)(s->tb_next + args[0]) -
-                                   (tcg_target_long)s->code_ptr) >> 1;
-            if (off == (int32_t)off) {
-                /* load address relative to PC */
-                tcg_out_insn(s, RIL, LARL, TCG_TMP0, off);
-            } else {
-                /* too far for larl */
-                tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0,
-                             (tcg_target_long)(s->tb_next + args[0]));
-            }
             /* load address stored at s->tb_next + args[0] */
-            tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_TMP0, 0);
+            tcg_out_ld_abs(s, TCG_TYPE_PTR, TCG_TMP0, s->tb_next + args[0]);
             /* and go there */
             tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_TMP0);
         }
-- 
1.7.0.1


Reply via email to