mirror of https://github.com/xemu-project/xemu.git
tcg: Add TCG_TARGET_HAS_MEMORY_BSWAP
For now, defined universally as true, since we previously required backends to implement swapped memory operations. Future patches may now remove that support where it is onerous. Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
6498594c8e
commit
e1dcf3529d
|
@ -137,6 +137,7 @@ typedef enum {
|
||||||
#define TCG_TARGET_HAS_mul_vec 1
|
#define TCG_TARGET_HAS_mul_vec 1
|
||||||
|
|
||||||
#define TCG_TARGET_DEFAULT_MO (0)
|
#define TCG_TARGET_DEFAULT_MO (0)
|
||||||
|
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
|
||||||
|
|
||||||
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
|
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
|
||||||
{
|
{
|
||||||
|
|
|
@ -131,6 +131,7 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TCG_TARGET_DEFAULT_MO (0)
|
#define TCG_TARGET_DEFAULT_MO (0)
|
||||||
|
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
|
||||||
|
|
||||||
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
|
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
|
||||||
{
|
{
|
||||||
|
|
|
@ -220,6 +220,8 @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
|
||||||
|
|
||||||
#define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
|
#define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
|
||||||
|
|
||||||
|
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
|
||||||
|
|
||||||
#ifdef CONFIG_SOFTMMU
|
#ifdef CONFIG_SOFTMMU
|
||||||
#define TCG_TARGET_NEED_LDST_LABELS
|
#define TCG_TARGET_NEED_LDST_LABELS
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -203,6 +203,7 @@ extern bool use_mips32r2_instructions;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TCG_TARGET_DEFAULT_MO (0)
|
#define TCG_TARGET_DEFAULT_MO (0)
|
||||||
|
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
|
||||||
|
|
||||||
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
|
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
|
||||||
{
|
{
|
||||||
|
|
|
@ -128,6 +128,7 @@ void flush_icache_range(uintptr_t start, uintptr_t stop);
|
||||||
void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
|
void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
|
||||||
|
|
||||||
#define TCG_TARGET_DEFAULT_MO (0)
|
#define TCG_TARGET_DEFAULT_MO (0)
|
||||||
|
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
|
||||||
|
|
||||||
#ifdef CONFIG_SOFTMMU
|
#ifdef CONFIG_SOFTMMU
|
||||||
#define TCG_TARGET_NEED_LDST_LABELS
|
#define TCG_TARGET_NEED_LDST_LABELS
|
||||||
|
|
|
@ -135,6 +135,7 @@ extern uint64_t s390_facilities;
|
||||||
#define TCG_TARGET_CALL_STACK_OFFSET 160
|
#define TCG_TARGET_CALL_STACK_OFFSET 160
|
||||||
|
|
||||||
#define TCG_TARGET_EXTEND_ARGS 1
|
#define TCG_TARGET_EXTEND_ARGS 1
|
||||||
|
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
|
||||||
|
|
||||||
#define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
|
#define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
|
||||||
|
|
||||||
|
|
|
@ -164,6 +164,7 @@ extern bool use_vis3_instructions;
|
||||||
#define TCG_AREG0 TCG_REG_I0
|
#define TCG_AREG0 TCG_REG_I0
|
||||||
|
|
||||||
#define TCG_TARGET_DEFAULT_MO (0)
|
#define TCG_TARGET_DEFAULT_MO (0)
|
||||||
|
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
|
||||||
|
|
||||||
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
|
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
|
||||||
{
|
{
|
||||||
|
|
118
tcg/tcg-op.c
118
tcg/tcg-op.c
|
@ -2694,25 +2694,78 @@ static void tcg_gen_req_mo(TCGBar type)
|
||||||
|
|
||||||
void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
||||||
{
|
{
|
||||||
|
TCGMemOp orig_memop;
|
||||||
|
|
||||||
tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
|
tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
|
||||||
memop = tcg_canonicalize_memop(memop, 0, 0);
|
memop = tcg_canonicalize_memop(memop, 0, 0);
|
||||||
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
|
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
|
||||||
addr, trace_mem_get_info(memop, 0));
|
addr, trace_mem_get_info(memop, 0));
|
||||||
|
|
||||||
|
orig_memop = memop;
|
||||||
|
if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
|
||||||
|
memop &= ~MO_BSWAP;
|
||||||
|
/* The bswap primitive requires zero-extended input. */
|
||||||
|
if ((memop & MO_SSIZE) == MO_SW) {
|
||||||
|
memop &= ~MO_SIGN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
|
gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
|
||||||
|
|
||||||
|
if ((orig_memop ^ memop) & MO_BSWAP) {
|
||||||
|
switch (orig_memop & MO_SIZE) {
|
||||||
|
case MO_16:
|
||||||
|
tcg_gen_bswap16_i32(val, val);
|
||||||
|
if (orig_memop & MO_SIGN) {
|
||||||
|
tcg_gen_ext16s_i32(val, val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MO_32:
|
||||||
|
tcg_gen_bswap32_i32(val, val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
||||||
{
|
{
|
||||||
|
TCGv_i32 swap = NULL;
|
||||||
|
|
||||||
tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
|
tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
|
||||||
memop = tcg_canonicalize_memop(memop, 0, 1);
|
memop = tcg_canonicalize_memop(memop, 0, 1);
|
||||||
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
|
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
|
||||||
addr, trace_mem_get_info(memop, 1));
|
addr, trace_mem_get_info(memop, 1));
|
||||||
|
|
||||||
|
if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
|
||||||
|
swap = tcg_temp_new_i32();
|
||||||
|
switch (memop & MO_SIZE) {
|
||||||
|
case MO_16:
|
||||||
|
tcg_gen_ext16u_i32(swap, val);
|
||||||
|
tcg_gen_bswap16_i32(swap, swap);
|
||||||
|
break;
|
||||||
|
case MO_32:
|
||||||
|
tcg_gen_bswap32_i32(swap, val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
val = swap;
|
||||||
|
memop &= ~MO_BSWAP;
|
||||||
|
}
|
||||||
|
|
||||||
gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);
|
gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);
|
||||||
|
|
||||||
|
if (swap) {
|
||||||
|
tcg_temp_free_i32(swap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
||||||
{
|
{
|
||||||
tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
|
TCGMemOp orig_memop;
|
||||||
|
|
||||||
if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
|
if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
|
||||||
tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop);
|
tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop);
|
||||||
if (memop & MO_SIGN) {
|
if (memop & MO_SIGN) {
|
||||||
|
@ -2723,24 +2776,85 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
|
||||||
memop = tcg_canonicalize_memop(memop, 1, 0);
|
memop = tcg_canonicalize_memop(memop, 1, 0);
|
||||||
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
|
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
|
||||||
addr, trace_mem_get_info(memop, 0));
|
addr, trace_mem_get_info(memop, 0));
|
||||||
|
|
||||||
|
orig_memop = memop;
|
||||||
|
if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
|
||||||
|
memop &= ~MO_BSWAP;
|
||||||
|
/* The bswap primitive requires zero-extended input. */
|
||||||
|
if ((memop & MO_SIGN) && (memop & MO_SIZE) < MO_64) {
|
||||||
|
memop &= ~MO_SIGN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx);
|
gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx);
|
||||||
|
|
||||||
|
if ((orig_memop ^ memop) & MO_BSWAP) {
|
||||||
|
switch (orig_memop & MO_SIZE) {
|
||||||
|
case MO_16:
|
||||||
|
tcg_gen_bswap16_i64(val, val);
|
||||||
|
if (orig_memop & MO_SIGN) {
|
||||||
|
tcg_gen_ext16s_i64(val, val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MO_32:
|
||||||
|
tcg_gen_bswap32_i64(val, val);
|
||||||
|
if (orig_memop & MO_SIGN) {
|
||||||
|
tcg_gen_ext32s_i64(val, val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MO_64:
|
||||||
|
tcg_gen_bswap64_i64(val, val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
|
||||||
{
|
{
|
||||||
tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
|
TCGv_i64 swap = NULL;
|
||||||
|
|
||||||
if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
|
if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
|
||||||
tcg_gen_qemu_st_i32(TCGV_LOW(val), addr, idx, memop);
|
tcg_gen_qemu_st_i32(TCGV_LOW(val), addr, idx, memop);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
|
||||||
memop = tcg_canonicalize_memop(memop, 1, 1);
|
memop = tcg_canonicalize_memop(memop, 1, 1);
|
||||||
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
|
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
|
||||||
addr, trace_mem_get_info(memop, 1));
|
addr, trace_mem_get_info(memop, 1));
|
||||||
|
|
||||||
|
if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
|
||||||
|
swap = tcg_temp_new_i64();
|
||||||
|
switch (memop & MO_SIZE) {
|
||||||
|
case MO_16:
|
||||||
|
tcg_gen_ext16u_i64(swap, val);
|
||||||
|
tcg_gen_bswap16_i64(swap, swap);
|
||||||
|
break;
|
||||||
|
case MO_32:
|
||||||
|
tcg_gen_ext32u_i64(swap, val);
|
||||||
|
tcg_gen_bswap32_i64(swap, swap);
|
||||||
|
break;
|
||||||
|
case MO_64:
|
||||||
|
tcg_gen_bswap64_i64(swap, val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
val = swap;
|
||||||
|
memop &= ~MO_BSWAP;
|
||||||
|
}
|
||||||
|
|
||||||
gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx);
|
gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx);
|
||||||
|
|
||||||
|
if (swap) {
|
||||||
|
tcg_temp_free_i64(swap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, TCGMemOp opc)
|
static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, TCGMemOp opc)
|
||||||
|
|
|
@ -198,6 +198,8 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
|
||||||
We prefer consistency across hosts on this. */
|
We prefer consistency across hosts on this. */
|
||||||
#define TCG_TARGET_DEFAULT_MO (0)
|
#define TCG_TARGET_DEFAULT_MO (0)
|
||||||
|
|
||||||
|
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
|
||||||
|
|
||||||
static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
|
static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
|
||||||
uintptr_t jmp_addr, uintptr_t addr)
|
uintptr_t jmp_addr, uintptr_t addr)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue