dh_alias_tl stays tl. In common-system code the helper C slot stays
uint64_t and the typecode stays i64, because one typemask is shared
by 32- and 64-bit guests. tcg_gen_callN zero-extends an I32 temp into
that slot and truncates an i64 return.

Signed-off-by: Yonggang Luo <[email protected]>
---
 include/exec/helper-head.h.inc | 21 ++++++++++++++++++--
 tcg/tcg.c                      | 35 ++++++++++++++++++++++++++++++++--
 2 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/include/exec/helper-head.h.inc b/include/exec/helper-head.h.inc
index 7dec5f5b067..6612937c5ae 100644
--- a/include/exec/helper-head.h.inc
+++ b/include/exec/helper-head.h.inc
@@ -45,16 +45,29 @@
 #define dh_ctype_noreturn G_NORETURN void
 #define dh_ctype(t) dh_ctype_##t
 
+#define dh_alias_tl tl
 #ifdef COMPILING_PER_TARGET
 # include "exec/target_long.h"
 # if TARGET_LONG_BITS == 32
-#  define dh_alias_tl i32
 #  define dh_typecode_tl dh_typecode_i32
 # else
-#  define dh_alias_tl i64
 #  define dh_typecode_tl dh_typecode_i64
 # endif
 # define dh_ctype_tl target_ulong
+#else
+/*
+ * Common-system helper FFI only: helper_info.typemask is compile-time
+ * and shared by 32- and 64-bit guests, so the C/libffi slot is
+ * max(i32, i64) -- always i64 / uint64_t. This is not the TCG temp
+ * width. TCGv_tl stays dynamic (I32 or I64 via tcg_type_tl());
+ * tcgv_tl_temp() is the handle-to-TCGTemp accessor and is valid for
+ * either size. Call lowering zero-extends an I32 temp into this
+ * unsigned i64 slot (dh_typecode_tl is i64, not s64). A helper C
+ * body that needs a signed guest value must narrow to XLEN and
+ * sign-extend itself; (int64_t)arg is not a 32-bit sign-extend.
+ */
+# define dh_typecode_tl dh_typecode_i64
+# define dh_ctype_tl uint64_t
 #endif /* COMPILING_PER_TARGET */
 
 #if __SIZEOF_POINTER__ == 4
@@ -76,6 +89,7 @@
 #define dh_retvar_decl0_i64 TCGv_i64 retval
 #define dh_retval_decl0_i128 TCGv_i128 retval
 #define dh_retvar_decl0_ptr TCGv_ptr retval
+#define dh_retvar_decl0_tl TCGv_tl retval
 #define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t))
 
 #define dh_retvar_decl_void
@@ -84,6 +98,7 @@
 #define dh_retvar_decl_i64 TCGv_i64 retval,
 #define dh_retvar_decl_i128 TCGv_i128 retval,
 #define dh_retvar_decl_ptr TCGv_ptr retval,
+#define dh_retvar_decl_tl TCGv_tl retval,
 #define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t))
 
 #define dh_retvar_void NULL
@@ -92,6 +107,7 @@
 #define dh_retvar_i64 tcgv_i64_temp(retval)
 #define dh_retvar_i128 tcgv_i128_temp(retval)
 #define dh_retvar_ptr tcgv_ptr_temp(retval)
+#define dh_retvar_tl tcgv_tl_temp(retval)
 #define dh_retvar(t) glue(dh_retvar_, dh_alias(t))
 
 #define dh_typecode_void 0
@@ -115,6 +131,7 @@
 #define dh_callflag_i64  0
 #define dh_callflag_i128 0
 #define dh_callflag_ptr  0
+#define dh_callflag_tl   0
 #define dh_callflag_void 0
 #define dh_callflag_noreturn TCG_CALL_NO_RETURN
 #define dh_callflag(t) glue(dh_callflag_, dh_alias(t))
diff --git a/tcg/tcg.c b/tcg/tcg.c
index ecc1f54c1bf..ba2a1127f92 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2515,6 +2515,8 @@ static void tcg_gen_callN(void *func, TCGHelperInfo *info,
                           TCGTemp *ret, TCGTemp **args)
 {
     TCGv_i64 extend_free[MAX_CALL_IARGS];
+    TCGv_i64 ret_temp = NULL;
+    TCGTemp *orig_ret = ret;
     int n_extend = 0;
     TCGOp *op;
     int i, n, pi = 0, total_args;
@@ -2524,6 +2526,19 @@ static void tcg_gen_callN(void *func, TCGHelperInfo 
*info,
         g_once_init_leave(HELPER_INFO_INIT(info), HELPER_INFO_INIT_VAL(info));
     }
 
+    /*
+     * An I32 temp in an i64 slot is zero-extended; s64 is sign-extended.
+     * The call returns the wide temp, then extrl writes the I32 back.
+     */
+    if (ret != NULL && ret->type == TCG_TYPE_I32) {
+        unsigned typecode = info->typemask & 7;
+
+        if (typecode == dh_typecode_i64 || typecode == dh_typecode_s64) {
+            ret_temp = tcg_temp_ebb_new_i64();
+            ret = tcgv_i64_temp(ret_temp);
+        }
+    }
+
     total_args = info->nr_out + info->nr_in + 2;
     op = tcg_op_alloc(INDEX_op_call, total_args);
 
@@ -2560,8 +2575,19 @@ static void tcg_gen_callN(void *func, TCGHelperInfo 
*info,
     for (i = 0; i < n; i++) {
         const TCGCallArgumentLoc *loc = &info->in[i];
         TCGTemp *ts = args[loc->arg_idx] + loc->tmp_subindex;
+        TCGCallArgumentKind kind = loc->kind;
 
-        switch (loc->kind) {
+        if (kind == TCG_CALL_ARG_NORMAL && ts->type == TCG_TYPE_I32) {
+            unsigned typecode =
+                extract32(info->typemask, (loc->arg_idx + 1) * 3, 3);
+
+            if (typecode == dh_typecode_i64 ||
+                typecode == dh_typecode_s64) {
+                kind = TCG_CALL_ARG_EXTEND_U + (typecode & 1);
+            }
+        }
+
+        switch (kind) {
         case TCG_CALL_ARG_NORMAL:
         case TCG_CALL_ARG_BY_REF:
         case TCG_CALL_ARG_BY_REF_N:
@@ -2574,7 +2600,7 @@ static void tcg_gen_callN(void *func, TCGHelperInfo *info,
                 TCGv_i64 temp = tcg_temp_ebb_new_i64();
                 TCGv_i32 orig = temp_tcgv_i32(ts);
 
-                if (loc->kind == TCG_CALL_ARG_EXTEND_S) {
+                if (kind == TCG_CALL_ARG_EXTEND_S) {
                     tcg_gen_ext_i32_i64(temp, orig);
                 } else {
                     tcg_gen_extu_i32_i64(temp, orig);
@@ -2602,6 +2628,11 @@ static void tcg_gen_callN(void *func, TCGHelperInfo 
*info,
     for (i = 0; i < n_extend; ++i) {
         tcg_temp_free_i64(extend_free[i]);
     }
+
+    if (ret_temp != NULL) {
+        tcg_gen_extrl_i64_i32(temp_tcgv_i32(orig_ret), ret_temp);
+        tcg_temp_free_i64(ret_temp);
+    }
 }
 
 void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret)
-- 
2.52.0.windows.1


Reply via email to