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
