tcg: Add INDEX_op_qemu_{ld,st}_i128
Add opcodes for backend support for 128-bit memory operations. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
7b88010719
commit
12fde9bcdb
@ -672,19 +672,20 @@ QEMU specific operations
|
||||
| This operation is optional. If the TCG backend does not implement the
|
||||
goto_ptr opcode, emitting this op is equivalent to emitting exit_tb(0).
|
||||
|
||||
* - qemu_ld_i32/i64 *t0*, *t1*, *flags*, *memidx*
|
||||
* - qemu_ld_i32/i64/i128 *t0*, *t1*, *flags*, *memidx*
|
||||
|
||||
qemu_st_i32/i64 *t0*, *t1*, *flags*, *memidx*
|
||||
qemu_st_i32/i64/i128 *t0*, *t1*, *flags*, *memidx*
|
||||
|
||||
qemu_st8_i32 *t0*, *t1*, *flags*, *memidx*
|
||||
|
||||
- | Load data at the guest address *t1* into *t0*, or store data in *t0* at guest
|
||||
address *t1*. The _i32/_i64 size applies to the size of the input/output
|
||||
address *t1*. The _i32/_i64/_i128 size applies to the size of the input/output
|
||||
register *t0* only. The address *t1* is always sized according to the guest,
|
||||
and the width of the memory operation is controlled by *flags*.
|
||||
|
|
||||
| Both *t0* and *t1* may be split into little-endian ordered pairs of registers
|
||||
if dealing with 64-bit quantities on a 32-bit host.
|
||||
if dealing with 64-bit quantities on a 32-bit host, or 128-bit quantities on
|
||||
a 64-bit host.
|
||||
|
|
||||
| The *memidx* selects the qemu tlb index to use (e.g. user or kernel access).
|
||||
The flags are the MemOp bits, selecting the sign, width, and endianness
|
||||
@ -693,6 +694,8 @@ QEMU specific operations
|
||||
| For a 32-bit host, qemu_ld/st_i64 is guaranteed to only be used with a
|
||||
64-bit memory access specified in *flags*.
|
||||
|
|
||||
| For qemu_ld/st_i128, these are only supported for a 64-bit host.
|
||||
|
|
||||
| For i386, qemu_st8_i32 is exactly like qemu_st_i32, except the size of
|
||||
the memory operation is known to be 8-bit. This allows the backend to
|
||||
provide a different set of register constraints.
|
||||
|
@ -213,6 +213,14 @@ DEF(qemu_st8_i32, 0, TLADDR_ARGS + 1, 1,
|
||||
TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS |
|
||||
IMPL(TCG_TARGET_HAS_qemu_st8_i32))
|
||||
|
||||
/* Only for 64-bit hosts at the moment. */
|
||||
DEF(qemu_ld_i128, 2, 1, 1,
|
||||
TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS | TCG_OPF_64BIT |
|
||||
IMPL(TCG_TARGET_HAS_qemu_ldst_i128))
|
||||
DEF(qemu_st_i128, 0, 3, 1,
|
||||
TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS | TCG_OPF_64BIT |
|
||||
IMPL(TCG_TARGET_HAS_qemu_ldst_i128))
|
||||
|
||||
/* Host vector support. */
|
||||
|
||||
#define IMPLVEC TCG_OPF_VECTOR | IMPL(TCG_TARGET_MAYBE_vec)
|
||||
|
@ -129,6 +129,8 @@ extern bool have_lse2;
|
||||
#define TCG_TARGET_HAS_muluh_i64 1
|
||||
#define TCG_TARGET_HAS_mulsh_i64 1
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
#define TCG_TARGET_HAS_v64 1
|
||||
#define TCG_TARGET_HAS_v128 1
|
||||
#define TCG_TARGET_HAS_v256 0
|
||||
|
@ -125,6 +125,8 @@ extern bool use_neon_instructions;
|
||||
#define TCG_TARGET_HAS_rem_i32 0
|
||||
#define TCG_TARGET_HAS_qemu_st8_i32 0
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
#define TCG_TARGET_HAS_v64 use_neon_instructions
|
||||
#define TCG_TARGET_HAS_v128 use_neon_instructions
|
||||
#define TCG_TARGET_HAS_v256 0
|
||||
|
@ -194,6 +194,8 @@ extern bool have_atomic16;
|
||||
#define TCG_TARGET_HAS_qemu_st8_i32 1
|
||||
#endif
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
/* We do not support older SSE systems, only beginning with AVX1. */
|
||||
#define TCG_TARGET_HAS_v64 have_avx1
|
||||
#define TCG_TARGET_HAS_v128 have_avx1
|
||||
|
@ -168,6 +168,7 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_muls2_i64 0
|
||||
#define TCG_TARGET_HAS_muluh_i64 1
|
||||
#define TCG_TARGET_HAS_mulsh_i64 1
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO (0)
|
||||
|
||||
|
@ -204,6 +204,8 @@ extern bool use_mips32r2_instructions;
|
||||
#define TCG_TARGET_HAS_ext16u_i64 0 /* andi rt, rs, 0xffff */
|
||||
#endif
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO 0
|
||||
#define TCG_TARGET_NEED_LDST_LABELS
|
||||
|
||||
|
@ -2186,11 +2186,13 @@ void tcg_optimize(TCGContext *s)
|
||||
break;
|
||||
case INDEX_op_qemu_ld_i32:
|
||||
case INDEX_op_qemu_ld_i64:
|
||||
case INDEX_op_qemu_ld_i128:
|
||||
done = fold_qemu_ld(&ctx, op);
|
||||
break;
|
||||
case INDEX_op_qemu_st_i32:
|
||||
case INDEX_op_qemu_st8_i32:
|
||||
case INDEX_op_qemu_st_i64:
|
||||
case INDEX_op_qemu_st_i128:
|
||||
done = fold_qemu_st(&ctx, op);
|
||||
break;
|
||||
CASE_OP_32_64(rem):
|
||||
|
@ -149,6 +149,8 @@ extern bool have_vsx;
|
||||
#define TCG_TARGET_HAS_mulsh_i64 1
|
||||
#endif
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
/*
|
||||
* While technically Altivec could support V64, it has no 64-bit store
|
||||
* instruction and substituting two 32-bit stores makes the generated
|
||||
|
@ -163,6 +163,8 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_muluh_i64 1
|
||||
#define TCG_TARGET_HAS_mulsh_i64 1
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO (0)
|
||||
|
||||
#define TCG_TARGET_NEED_LDST_LABELS
|
||||
|
@ -140,6 +140,8 @@ extern uint64_t s390_facilities[3];
|
||||
#define TCG_TARGET_HAS_muluh_i64 0
|
||||
#define TCG_TARGET_HAS_mulsh_i64 0
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
#define TCG_TARGET_HAS_v64 HAVE_FACILITY(VECTOR)
|
||||
#define TCG_TARGET_HAS_v128 HAVE_FACILITY(VECTOR)
|
||||
#define TCG_TARGET_HAS_v256 0
|
||||
|
@ -151,6 +151,8 @@ extern bool use_vis3_instructions;
|
||||
#define TCG_TARGET_HAS_muluh_i64 use_vis3_instructions
|
||||
#define TCG_TARGET_HAS_mulsh_i64 0
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
#define TCG_AREG0 TCG_REG_I0
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO (0)
|
||||
|
69
tcg/tcg-op.c
69
tcg/tcg-op.c
@ -3205,7 +3205,7 @@ static void canonicalize_memop_i128_as_i64(MemOp ret[2], MemOp orig)
|
||||
|
||||
void tcg_gen_qemu_ld_i128(TCGv_i128 val, TCGv addr, TCGArg idx, MemOp memop)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(memop, idx);
|
||||
const MemOpIdx oi = make_memop_idx(memop, idx);
|
||||
|
||||
tcg_debug_assert((memop & MO_SIZE) == MO_128);
|
||||
tcg_debug_assert((memop & MO_SIGN) == 0);
|
||||
@ -3213,9 +3213,36 @@ void tcg_gen_qemu_ld_i128(TCGv_i128 val, TCGv addr, TCGArg idx, MemOp memop)
|
||||
tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
|
||||
addr = plugin_prep_mem_callbacks(addr);
|
||||
|
||||
/* TODO: allow the tcg backend to see the whole operation. */
|
||||
/* TODO: For now, force 32-bit hosts to use the helper. */
|
||||
if (TCG_TARGET_HAS_qemu_ldst_i128 && TCG_TARGET_REG_BITS == 64) {
|
||||
TCGv_i64 lo, hi;
|
||||
TCGArg addr_arg;
|
||||
MemOpIdx adj_oi;
|
||||
bool need_bswap = false;
|
||||
|
||||
if (use_two_i64_for_i128(memop)) {
|
||||
if ((memop & MO_BSWAP) && !tcg_target_has_memory_bswap(memop)) {
|
||||
lo = TCGV128_HIGH(val);
|
||||
hi = TCGV128_LOW(val);
|
||||
adj_oi = make_memop_idx(memop & ~MO_BSWAP, idx);
|
||||
need_bswap = true;
|
||||
} else {
|
||||
lo = TCGV128_LOW(val);
|
||||
hi = TCGV128_HIGH(val);
|
||||
adj_oi = oi;
|
||||
}
|
||||
|
||||
#if TARGET_LONG_BITS == 32
|
||||
addr_arg = tcgv_i32_arg(addr);
|
||||
#else
|
||||
addr_arg = tcgv_i64_arg(addr);
|
||||
#endif
|
||||
tcg_gen_op4ii_i64(INDEX_op_qemu_ld_i128, lo, hi, addr_arg, adj_oi);
|
||||
|
||||
if (need_bswap) {
|
||||
tcg_gen_bswap64_i64(lo, lo);
|
||||
tcg_gen_bswap64_i64(hi, hi);
|
||||
}
|
||||
} else if (use_two_i64_for_i128(memop)) {
|
||||
MemOp mop[2];
|
||||
TCGv addr_p8;
|
||||
TCGv_i64 x, y;
|
||||
@ -3258,7 +3285,7 @@ void tcg_gen_qemu_ld_i128(TCGv_i128 val, TCGv addr, TCGArg idx, MemOp memop)
|
||||
|
||||
void tcg_gen_qemu_st_i128(TCGv_i128 val, TCGv addr, TCGArg idx, MemOp memop)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(memop, idx);
|
||||
const MemOpIdx oi = make_memop_idx(memop, idx);
|
||||
|
||||
tcg_debug_assert((memop & MO_SIZE) == MO_128);
|
||||
tcg_debug_assert((memop & MO_SIGN) == 0);
|
||||
@ -3266,9 +3293,39 @@ void tcg_gen_qemu_st_i128(TCGv_i128 val, TCGv addr, TCGArg idx, MemOp memop)
|
||||
tcg_gen_req_mo(TCG_MO_ST_LD | TCG_MO_ST_ST);
|
||||
addr = plugin_prep_mem_callbacks(addr);
|
||||
|
||||
/* TODO: allow the tcg backend to see the whole operation. */
|
||||
/* TODO: For now, force 32-bit hosts to use the helper. */
|
||||
|
||||
if (use_two_i64_for_i128(memop)) {
|
||||
if (TCG_TARGET_HAS_qemu_ldst_i128 && TCG_TARGET_REG_BITS == 64) {
|
||||
TCGv_i64 lo, hi;
|
||||
TCGArg addr_arg;
|
||||
MemOpIdx adj_oi;
|
||||
bool need_bswap = false;
|
||||
|
||||
if ((memop & MO_BSWAP) && !tcg_target_has_memory_bswap(memop)) {
|
||||
lo = tcg_temp_new_i64();
|
||||
hi = tcg_temp_new_i64();
|
||||
tcg_gen_bswap64_i64(lo, TCGV128_HIGH(val));
|
||||
tcg_gen_bswap64_i64(hi, TCGV128_LOW(val));
|
||||
adj_oi = make_memop_idx(memop & ~MO_BSWAP, idx);
|
||||
need_bswap = true;
|
||||
} else {
|
||||
lo = TCGV128_LOW(val);
|
||||
hi = TCGV128_HIGH(val);
|
||||
adj_oi = oi;
|
||||
}
|
||||
|
||||
#if TARGET_LONG_BITS == 32
|
||||
addr_arg = tcgv_i32_arg(addr);
|
||||
#else
|
||||
addr_arg = tcgv_i64_arg(addr);
|
||||
#endif
|
||||
tcg_gen_op4ii_i64(INDEX_op_qemu_st_i128, lo, hi, addr_arg, adj_oi);
|
||||
|
||||
if (need_bswap) {
|
||||
tcg_temp_free_i64(lo);
|
||||
tcg_temp_free_i64(hi);
|
||||
}
|
||||
} else if (use_two_i64_for_i128(memop)) {
|
||||
MemOp mop[2];
|
||||
TCGv addr_p8;
|
||||
TCGv_i64 x, y;
|
||||
|
10
tcg/tcg.c
10
tcg/tcg.c
@ -1735,6 +1735,10 @@ bool tcg_op_supported(TCGOpcode op)
|
||||
case INDEX_op_qemu_st8_i32:
|
||||
return TCG_TARGET_HAS_qemu_st8_i32;
|
||||
|
||||
case INDEX_op_qemu_ld_i128:
|
||||
case INDEX_op_qemu_st_i128:
|
||||
return TCG_TARGET_HAS_qemu_ldst_i128;
|
||||
|
||||
case INDEX_op_mov_i32:
|
||||
case INDEX_op_setcond_i32:
|
||||
case INDEX_op_brcond_i32:
|
||||
@ -2187,7 +2191,7 @@ static const char * const cond_name[] =
|
||||
[TCG_COND_GTU] = "gtu"
|
||||
};
|
||||
|
||||
static const char * const ldst_name[] =
|
||||
static const char * const ldst_name[(MO_BSWAP | MO_SSIZE) + 1] =
|
||||
{
|
||||
[MO_UB] = "ub",
|
||||
[MO_SB] = "sb",
|
||||
@ -2201,6 +2205,8 @@ static const char * const ldst_name[] =
|
||||
[MO_BEUL] = "beul",
|
||||
[MO_BESL] = "besl",
|
||||
[MO_BEUQ] = "beq",
|
||||
[MO_128 + MO_BE] = "beo",
|
||||
[MO_128 + MO_LE] = "leo",
|
||||
};
|
||||
|
||||
static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
|
||||
@ -2357,6 +2363,8 @@ static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
|
||||
case INDEX_op_qemu_st8_i32:
|
||||
case INDEX_op_qemu_ld_i64:
|
||||
case INDEX_op_qemu_st_i64:
|
||||
case INDEX_op_qemu_ld_i128:
|
||||
case INDEX_op_qemu_st_i128:
|
||||
{
|
||||
const char *s_al, *s_op, *s_at;
|
||||
MemOpIdx oi = op->args[k++];
|
||||
|
@ -127,6 +127,8 @@
|
||||
#define TCG_TARGET_HAS_mulu2_i32 1
|
||||
#endif /* TCG_TARGET_REG_BITS == 64 */
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
/* Number of registers available. */
|
||||
#define TCG_TARGET_NB_REGS 16
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user