test-tcg-op calls bswap32_tl, revbit32_tl, trunc, and ext from a common build and checks the i32 or i64 callee, including the 32-bit flag drop. dup_const_tl is checked for MO_8, MO_16, and MO_32. Per-target tests cover both fixed widths.
The call test checks the tl alias and C type for a common build and for both per-target widths. tcg_gen_callN zero-extends an I32 temp into an i64 slot, sign-extends it into an s64 slot, and truncates an i64 return back to I32. Both tests link through tcg_core_deps. That list starts empty and, with TCG enabled, holds the tcg_core objects already built into libsystem, pagevary, and stubs for disas and the qemu ld/st helpers. Signed-off-by: Yonggang Luo <[email protected]> --- accel/tcg/meson.build | 2 +- meson.build | 16 ++ tcg/meson.build | 9 +- tests/unit/meson.build | 20 ++ tests/unit/test-helper-tl.c | 20 ++ tests/unit/test-helper-tl.h | 25 +++ tests/unit/test-helper-tl32.c | 27 +++ tests/unit/test-helper-tl64.c | 27 +++ tests/unit/test-tcg-call-tl-stubs.c | 45 +++++ tests/unit/test-tcg-call-tl.c | 280 ++++++++++++++++++++++++++++ tests/unit/test-tcg-op-dispatch.h | 203 ++++++++++++++++++++ tests/unit/test-tcg-op-tl32.c | 24 +++ tests/unit/test-tcg-op-tl64.c | 24 +++ tests/unit/test-tcg-op.c | 66 +++++++ 14 files changed, 784 insertions(+), 4 deletions(-) create mode 100644 tests/unit/test-helper-tl.c create mode 100644 tests/unit/test-helper-tl.h create mode 100644 tests/unit/test-helper-tl32.c create mode 100644 tests/unit/test-helper-tl64.c create mode 100644 tests/unit/test-tcg-call-tl-stubs.c create mode 100644 tests/unit/test-tcg-call-tl.c create mode 100644 tests/unit/test-tcg-op-dispatch.h create mode 100644 tests/unit/test-tcg-op-tl32.c create mode 100644 tests/unit/test-tcg-op-tl64.c create mode 100644 tests/unit/test-tcg-op.c diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 002aa8f4588..21da63c252f 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -3,11 +3,11 @@ if not have_tcg endif tcg_ss = ss.source_set() +tcg_core.add(files('tcg-runtime.c')) tcg_ss.add(files( 'cpu-exec.c', 'cpu-exec-common.c', - 'tcg-runtime.c', 'tcg-runtime-gvec.c', 'tb-maint.c', 'tcg-all.c', diff --git a/meson.build b/meson.build index 9485f4e97be..d5639a2d676 100644 --- a/meson.build +++ b/meson.build @@ -3731,6 +3731,8 @@ stub_ss = ss.source_set() trace_ss = ss.source_set() user_ss = ss.source_set() util_ss = ss.source_set() +tcg_core = ss.source_set() +tcg_core_deps = [] # accel modules qtest_module_ss = ss.source_set() @@ -4139,6 +4141,20 @@ libsystem = static_library('system', dependencies: system_ss.all_dependencies(), build_by_default: false) +if have_tcg + # tcg_core is compiled into libsystem. Reuse those objects. + # page-vary-common.c is in common_all, not tcg_core. + tcg_core_deps = files('tests/unit/test-tcg-call-tl-stubs.c') + [ + declare_dependency( + objects: libsystem.extract_objects(tcg_core.all_sources()), + compile_args: [ + '-DCOMPILING_SYSTEM_VS_USER', + '-DCONFIG_SOFTMMU', + ]), + ] + tcg_core_deps += pagevary +endif + # Note that this library is never used directly (only through extract_objects) # and is not built by default; therefore, source files not used by the build # configuration will be in build.ninja, but are never built by default. diff --git a/tcg/meson.build b/tcg/meson.build index 706a6eb260e..dced8eb781c 100644 --- a/tcg/meson.build +++ b/tcg/meson.build @@ -4,15 +4,17 @@ endif tcg_ss = ss.source_set() -tcg_ss.add(files( +tcg_core.add(files( 'optimize.c', 'region.c', 'tcg.c', 'tcg-common.c', 'tcg-op.c', + 'tcg-op-vec.c', +)) +tcg_ss.add(files( 'tcg-op-ldst.c', 'tcg-op-gvec.c', - 'tcg-op-vec.c', )) if get_option('tcg_interpreter') @@ -24,8 +26,9 @@ endif tcg_ss.add(when: libdw, if_true: files('debuginfo.c')) if host_os == 'linux' - tcg_ss.add(files('perf.c')) + tcg_core.add(files('perf.c')) endif +tcg_ss.add_all(tcg_core) user_ss.add_all(tcg_ss) system_ss.add_all(tcg_ss) diff --git a/tests/unit/meson.build b/tests/unit/meson.build index dc139889c1d..552f96e37dd 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -43,6 +43,13 @@ tests = { 'test-qgraph': ['../qtest/libqos/qgraph.c'], 'check-qom-interface': [qom], 'check-qom-proplist': [qom], + 'test-tcg-op': [qom] + tcg_core_deps, + 'test-tcg-op-tl32': [declare_dependency(compile_args: [ + '-DCOMPILING_PER_TARGET', + '-DCONFIG_TARGET="test-tcg-op-mem-config32.h"'])], + 'test-tcg-op-tl64': [declare_dependency(compile_args: [ + '-DCOMPILING_PER_TARGET', + '-DCONFIG_TARGET="test-tcg-op-mem-config64.h"'])], 'test-tcg-op-mem': [qom], 'test-tcg-op-mem-tl32': [declare_dependency(compile_args: [ '-DCOMPILING_PER_TARGET', @@ -53,6 +60,13 @@ tests = { 'test-tcg-op-mem-va32-tl64': [declare_dependency(compile_args: [ '-DCOMPILING_PER_TARGET', '-DCONFIG_TARGET="test-tcg-op-mem-config64.h"'])], + 'test-helper-tl': [], + 'test-helper-tl32': [declare_dependency(compile_args: [ + '-DCOMPILING_PER_TARGET', + '-DCONFIG_TARGET="test-tcg-op-mem-config32.h"'])], + 'test-helper-tl64': [declare_dependency(compile_args: [ + '-DCOMPILING_PER_TARGET', + '-DCONFIG_TARGET="test-tcg-op-mem-config64.h"'])], 'test-target-info': [qom, declare_dependency( objects: target_info_def_objects.values(), compile_args: ['-DTARGET_INFO_DEF_COUNT=@0@'.format( @@ -67,6 +81,12 @@ tests = { 'test-envlist': [], } +if have_tcg + tests += { + 'test-tcg-call-tl': tcg_core_deps, + } +endif + if have_system or have_tools tests += { 'test-qmp-event': [testqapi], diff --git a/tests/unit/test-helper-tl.c b/tests/unit/test-helper-tl.c new file mode 100644 index 00000000000..47719ccd95f --- /dev/null +++ b/tests/unit/test-helper-tl.c @@ -0,0 +1,20 @@ +/* + * Common-system tl helper slot stays an i64 C type. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "exec/helper-head.h.inc" + +#define HELPER_TL_EXPECT_TYPECODE dh_typecode_i64 +#define HELPER_TL_EXPECT_CTYPE uint64_t +#include "test-helper-tl.h" + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/tcg/helper-tl/alias", test_helper_tl_alias); + g_test_add_func("/tcg/helper-tl/slot", test_helper_tl_slot); + return g_test_run(); +} diff --git a/tests/unit/test-helper-tl.h b/tests/unit/test-helper-tl.h new file mode 100644 index 00000000000..3ab660217f4 --- /dev/null +++ b/tests/unit/test-helper-tl.h @@ -0,0 +1,25 @@ +/* + * Shared checks for the tl helper slot. + * + * The including file defines HELPER_TL_EXPECT_TYPECODE and + * HELPER_TL_EXPECT_CTYPE after including exec/helper-head.h.inc. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +static void test_helper_tl_alias(void) +{ +#define HELPER_TL_ALIAS_PROBE_tl 1 +#define HELPER_TL_ALIAS_PROBE_i32 0 +#define HELPER_TL_ALIAS_PROBE_i64 0 + g_assert_cmpint(glue(HELPER_TL_ALIAS_PROBE_, dh_alias(tl)), ==, 1); +} + +static void test_helper_tl_slot(void) +{ + g_assert_cmpint(dh_typecode(tl), ==, HELPER_TL_EXPECT_TYPECODE); + g_assert_cmpint(dh_typemask(tl, 0), ==, HELPER_TL_EXPECT_TYPECODE); + g_assert_cmpint(dh_callflag(tl), ==, 0); + g_assert_true(__builtin_types_compatible_p(dh_ctype(tl), + HELPER_TL_EXPECT_CTYPE)); +} diff --git a/tests/unit/test-helper-tl32.c b/tests/unit/test-helper-tl32.c new file mode 100644 index 00000000000..1e99c22d6a9 --- /dev/null +++ b/tests/unit/test-helper-tl32.c @@ -0,0 +1,27 @@ +/* + * Per-target tl helper slot with TARGET_LONG_BITS == 32. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "exec/helper-head.h.inc" + +#define HELPER_TL_EXPECT_TYPECODE dh_typecode_i32 +#define HELPER_TL_EXPECT_CTYPE uint32_t +#include "test-helper-tl.h" + +static void test_helper_tl32_ctype(void) +{ + g_assert_cmpint(TARGET_LONG_BITS, ==, 32); + g_assert_true(__builtin_types_compatible_p(dh_ctype(tl), target_ulong)); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/tcg/helper-tl/tl32-alias", test_helper_tl_alias); + g_test_add_func("/tcg/helper-tl/tl32-slot", test_helper_tl_slot); + g_test_add_func("/tcg/helper-tl/tl32-ctype", test_helper_tl32_ctype); + return g_test_run(); +} diff --git a/tests/unit/test-helper-tl64.c b/tests/unit/test-helper-tl64.c new file mode 100644 index 00000000000..499a84bbf62 --- /dev/null +++ b/tests/unit/test-helper-tl64.c @@ -0,0 +1,27 @@ +/* + * Per-target tl helper slot with TARGET_LONG_BITS == 64. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "exec/helper-head.h.inc" + +#define HELPER_TL_EXPECT_TYPECODE dh_typecode_i64 +#define HELPER_TL_EXPECT_CTYPE uint64_t +#include "test-helper-tl.h" + +static void test_helper_tl64_ctype(void) +{ + g_assert_cmpint(TARGET_LONG_BITS, ==, 64); + g_assert_true(__builtin_types_compatible_p(dh_ctype(tl), target_ulong)); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/tcg/helper-tl/tl64-alias", test_helper_tl_alias); + g_test_add_func("/tcg/helper-tl/tl64-slot", test_helper_tl_slot); + g_test_add_func("/tcg/helper-tl/tl64-ctype", test_helper_tl64_ctype); + return g_test_run(); +} diff --git a/tests/unit/test-tcg-call-tl-stubs.c b/tests/unit/test-tcg-call-tl-stubs.c new file mode 100644 index 00000000000..ec1414b88ba --- /dev/null +++ b/tests/unit/test-tcg-call-tl-stubs.c @@ -0,0 +1,45 @@ +/* + * Stubs for symbols referenced by extracted tcg_core objects. + * The call-slot test does not execute these paths. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "tcg/helper-info.h" + +void disas(FILE *out, const void *code, size_t size); +void helper_ldub_mmu(void); +void helper_lduw_mmu(void); +void helper_ldul_mmu(void); +void helper_ldq_mmu(void); +void helper_ld16_mmu(void); +void helper_ldsb_mmu(void); +void helper_ldsw_mmu(void); +void helper_ldsl_mmu(void); +void helper_stb_mmu(void); +void helper_stw_mmu(void); +void helper_stl_mmu(void); +void helper_stq_mmu(void); +void helper_st16_mmu(void); + +void disas(FILE *out, const void *code, size_t size) +{ + (void)out; + (void)code; + (void)size; +} + +void helper_ldub_mmu(void) {} +void helper_lduw_mmu(void) {} +void helper_ldul_mmu(void) {} +void helper_ldq_mmu(void) {} +void helper_ld16_mmu(void) {} +void helper_ldsb_mmu(void) {} +void helper_ldsw_mmu(void) {} +void helper_ldsl_mmu(void) {} +void helper_stb_mmu(void) {} +void helper_stw_mmu(void) {} +void helper_stl_mmu(void) {} +void helper_stq_mmu(void) {} +void helper_st16_mmu(void) {} diff --git a/tests/unit/test-tcg-call-tl.c b/tests/unit/test-tcg-call-tl.c new file mode 100644 index 00000000000..fc39bbaabae --- /dev/null +++ b/tests/unit/test-tcg-call-tl.c @@ -0,0 +1,280 @@ +/* + * Execute tcg_gen_callN when an I32 temp meets an i64 or s64 slot. + * + * The common-system tl helper uses a fixed i64 C slot. tcg_gen_callN + * zero-extends an I32 argument into that slot, sign-extends an I32 + * argument into an s64 slot, and truncates an i64 or s64 return back + * to an I32 temp. A matching width leaves the call op alone. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "tcg/tcg-op-common.h" + +static TCGContext *ctx; + +static void dummy_helper(void) +{ +} + +static void reset_ctx(void) +{ + if (!ctx) { + ctx = g_new0(TCGContext, 1); + tcg_ctx = ctx; + } + tcg_func_start(ctx); +} + +static TCGTemp *new_temp(TCGType type) +{ + if (type == TCG_TYPE_I32) { + return tcgv_i32_temp(tcg_temp_new_i32()); + } + return tcgv_i64_temp(tcg_temp_new_i64()); +} + +static void prep_info(TCGHelperInfo *info, unsigned typemask) +{ + if (!info->func) { + info->func = dummy_helper; + info->typemask = typemask; + info->flags = TCG_CALL_NO_SIDE_EFFECTS; + } +} + +static int collect_ops(TCGOpcode *out, int max) +{ + TCGOp *op; + int n = 0; + + QTAILQ_FOREACH(op, &ctx->ops, link) { + g_assert_cmpint(n, <, max); + out[n++] = op->opc; + } + return n; +} + +static void assert_ops(const TCGOpcode *exp, int nexp) +{ + TCGOpcode got[8]; + int n = collect_ops(got, ARRAY_SIZE(got)); + int i; + + g_assert_cmpint(n, ==, nexp); + for (i = 0; i < n; i++) { + g_assert_cmpint(got[i], ==, exp[i]); + } +} + +static void assert_call_shape(int nr_out, int nr_in) +{ + TCGOp *op; + int calls = 0; + + QTAILQ_FOREACH(op, &ctx->ops, link) { + if (op->opc == INDEX_op_call) { + g_assert_cmpint(TCGOP_CALLO(op), ==, nr_out); + g_assert_cmpint(TCGOP_CALLI(op), ==, nr_in); + calls++; + } + } + g_assert_cmpint(calls, ==, 1); +} + +static void emit_call1(TCGHelperInfo *info, bool has_ret, + TCGType ret_type, TCGType arg_type) +{ + TCGTemp *ret = NULL; + TCGTemp *arg; + + reset_ctx(); + if (has_ret) { + ret = new_temp(ret_type); + } + arg = new_temp(arg_type); + tcg_gen_call1(dummy_helper, info, ret, arg); +} + +static void emit_call2(TCGHelperInfo *info, TCGType arg0, TCGType arg1) +{ + TCGTemp *a0, *a1; + + reset_ctx(); + a0 = new_temp(arg0); + a1 = new_temp(arg1); + tcg_gen_call2(dummy_helper, info, NULL, a0, a1); +} + +static void test_i32_arg_i64_ret(void) +{ + static TCGHelperInfo info; + TCGOpcode exp[] = { + INDEX_op_extu_i32_i64, + INDEX_op_call, + INDEX_op_extrl_i64_i32, + }; + + prep_info(&info, dh_typemask(i64, 0) | dh_typemask(i64, 1)); + emit_call1(&info, true, TCG_TYPE_I32, TCG_TYPE_I32); + assert_ops(exp, ARRAY_SIZE(exp)); + assert_call_shape(1, 1); +} + +static void test_i32_arg_s64_ret(void) +{ + static TCGHelperInfo info; + TCGOpcode exp[] = { + INDEX_op_ext_i32_i64, + INDEX_op_call, + INDEX_op_extrl_i64_i32, + }; + + prep_info(&info, dh_typemask(s64, 0) | dh_typemask(s64, 1)); + emit_call1(&info, true, TCG_TYPE_I32, TCG_TYPE_I32); + assert_ops(exp, ARRAY_SIZE(exp)); + assert_call_shape(1, 1); +} + +static void test_i64_arg_i64_ret(void) +{ + static TCGHelperInfo info; + TCGOpcode exp[] = { INDEX_op_call }; + + prep_info(&info, dh_typemask(i64, 0) | dh_typemask(i64, 1)); + emit_call1(&info, true, TCG_TYPE_I64, TCG_TYPE_I64); + assert_ops(exp, ARRAY_SIZE(exp)); + assert_call_shape(1, 1); +} + +static void test_i64_arg_i32_ret(void) +{ + static TCGHelperInfo info; + TCGOpcode exp[] = { + INDEX_op_call, + INDEX_op_extrl_i64_i32, + }; + + prep_info(&info, dh_typemask(i64, 0) | dh_typemask(i64, 1)); + emit_call1(&info, true, TCG_TYPE_I32, TCG_TYPE_I64); + assert_ops(exp, ARRAY_SIZE(exp)); + assert_call_shape(1, 1); +} + +static void test_void_i32_arg_i64(void) +{ + static TCGHelperInfo info; + TCGOpcode exp[] = { + INDEX_op_extu_i32_i64, + INDEX_op_call, + }; + + prep_info(&info, dh_typemask(void, 0) | dh_typemask(i64, 1)); + emit_call1(&info, false, 0, TCG_TYPE_I32); + assert_ops(exp, ARRAY_SIZE(exp)); + assert_call_shape(0, 1); +} + +/* + * An i32 or s32 slot keeps the host ABI kind. tcg_gen_callN must not + * also apply the i64-slot extend, and must not truncate the return. + */ +static void test_i32_slot(void) +{ + static TCGHelperInfo info; + TCGOpcode exp[2]; + int n = 0; + + prep_info(&info, dh_typemask(i32, 0) | dh_typemask(i32, 1)); + emit_call1(&info, true, TCG_TYPE_I32, TCG_TYPE_I32); + if (info.in[0].kind == TCG_CALL_ARG_EXTEND_U) { + exp[n++] = INDEX_op_extu_i32_i64; + } else if (info.in[0].kind == TCG_CALL_ARG_EXTEND_S) { + exp[n++] = INDEX_op_ext_i32_i64; + } else { + g_assert_cmpint(info.in[0].kind, ==, TCG_CALL_ARG_NORMAL); + } + exp[n++] = INDEX_op_call; + assert_ops(exp, n); + assert_call_shape(1, 1); +} + +static void test_s32_slot(void) +{ + static TCGHelperInfo info; + TCGOpcode exp[2]; + int n = 0; + + prep_info(&info, dh_typemask(s32, 0) | dh_typemask(s32, 1)); + emit_call1(&info, true, TCG_TYPE_I32, TCG_TYPE_I32); + if (info.in[0].kind == TCG_CALL_ARG_EXTEND_U) { + exp[n++] = INDEX_op_extu_i32_i64; + } else if (info.in[0].kind == TCG_CALL_ARG_EXTEND_S) { + exp[n++] = INDEX_op_ext_i32_i64; + } else { + g_assert_cmpint(info.in[0].kind, ==, TCG_CALL_ARG_NORMAL); + } + exp[n++] = INDEX_op_call; + assert_ops(exp, n); + assert_call_shape(1, 1); +} + +static void test_i32_arg_ptr_slot(void) +{ + static TCGHelperInfo info; + TCGOpcode exp[] = { INDEX_op_call }; + + prep_info(&info, dh_typemask(ptr, 0) | dh_typemask(ptr, 1)); + emit_call1(&info, true, TCG_TYPE_PTR, TCG_TYPE_I32); + assert_ops(exp, ARRAY_SIZE(exp)); + assert_call_shape(1, 1); +} + +static void test_two_args_i32_then_i64(void) +{ + static TCGHelperInfo info; + TCGOpcode exp[] = { + INDEX_op_extu_i32_i64, + INDEX_op_call, + }; + + prep_info(&info, dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2)); + emit_call2(&info, TCG_TYPE_I32, TCG_TYPE_I64); + assert_ops(exp, ARRAY_SIZE(exp)); + assert_call_shape(0, 2); +} + +static void test_two_args_i64_then_s64(void) +{ + static TCGHelperInfo info; + TCGOpcode exp[] = { + INDEX_op_ext_i32_i64, + INDEX_op_call, + }; + + prep_info(&info, dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(s64, 2)); + emit_call2(&info, TCG_TYPE_I64, TCG_TYPE_I32); + assert_ops(exp, ARRAY_SIZE(exp)); + assert_call_shape(0, 2); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/tcg/call-tl/i32-arg-i64-ret", test_i32_arg_i64_ret); + g_test_add_func("/tcg/call-tl/i32-arg-s64-ret", test_i32_arg_s64_ret); + g_test_add_func("/tcg/call-tl/i64-arg-i64-ret", test_i64_arg_i64_ret); + g_test_add_func("/tcg/call-tl/i64-arg-i32-ret", test_i64_arg_i32_ret); + g_test_add_func("/tcg/call-tl/void-i32-arg-i64", test_void_i32_arg_i64); + g_test_add_func("/tcg/call-tl/i32-slot", test_i32_slot); + g_test_add_func("/tcg/call-tl/s32-slot", test_s32_slot); + g_test_add_func("/tcg/call-tl/i32-arg-ptr-slot", test_i32_arg_ptr_slot); + g_test_add_func("/tcg/call-tl/two-args-i32-then-i64", + test_two_args_i32_then_i64); + g_test_add_func("/tcg/call-tl/two-args-i64-then-s64", + test_two_args_i64_then_s64); + return g_test_run(); +} diff --git a/tests/unit/test-tcg-op-dispatch.h b/tests/unit/test-tcg-op-dispatch.h new file mode 100644 index 00000000000..991126b3743 --- /dev/null +++ b/tests/unit/test-tcg-op-dispatch.h @@ -0,0 +1,203 @@ +/* + * Intercept tcg_gen_* callees so tcg-op-tl.h dispatch can be called + * without a TCG context. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef TEST_TCG_OP_DISPATCH_H +#define TEST_TCG_OP_DISPATCH_H + +#include "tcg/tcg.h" + +static struct { + int bswap32_i32; + int bswap32_i64; + int bswap32_i64_flags; + int revbit32_i32; + int revbit32_i64; + int revbit32_i64_flags; + int mov_i32; + int mov_i64; + int extrl_i64_i32; + int extu_i32_i64; + int ext_i32_i64; +} tcg_op_test_saw; + +#define tcg_gen_bswap32_i32 tcg_op_test_record_bswap32_i32 +#define tcg_gen_bswap32_i64 tcg_op_test_record_bswap32_i64 +#define tcg_gen_revbit32_i32 tcg_op_test_record_revbit32_i32 +#define tcg_gen_revbit32_i64 tcg_op_test_record_revbit32_i64 +#define tcg_gen_mov_i32 tcg_op_test_record_mov_i32 +#define tcg_gen_mov_i64 tcg_op_test_record_mov_i64 +#define tcg_gen_extrl_i64_i32 tcg_op_test_record_extrl_i64_i32 +#define tcg_gen_extu_i32_i64 tcg_op_test_record_extu_i32_i64 +#define tcg_gen_ext_i32_i64 tcg_op_test_record_ext_i32_i64 + +#include "tcg/tcg-op.h" + +void tcg_op_test_record_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) +{ + tcg_op_test_saw.bswap32_i32++; + (void)ret; + (void)arg; +} + +void tcg_op_test_record_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) +{ + tcg_op_test_saw.bswap32_i64++; + tcg_op_test_saw.bswap32_i64_flags = flags; + (void)ret; + (void)arg; +} + +void tcg_op_test_record_revbit32_i32(TCGv_i32 ret, TCGv_i32 arg) +{ + tcg_op_test_saw.revbit32_i32++; + (void)ret; + (void)arg; +} + +void tcg_op_test_record_revbit32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) +{ + tcg_op_test_saw.revbit32_i64++; + tcg_op_test_saw.revbit32_i64_flags = flags; + (void)ret; + (void)arg; +} + +void tcg_op_test_record_mov_i32(TCGv_i32 ret, TCGv_i32 arg) +{ + tcg_op_test_saw.mov_i32++; + (void)ret; + (void)arg; +} + +void tcg_op_test_record_mov_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_op_test_saw.mov_i64++; + (void)ret; + (void)arg; +} + +void tcg_op_test_record_extrl_i64_i32(TCGv_i32 ret, TCGv_i64 arg) +{ + tcg_op_test_saw.extrl_i64_i32++; + (void)ret; + (void)arg; +} + +void tcg_op_test_record_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg) +{ + tcg_op_test_saw.extu_i32_i64++; + (void)ret; + (void)arg; +} + +void tcg_op_test_record_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg) +{ + tcg_op_test_saw.ext_i32_i64++; + (void)ret; + (void)arg; +} + +static void tcg_op_test_saw_reset(void) +{ + memset(&tcg_op_test_saw, 0, sizeof(tcg_op_test_saw)); +} + +G_GNUC_UNUSED +static void tcg_op_test_expect_i32(void) +{ + g_assert_false(tl_is_64()); + + tcg_op_test_saw_reset(); + tcg_gen_bswap32_tl((TCGv)NULL, (TCGv)NULL, 0x15); + g_assert_cmpint(tcg_op_test_saw.bswap32_i32, ==, 1); + g_assert_cmpint(tcg_op_test_saw.bswap32_i64, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_revbit32_tl((TCGv)NULL, (TCGv)NULL, 0x15); + g_assert_cmpint(tcg_op_test_saw.revbit32_i32, ==, 1); + g_assert_cmpint(tcg_op_test_saw.revbit32_i64, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_trunc_tl_i32(NULL, (TCGv)NULL); + g_assert_cmpint(tcg_op_test_saw.mov_i32, ==, 1); + g_assert_cmpint(tcg_op_test_saw.extrl_i64_i32, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_trunc_i64_tl((TCGv)NULL, NULL); + g_assert_cmpint(tcg_op_test_saw.extrl_i64_i32, ==, 1); + g_assert_cmpint(tcg_op_test_saw.mov_i64, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_extu_i32_tl((TCGv)NULL, NULL); + g_assert_cmpint(tcg_op_test_saw.mov_i32, ==, 1); + g_assert_cmpint(tcg_op_test_saw.extu_i32_i64, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_ext_i32_tl((TCGv)NULL, NULL); + g_assert_cmpint(tcg_op_test_saw.mov_i32, ==, 1); + g_assert_cmpint(tcg_op_test_saw.ext_i32_i64, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_extu_tl_i64(NULL, (TCGv)NULL); + g_assert_cmpint(tcg_op_test_saw.extu_i32_i64, ==, 1); + g_assert_cmpint(tcg_op_test_saw.mov_i64, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_ext_tl_i64(NULL, (TCGv)NULL); + g_assert_cmpint(tcg_op_test_saw.ext_i32_i64, ==, 1); + g_assert_cmpint(tcg_op_test_saw.mov_i64, ==, 0); +} + +G_GNUC_UNUSED +static void tcg_op_test_expect_i64(void) +{ + g_assert_true(tl_is_64()); + + tcg_op_test_saw_reset(); + tcg_gen_bswap32_tl((TCGv)NULL, (TCGv)NULL, 0x15); + g_assert_cmpint(tcg_op_test_saw.bswap32_i64, ==, 1); + g_assert_cmpint(tcg_op_test_saw.bswap32_i64_flags, ==, 0x15); + g_assert_cmpint(tcg_op_test_saw.bswap32_i32, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_revbit32_tl((TCGv)NULL, (TCGv)NULL, 0x15); + g_assert_cmpint(tcg_op_test_saw.revbit32_i64, ==, 1); + g_assert_cmpint(tcg_op_test_saw.revbit32_i64_flags, ==, 0x15); + g_assert_cmpint(tcg_op_test_saw.revbit32_i32, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_trunc_tl_i32(NULL, (TCGv)NULL); + g_assert_cmpint(tcg_op_test_saw.extrl_i64_i32, ==, 1); + g_assert_cmpint(tcg_op_test_saw.mov_i32, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_trunc_i64_tl((TCGv)NULL, NULL); + g_assert_cmpint(tcg_op_test_saw.mov_i64, ==, 1); + g_assert_cmpint(tcg_op_test_saw.extrl_i64_i32, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_extu_i32_tl((TCGv)NULL, NULL); + g_assert_cmpint(tcg_op_test_saw.extu_i32_i64, ==, 1); + g_assert_cmpint(tcg_op_test_saw.mov_i32, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_ext_i32_tl((TCGv)NULL, NULL); + g_assert_cmpint(tcg_op_test_saw.ext_i32_i64, ==, 1); + g_assert_cmpint(tcg_op_test_saw.mov_i32, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_extu_tl_i64(NULL, (TCGv)NULL); + g_assert_cmpint(tcg_op_test_saw.mov_i64, ==, 1); + g_assert_cmpint(tcg_op_test_saw.extu_i32_i64, ==, 0); + + tcg_op_test_saw_reset(); + tcg_gen_ext_tl_i64(NULL, (TCGv)NULL); + g_assert_cmpint(tcg_op_test_saw.mov_i64, ==, 1); + g_assert_cmpint(tcg_op_test_saw.ext_i32_i64, ==, 0); +} + +#endif /* TEST_TCG_OP_DISPATCH_H */ diff --git a/tests/unit/test-tcg-op-tl32.c b/tests/unit/test-tcg-op-tl32.c new file mode 100644 index 00000000000..5d7cf05c5ea --- /dev/null +++ b/tests/unit/test-tcg-op-tl32.c @@ -0,0 +1,24 @@ +/* + * tcg-op.h with TARGET_LONG_BITS == 32. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "test-tcg-op-dispatch.h" + +static void test_tl32(void) +{ + g_assert_cmpint(TARGET_LONG_BITS, ==, 32); + g_assert_false(tl_is_64()); + g_assert_true(__builtin_types_compatible_p(__typeof__(tcg_temp_new()), + TCGv_i32)); + tcg_op_test_expect_i32(); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/tcg/op/tl32-dispatch", test_tl32); + return g_test_run(); +} diff --git a/tests/unit/test-tcg-op-tl64.c b/tests/unit/test-tcg-op-tl64.c new file mode 100644 index 00000000000..0d9a7e2d0fc --- /dev/null +++ b/tests/unit/test-tcg-op-tl64.c @@ -0,0 +1,24 @@ +/* + * tcg-op.h with TARGET_LONG_BITS == 64. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "test-tcg-op-dispatch.h" + +static void test_tl64(void) +{ + g_assert_cmpint(TARGET_LONG_BITS, ==, 64); + g_assert_true(tl_is_64()); + g_assert_true(__builtin_types_compatible_p(__typeof__(tcg_temp_new()), + TCGv_i64)); + tcg_op_test_expect_i64(); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/tcg/op/tl64-dispatch", test_tl64); + return g_test_run(); +} diff --git a/tests/unit/test-tcg-op.c b/tests/unit/test-tcg-op.c new file mode 100644 index 00000000000..92041349b47 --- /dev/null +++ b/tests/unit/test-tcg-op.c @@ -0,0 +1,66 @@ +/* + * Compile and call tcg-op.h with no TARGET_LONG_BITS. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/target-info-def.h" +#include "test-tcg-op-dispatch.h" + +static const TargetInfo tl32_info = { + .target_name = "tl32", + .long_bits = 32, +}; + +static const TargetInfo tl64_info = { + .target_name = "tl64", + .long_bits = 64, +}; + +static void test_common_tl_types(void) +{ + g_assert_true(__builtin_types_compatible_p(__typeof__(tcg_temp_new()), + TCGv)); + g_assert_true(__builtin_types_compatible_p( + __typeof__(tcg_constant_tl(0)), TCGv)); +} + +static void test_dispatch_both_widths(void) +{ + target_info_select(&tl32_info); + tcg_op_test_expect_i32(); + + target_info_select(&tl64_info); + tcg_op_test_expect_i64(); +} + +static void test_dup_const_tl_width(void) +{ + target_info_select(&tl32_info); + g_assert_false(tl_is_64()); + g_assert_cmpint(tcg_type_tl(), ==, TCG_TYPE_I32); + g_assert_cmpuint((uint64_t)dup_const_tl(MO_8, 0xab), ==, 0xababababu); + g_assert_cmpuint((uint64_t)dup_const_tl(MO_16, 0xabcd), ==, 0xabcdabcdu); + g_assert_cmpuint((uint64_t)dup_const_tl(MO_32, 0x01020304), ==, + 0x01020304u); + + target_info_select(&tl64_info); + g_assert_true(tl_is_64()); + g_assert_cmpint(tcg_type_tl(), ==, TCG_TYPE_I64); + g_assert_cmpuint((uint64_t)dup_const_tl(MO_8, 0xab), ==, + 0xababababababababull); + g_assert_cmpuint((uint64_t)dup_const_tl(MO_16, 0xabcd), ==, + 0xabcdabcdabcdabcdull); + g_assert_cmpuint((uint64_t)dup_const_tl(MO_32, 0x01020304), ==, + 0x0102030401020304ull); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/tcg/op/common-tl-types", test_common_tl_types); + g_test_add_func("/tcg/op/dispatch-both-widths", test_dispatch_both_widths); + g_test_add_func("/tcg/op/dup-const-tl-width", test_dup_const_tl_width); + return g_test_run(); +} -- 2.52.0.windows.1
