302 changes: 180 additions & 122 deletions tcg/ppc/tcg-target.c.inc

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion tcg/ppc/tcg-target.h
Expand Up @@ -149,6 +149,9 @@ extern bool have_vsx;
#define TCG_TARGET_HAS_mulsh_i64 1
#endif

#define TCG_TARGET_HAS_qemu_ldst_i128 \
(TCG_TARGET_REG_BITS == 64 && have_isa_2_07)

/*
* While technically Altivec could support V64, it has no 64-bit store
* instruction and substituting two 32-bit stores makes the generated
Expand Down Expand Up @@ -179,7 +182,6 @@ extern bool have_vsx;
#define TCG_TARGET_HAS_cmpsel_vec 0

#define TCG_TARGET_DEFAULT_MO (0)
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
#define TCG_TARGET_NEED_LDST_LABELS
#define TCG_TARGET_NEED_POOL_LABELS

Expand Down
161 changes: 57 additions & 104 deletions tcg/riscv/tcg-target.c.inc
Expand Up @@ -846,56 +846,18 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
* Load/store and TLB
*/

#if defined(CONFIG_SOFTMMU)
/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
* MemOpIdx oi, uintptr_t ra)
*/
static void * const qemu_ld_helpers[MO_SSIZE + 1] = {
[MO_UB] = helper_ret_ldub_mmu,
[MO_SB] = helper_ret_ldsb_mmu,
#if HOST_BIG_ENDIAN
[MO_UW] = helper_be_lduw_mmu,
[MO_SW] = helper_be_ldsw_mmu,
[MO_UL] = helper_be_ldul_mmu,
#if TCG_TARGET_REG_BITS == 64
[MO_SL] = helper_be_ldsl_mmu,
#endif
[MO_UQ] = helper_be_ldq_mmu,
#else
[MO_UW] = helper_le_lduw_mmu,
[MO_SW] = helper_le_ldsw_mmu,
[MO_UL] = helper_le_ldul_mmu,
#if TCG_TARGET_REG_BITS == 64
[MO_SL] = helper_le_ldsl_mmu,
#endif
[MO_UQ] = helper_le_ldq_mmu,
#endif
};

/* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr,
* uintxx_t val, MemOpIdx oi,
* uintptr_t ra)
*/
static void * const qemu_st_helpers[MO_SIZE + 1] = {
[MO_8] = helper_ret_stb_mmu,
#if HOST_BIG_ENDIAN
[MO_16] = helper_be_stw_mmu,
[MO_32] = helper_be_stl_mmu,
[MO_64] = helper_be_stq_mmu,
#else
[MO_16] = helper_le_stw_mmu,
[MO_32] = helper_le_stl_mmu,
[MO_64] = helper_le_stq_mmu,
#endif
};

static void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
{
tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, 0);
bool ok = reloc_jimm20(s->code_ptr - 1, target);
tcg_debug_assert(ok);
}

bool tcg_target_has_memory_bswap(MemOp memop)
{
return false;
}

/* We have three temps, we might as well expose them. */
static const TCGLdstHelperParam ldst_helper_param = {
.ntmp = 3, .tmp = { TCG_REG_TMP0, TCG_REG_TMP1, TCG_REG_TMP2 }
Expand Down Expand Up @@ -935,34 +897,6 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
tcg_out_goto(s, l->raddr);
return true;
}
#else
static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l)
{
/* resolve label address */
if (!reloc_sbimm12(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) {
return false;
}

tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_A1, l->addrlo_reg);
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0);

/* tail call, with the return address back inline. */
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RA, (uintptr_t)l->raddr);
tcg_out_call_int(s, (const void *)(l->is_ld ? helper_unaligned_ld
: helper_unaligned_st), true);
return true;
}

static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
return tcg_out_fail_alignment(s, l);
}

static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
return tcg_out_fail_alignment(s, l);
}
#endif /* CONFIG_SOFTMMU */

/*
* For softmmu, perform the TLB load and compare.
Expand All @@ -976,17 +910,21 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, TCGReg *pbase,
{
TCGLabelQemuLdst *ldst = NULL;
MemOp opc = get_memop(oi);
unsigned a_bits = get_alignment_bits(opc);
unsigned a_mask = (1u << a_bits) - 1;
TCGAtomAlign aa;
unsigned a_mask;

aa = atom_and_align_for_opc(s, opc, MO_ATOM_IFALIGN, false);
a_mask = (1u << aa.align) - 1;

#ifdef CONFIG_SOFTMMU
unsigned s_bits = opc & MO_SIZE;
unsigned s_mask = (1u << s_bits) - 1;
int mem_index = get_mmuidx(oi);
int fast_ofs = TLB_MASK_TABLE_OFS(mem_index);
int mask_ofs = fast_ofs + offsetof(CPUTLBDescFast, mask);
int table_ofs = fast_ofs + offsetof(CPUTLBDescFast, table);
TCGReg mask_base = TCG_AREG0, table_base = TCG_AREG0;
tcg_target_long compare_mask;
int compare_mask;
TCGReg addr_adj;

ldst = new_ldst_label(s);
ldst->is_ld = is_ld;
Expand All @@ -995,44 +933,51 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, TCGReg *pbase,

QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) > 0);
QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -(1 << 11));
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, mask_base, mask_ofs);
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, table_base, table_ofs);
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_AREG0, mask_ofs);
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, table_ofs);

tcg_out_opc_imm(s, OPC_SRLI, TCG_REG_TMP2, addr_reg,
TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
s->page_bits - CPU_TLB_ENTRY_BITS);
tcg_out_opc_reg(s, OPC_AND, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP0);
tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP1);

/*
* For aligned accesses, we check the first byte and include the alignment
* bits within the address. For unaligned access, we check that we don't
* cross pages using the address of the last byte of the access.
*/
addr_adj = addr_reg;
if (a_mask < s_mask) {
addr_adj = TCG_REG_TMP0;
tcg_out_opc_imm(s, TARGET_LONG_BITS == 32 ? OPC_ADDIW : OPC_ADDI,
addr_adj, addr_reg, s_mask - a_mask);
}
compare_mask = s->page_mask | a_mask;
if (compare_mask == sextreg(compare_mask, 0, 12)) {
tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP1, addr_adj, compare_mask);
} else {
tcg_out_movi(s, TCG_TYPE_TL, TCG_REG_TMP1, compare_mask);
tcg_out_opc_reg(s, OPC_AND, TCG_REG_TMP1, TCG_REG_TMP1, addr_adj);
}

/* Load the tlb comparator and the addend. */
tcg_out_ld(s, TCG_TYPE_TL, TCG_REG_TMP0, TCG_REG_TMP2,
is_ld ? offsetof(CPUTLBEntry, addr_read)
: offsetof(CPUTLBEntry, addr_write));
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP2, TCG_REG_TMP2,
offsetof(CPUTLBEntry, addend));

/* We don't support unaligned accesses. */
if (a_bits < s_bits) {
a_bits = s_bits;
}
/* Clear the non-page, non-alignment bits from the address. */
compare_mask = (tcg_target_long)TARGET_PAGE_MASK | a_mask;
if (compare_mask == sextreg(compare_mask, 0, 12)) {
tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP1, addr_reg, compare_mask);
} else {
tcg_out_movi(s, TCG_TYPE_TL, TCG_REG_TMP1, compare_mask);
tcg_out_opc_reg(s, OPC_AND, TCG_REG_TMP1, TCG_REG_TMP1, addr_reg);
}

/* Compare masked address with the TLB entry. */
ldst->label_ptr[0] = s->code_ptr;
tcg_out_opc_branch(s, OPC_BNE, TCG_REG_TMP0, TCG_REG_TMP1, 0);

/* TLB Hit - translate address using addend. */
addr_adj = addr_reg;
if (TARGET_LONG_BITS == 32) {
tcg_out_ext32u(s, TCG_REG_TMP0, addr_reg);
addr_reg = TCG_REG_TMP0;
addr_adj = TCG_REG_TMP0;
tcg_out_ext32u(s, addr_adj, addr_reg);
}
tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_REG_TMP2, addr_reg);
tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_REG_TMP2, addr_adj);
*pbase = TCG_REG_TMP0;
#else
if (a_mask) {
Expand All @@ -1041,8 +986,8 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, TCGReg *pbase,
ldst->oi = oi;
ldst->addrlo_reg = addr_reg;

/* We are expecting a_bits max 7, so we can always use andi. */
tcg_debug_assert(a_bits < 12);
/* We are expecting alignment max 7, so we can always use andi. */
tcg_debug_assert(a_mask == sextreg(a_mask, 0, 12));
tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP1, addr_reg, a_mask);

ldst->label_ptr[0] = s->code_ptr;
Expand Down Expand Up @@ -1437,16 +1382,20 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
tcg_out_setcond(s, args[3], a0, a1, a2);
break;

case INDEX_op_qemu_ld_i32:
case INDEX_op_qemu_ld_a32_i32:
case INDEX_op_qemu_ld_a64_i32:
tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I32);
break;
case INDEX_op_qemu_ld_i64:
case INDEX_op_qemu_ld_a32_i64:
case INDEX_op_qemu_ld_a64_i64:
tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I64);
break;
case INDEX_op_qemu_st_i32:
case INDEX_op_qemu_st_a32_i32:
case INDEX_op_qemu_st_a64_i32:
tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I32);
break;
case INDEX_op_qemu_st_i64:
case INDEX_op_qemu_st_a32_i64:
case INDEX_op_qemu_st_a64_i64:
tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I64);
break;

Expand Down Expand Up @@ -1588,11 +1537,15 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_sub2_i64:
return C_O2_I4(r, r, rZ, rZ, rM, rM);

case INDEX_op_qemu_ld_i32:
case INDEX_op_qemu_ld_i64:
case INDEX_op_qemu_ld_a32_i32:
case INDEX_op_qemu_ld_a64_i32:
case INDEX_op_qemu_ld_a32_i64:
case INDEX_op_qemu_ld_a64_i64:
return C_O1_I1(r, r);
case INDEX_op_qemu_st_i32:
case INDEX_op_qemu_st_i64:
case INDEX_op_qemu_st_a32_i32:
case INDEX_op_qemu_st_a64_i32:
case INDEX_op_qemu_st_a32_i64:
case INDEX_op_qemu_st_a64_i64:
return C_O0_I2(rZ, r);

default:
Expand Down
4 changes: 2 additions & 2 deletions tcg/riscv/tcg-target.h
Expand Up @@ -163,11 +163,11 @@ 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
#define TCG_TARGET_NEED_POOL_LABELS

#define TCG_TARGET_HAS_MEMORY_BSWAP 0

#endif
2 changes: 2 additions & 0 deletions tcg/s390x/tcg-target-con-set.h
Expand Up @@ -14,6 +14,7 @@ C_O0_I2(r, r)
C_O0_I2(r, ri)
C_O0_I2(r, rA)
C_O0_I2(v, r)
C_O0_I3(o, m, r)
C_O1_I1(r, r)
C_O1_I1(v, r)
C_O1_I1(v, v)
Expand All @@ -36,6 +37,7 @@ C_O1_I2(v, v, v)
C_O1_I3(v, v, v, v)
C_O1_I4(r, r, ri, rI, r)
C_O1_I4(r, r, rA, rI, r)
C_O2_I1(o, m, r)
C_O2_I2(o, m, 0, r)
C_O2_I2(o, m, r, r)
C_O2_I3(o, m, 0, 1, r)
Expand Down
207 changes: 134 additions & 73 deletions tcg/s390x/tcg-target.c.inc
Expand Up @@ -243,6 +243,7 @@ typedef enum S390Opcode {
RXY_LLGF = 0xe316,
RXY_LLGH = 0xe391,
RXY_LMG = 0xeb04,
RXY_LPQ = 0xe38f,
RXY_LRV = 0xe31e,
RXY_LRVG = 0xe30f,
RXY_LRVH = 0xe31f,
Expand All @@ -253,6 +254,7 @@ typedef enum S390Opcode {
RXY_STG = 0xe324,
RXY_STHY = 0xe370,
RXY_STMG = 0xeb24,
RXY_STPQ = 0xe38e,
RXY_STRV = 0xe33e,
RXY_STRVG = 0xe32f,
RXY_STRVH = 0xe33f,
Expand Down Expand Up @@ -438,33 +440,6 @@ static const uint8_t tcg_cond_to_ltr_cond[] = {
[TCG_COND_GEU] = S390_CC_ALWAYS,
};

#ifdef CONFIG_SOFTMMU
static void * const qemu_ld_helpers[(MO_SSIZE | MO_BSWAP) + 1] = {
[MO_UB] = helper_ret_ldub_mmu,
[MO_SB] = helper_ret_ldsb_mmu,
[MO_LEUW] = helper_le_lduw_mmu,
[MO_LESW] = helper_le_ldsw_mmu,
[MO_LEUL] = helper_le_ldul_mmu,
[MO_LESL] = helper_le_ldsl_mmu,
[MO_LEUQ] = helper_le_ldq_mmu,
[MO_BEUW] = helper_be_lduw_mmu,
[MO_BESW] = helper_be_ldsw_mmu,
[MO_BEUL] = helper_be_ldul_mmu,
[MO_BESL] = helper_be_ldsl_mmu,
[MO_BEUQ] = helper_be_ldq_mmu,
};

static void * const qemu_st_helpers[(MO_SIZE | MO_BSWAP) + 1] = {
[MO_UB] = helper_ret_stb_mmu,
[MO_LEUW] = helper_le_stw_mmu,
[MO_LEUL] = helper_le_stl_mmu,
[MO_LEUQ] = helper_le_stq_mmu,
[MO_BEUW] = helper_be_stw_mmu,
[MO_BEUL] = helper_be_stl_mmu,
[MO_BEUQ] = helper_be_stq_mmu,
};
#endif

static const tcg_insn_unit *tb_ret_addr;
uint64_t s390_facilities[3];

Expand Down Expand Up @@ -1599,8 +1574,25 @@ typedef struct {
TCGReg base;
TCGReg index;
int disp;
TCGAtomAlign aa;
} HostAddress;

bool tcg_target_has_memory_bswap(MemOp memop)
{
TCGAtomAlign aa;

if ((memop & MO_SIZE) <= MO_64) {
return true;
}

/*
* Reject 16-byte memop with 16-byte atomicity,
* but do allow a pair of 64-bit operations.
*/
aa = atom_and_align_for_opc(tcg_ctx, memop, MO_ATOM_IFALIGN, true);
return aa.atom <= MO_64;
}

static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg data,
HostAddress h)
{
Expand Down Expand Up @@ -1706,7 +1698,6 @@ static void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg data,
}
}

#if defined(CONFIG_SOFTMMU)
static const TCGLdstHelperParam ldst_helper_param = {
.ntmp = 1, .tmp = { TCG_TMP0 }
};
Expand All @@ -1721,7 +1712,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
}

tcg_out_ld_helper_args(s, lb, &ldst_helper_param);
tcg_out_call_int(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]);
tcg_out_call_int(s, qemu_ld_helpers[opc & MO_SIZE]);
tcg_out_ld_helper_ret(s, lb, false, &ldst_helper_param);

tgen_gotoi(s, S390_CC_ALWAYS, lb->raddr);
Expand All @@ -1738,39 +1729,11 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
}

tcg_out_st_helper_args(s, lb, &ldst_helper_param);
tcg_out_call_int(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]);
tcg_out_call_int(s, qemu_st_helpers[opc & MO_SIZE]);

tgen_gotoi(s, S390_CC_ALWAYS, lb->raddr);
return true;
}
#else
static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l)
{
if (!patch_reloc(l->label_ptr[0], R_390_PC16DBL,
(intptr_t)tcg_splitwx_to_rx(s->code_ptr), 2)) {
return false;
}

tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_R3, l->addrlo_reg);
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R2, TCG_AREG0);

/* "Tail call" to the helper, with the return address back inline. */
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R14, (uintptr_t)l->raddr);
tgen_gotoi(s, S390_CC_ALWAYS, (const void *)(l->is_ld ? helper_unaligned_ld
: helper_unaligned_st));
return true;
}

static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
return tcg_out_fail_alignment(s, l);
}

static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
return tcg_out_fail_alignment(s, l);
}
#endif /* CONFIG_SOFTMMU */

/*
* For softmmu, perform the TLB load and compare.
Expand All @@ -1784,11 +1747,13 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
{
TCGLabelQemuLdst *ldst = NULL;
MemOp opc = get_memop(oi);
unsigned a_bits = get_alignment_bits(opc);
unsigned a_mask = (1u << a_bits) - 1;
MemOp s_bits = opc & MO_SIZE;
unsigned a_mask;

h->aa = atom_and_align_for_opc(s, opc, MO_ATOM_IFALIGN, s_bits == MO_128);
a_mask = (1 << h->aa.align) - 1;

#ifdef CONFIG_SOFTMMU
unsigned s_bits = opc & MO_SIZE;
unsigned s_mask = (1 << s_bits) - 1;
int mem_index = get_mmuidx(oi);
int fast_off = TLB_MASK_TABLE_OFS(mem_index);
Expand All @@ -1803,7 +1768,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
ldst->addrlo_reg = addr_reg;

tcg_out_sh64(s, RSY_SRLG, TCG_TMP0, addr_reg, TCG_REG_NONE,
TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
s->page_bits - CPU_TLB_ENTRY_BITS);

QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) > 0);
QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -(1 << 19));
Expand All @@ -1815,8 +1780,8 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
* bits within the address. For unaligned access, we check that we don't
* cross pages using the address of the last byte of the access.
*/
a_off = (a_bits >= s_bits ? 0 : s_mask - a_mask);
tlb_mask = (uint64_t)TARGET_PAGE_MASK | a_mask;
a_off = (a_mask >= s_mask ? 0 : s_mask - a_mask);
tlb_mask = (uint64_t)s->page_mask | a_mask;
if (a_off == 0) {
tgen_andi_risbg(s, TCG_REG_R0, addr_reg, tlb_mask);
} else {
Expand Down Expand Up @@ -1857,7 +1822,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
ldst->addrlo_reg = addr_reg;

/* We are expecting a_bits to max out at 7, much lower than TMLL. */
tcg_debug_assert(a_bits < 16);
tcg_debug_assert(a_mask <= 0xffff);
tcg_out_insn(s, RI, TMLL, addr_reg, a_mask);

tcg_out16(s, RI_BRC | (7 << 4)); /* CC in {1,2,3} */
Expand Down Expand Up @@ -1913,6 +1878,80 @@ static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg,
}
}

static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg datalo, TCGReg datahi,
TCGReg addr_reg, MemOpIdx oi, bool is_ld)
{
TCGLabel *l1 = NULL, *l2 = NULL;
TCGLabelQemuLdst *ldst;
HostAddress h;
bool need_bswap;
bool use_pair;
S390Opcode insn;

ldst = prepare_host_addr(s, &h, addr_reg, oi, is_ld);

use_pair = h.aa.atom < MO_128;
need_bswap = get_memop(oi) & MO_BSWAP;

if (!use_pair) {
/*
* Atomicity requires we use LPQ. If we've already checked for
* 16-byte alignment, that's all we need. If we arrive with
* lesser alignment, we have determined that less than 16-byte
* alignment can be satisfied with two 8-byte loads.
*/
if (h.aa.align < MO_128) {
use_pair = true;
l1 = gen_new_label();
l2 = gen_new_label();

tcg_out_insn(s, RI, TMLL, addr_reg, 15);
tgen_branch(s, 7, l1); /* CC in {1,2,3} */
}

tcg_debug_assert(!need_bswap);
tcg_debug_assert(datalo & 1);
tcg_debug_assert(datahi == datalo - 1);
insn = is_ld ? RXY_LPQ : RXY_STPQ;
tcg_out_insn_RXY(s, insn, datahi, h.base, h.index, h.disp);

if (use_pair) {
tgen_branch(s, S390_CC_ALWAYS, l2);
tcg_out_label(s, l1);
}
}
if (use_pair) {
TCGReg d1, d2;

if (need_bswap) {
d1 = datalo, d2 = datahi;
insn = is_ld ? RXY_LRVG : RXY_STRVG;
} else {
d1 = datahi, d2 = datalo;
insn = is_ld ? RXY_LG : RXY_STG;
}

if (h.base == d1 || h.index == d1) {
tcg_out_insn(s, RXY, LAY, TCG_TMP0, h.base, h.index, h.disp);
h.base = TCG_TMP0;
h.index = TCG_REG_NONE;
h.disp = 0;
}
tcg_out_insn_RXY(s, insn, d1, h.base, h.index, h.disp);
tcg_out_insn_RXY(s, insn, d2, h.base, h.index, h.disp + 8);
}
if (l2) {
tcg_out_label(s, l2);
}

if (ldst) {
ldst->type = TCG_TYPE_I128;
ldst->datalo_reg = datalo;
ldst->datahi_reg = datahi;
ldst->raddr = tcg_splitwx_to_rx(s->code_ptr);
}
}

static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
{
/* Reuse the zeroing that exists for goto_ptr. */
Expand Down Expand Up @@ -2258,18 +2297,30 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
args[2], const_args[2], args[3], const_args[3], args[4]);
break;

case INDEX_op_qemu_ld_i32:
case INDEX_op_qemu_ld_a32_i32:
case INDEX_op_qemu_ld_a64_i32:
tcg_out_qemu_ld(s, args[0], args[1], args[2], TCG_TYPE_I32);
break;
case INDEX_op_qemu_ld_i64:
case INDEX_op_qemu_ld_a32_i64:
case INDEX_op_qemu_ld_a64_i64:
tcg_out_qemu_ld(s, args[0], args[1], args[2], TCG_TYPE_I64);
break;
case INDEX_op_qemu_st_i32:
case INDEX_op_qemu_st_a32_i32:
case INDEX_op_qemu_st_a64_i32:
tcg_out_qemu_st(s, args[0], args[1], args[2], TCG_TYPE_I32);
break;
case INDEX_op_qemu_st_i64:
case INDEX_op_qemu_st_a32_i64:
case INDEX_op_qemu_st_a64_i64:
tcg_out_qemu_st(s, args[0], args[1], args[2], TCG_TYPE_I64);
break;
case INDEX_op_qemu_ld_a32_i128:
case INDEX_op_qemu_ld_a64_i128:
tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], true);
break;
case INDEX_op_qemu_st_a32_i128:
case INDEX_op_qemu_st_a64_i128:
tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false);
break;

case INDEX_op_ld16s_i64:
tcg_out_mem(s, 0, RXY_LGH, args[0], args[1], TCG_REG_NONE, args[2]);
Expand Down Expand Up @@ -3141,12 +3192,22 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_ctpop_i64:
return C_O1_I1(r, r);

case INDEX_op_qemu_ld_i32:
case INDEX_op_qemu_ld_i64:
case INDEX_op_qemu_ld_a32_i32:
case INDEX_op_qemu_ld_a64_i32:
case INDEX_op_qemu_ld_a32_i64:
case INDEX_op_qemu_ld_a64_i64:
return C_O1_I1(r, r);
case INDEX_op_qemu_st_i64:
case INDEX_op_qemu_st_i32:
case INDEX_op_qemu_st_a32_i64:
case INDEX_op_qemu_st_a64_i64:
case INDEX_op_qemu_st_a32_i32:
case INDEX_op_qemu_st_a64_i32:
return C_O0_I2(r, r);
case INDEX_op_qemu_ld_a32_i128:
case INDEX_op_qemu_ld_a64_i128:
return C_O2_I1(o, m, r);
case INDEX_op_qemu_st_a32_i128:
case INDEX_op_qemu_st_a64_i128:
return C_O0_I3(o, m, r);

case INDEX_op_deposit_i32:
case INDEX_op_deposit_i64:
Expand Down
4 changes: 2 additions & 2 deletions tcg/s390x/tcg-target.h
Expand Up @@ -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 1

#define TCG_TARGET_HAS_v64 HAVE_FACILITY(VECTOR)
#define TCG_TARGET_HAS_v128 HAVE_FACILITY(VECTOR)
#define TCG_TARGET_HAS_v256 0
Expand Down Expand Up @@ -172,8 +174,6 @@ extern uint64_t s390_facilities[3];
#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_BY_REF
#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_BY_REF

#define TCG_TARGET_HAS_MEMORY_BSWAP 1

#define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
#define TCG_TARGET_NEED_LDST_LABELS
#define TCG_TARGET_NEED_POOL_LABELS
Expand Down
2 changes: 0 additions & 2 deletions tcg/sparc64/tcg-target-con-set.h
Expand Up @@ -12,8 +12,6 @@
C_O0_I1(r)
C_O0_I2(rZ, r)
C_O0_I2(rZ, rJ)
C_O0_I2(sZ, s)
C_O1_I1(r, s)
C_O1_I1(r, r)
C_O1_I2(r, r, r)
C_O1_I2(r, rZ, rJ)
Expand Down
1 change: 0 additions & 1 deletion tcg/sparc64/tcg-target-con-str.h
Expand Up @@ -9,7 +9,6 @@
* REGS(letter, register_mask)
*/
REGS('r', ALL_GENERAL_REGS)
REGS('s', ALL_QLDST_REGS)

/*
* Define constraint letters for constants:
Expand Down
717 changes: 232 additions & 485 deletions tcg/sparc64/tcg-target.c.inc

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion tcg/sparc64/tcg-target.h
Expand Up @@ -151,10 +151,12 @@ 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)
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
#define TCG_TARGET_NEED_LDST_LABELS
#define TCG_TARGET_NEED_POOL_LABELS

#endif
2 changes: 2 additions & 0 deletions tcg/tcg-internal.h
Expand Up @@ -126,4 +126,6 @@ static inline TCGv_i64 TCGV128_HIGH(TCGv_i128 t)
return temp_tcgv_i64(tcgv_i128_temp(t) + o);
}

bool tcg_target_has_memory_bswap(MemOp memop);

#endif /* TCG_INTERNAL_H */
1,234 changes: 1,234 additions & 0 deletions tcg/tcg-op-ldst.c

Large diffs are not rendered by default.

864 changes: 0 additions & 864 deletions tcg/tcg-op.c

Large diffs are not rendered by default.

627 changes: 504 additions & 123 deletions tcg/tcg.c

Large diffs are not rendered by default.

243 changes: 81 additions & 162 deletions tcg/tci.c
Expand Up @@ -286,162 +286,54 @@ static bool tci_compare64(uint64_t u0, uint64_t u1, TCGCond condition)
return result;
}

static uint64_t tci_qemu_ld(CPUArchState *env, target_ulong taddr,
static uint64_t tci_qemu_ld(CPUArchState *env, uint64_t taddr,
MemOpIdx oi, const void *tb_ptr)
{
MemOp mop = get_memop(oi);
uintptr_t ra = (uintptr_t)tb_ptr;

#ifdef CONFIG_SOFTMMU
switch (mop & (MO_BSWAP | MO_SSIZE)) {
switch (mop & MO_SSIZE) {
case MO_UB:
return helper_ret_ldub_mmu(env, taddr, oi, ra);
return helper_ldub_mmu(env, taddr, oi, ra);
case MO_SB:
return helper_ret_ldsb_mmu(env, taddr, oi, ra);
case MO_LEUW:
return helper_le_lduw_mmu(env, taddr, oi, ra);
case MO_LESW:
return helper_le_ldsw_mmu(env, taddr, oi, ra);
case MO_LEUL:
return helper_le_ldul_mmu(env, taddr, oi, ra);
case MO_LESL:
return helper_le_ldsl_mmu(env, taddr, oi, ra);
case MO_LEUQ:
return helper_le_ldq_mmu(env, taddr, oi, ra);
case MO_BEUW:
return helper_be_lduw_mmu(env, taddr, oi, ra);
case MO_BESW:
return helper_be_ldsw_mmu(env, taddr, oi, ra);
case MO_BEUL:
return helper_be_ldul_mmu(env, taddr, oi, ra);
case MO_BESL:
return helper_be_ldsl_mmu(env, taddr, oi, ra);
case MO_BEUQ:
return helper_be_ldq_mmu(env, taddr, oi, ra);
return helper_ldsb_mmu(env, taddr, oi, ra);
case MO_UW:
return helper_lduw_mmu(env, taddr, oi, ra);
case MO_SW:
return helper_ldsw_mmu(env, taddr, oi, ra);
case MO_UL:
return helper_ldul_mmu(env, taddr, oi, ra);
case MO_SL:
return helper_ldsl_mmu(env, taddr, oi, ra);
case MO_UQ:
return helper_ldq_mmu(env, taddr, oi, ra);
default:
g_assert_not_reached();
}
#else
void *haddr = g2h(env_cpu(env), taddr);
unsigned a_mask = (1u << get_alignment_bits(mop)) - 1;
uint64_t ret;

set_helper_retaddr(ra);
if (taddr & a_mask) {
helper_unaligned_ld(env, taddr);
}
switch (mop & (MO_BSWAP | MO_SSIZE)) {
case MO_UB:
ret = ldub_p(haddr);
break;
case MO_SB:
ret = ldsb_p(haddr);
break;
case MO_LEUW:
ret = lduw_le_p(haddr);
break;
case MO_LESW:
ret = ldsw_le_p(haddr);
break;
case MO_LEUL:
ret = (uint32_t)ldl_le_p(haddr);
break;
case MO_LESL:
ret = (int32_t)ldl_le_p(haddr);
break;
case MO_LEUQ:
ret = ldq_le_p(haddr);
break;
case MO_BEUW:
ret = lduw_be_p(haddr);
break;
case MO_BESW:
ret = ldsw_be_p(haddr);
break;
case MO_BEUL:
ret = (uint32_t)ldl_be_p(haddr);
break;
case MO_BESL:
ret = (int32_t)ldl_be_p(haddr);
break;
case MO_BEUQ:
ret = ldq_be_p(haddr);
break;
default:
g_assert_not_reached();
}
clear_helper_retaddr();
return ret;
#endif
}

static void tci_qemu_st(CPUArchState *env, target_ulong taddr, uint64_t val,
static void tci_qemu_st(CPUArchState *env, uint64_t taddr, uint64_t val,
MemOpIdx oi, const void *tb_ptr)
{
MemOp mop = get_memop(oi);
uintptr_t ra = (uintptr_t)tb_ptr;

#ifdef CONFIG_SOFTMMU
switch (mop & (MO_BSWAP | MO_SIZE)) {
switch (mop & MO_SIZE) {
case MO_UB:
helper_ret_stb_mmu(env, taddr, val, oi, ra);
helper_stb_mmu(env, taddr, val, oi, ra);
break;
case MO_LEUW:
helper_le_stw_mmu(env, taddr, val, oi, ra);
case MO_UW:
helper_stw_mmu(env, taddr, val, oi, ra);
break;
case MO_LEUL:
helper_le_stl_mmu(env, taddr, val, oi, ra);
case MO_UL:
helper_stl_mmu(env, taddr, val, oi, ra);
break;
case MO_LEUQ:
helper_le_stq_mmu(env, taddr, val, oi, ra);
break;
case MO_BEUW:
helper_be_stw_mmu(env, taddr, val, oi, ra);
break;
case MO_BEUL:
helper_be_stl_mmu(env, taddr, val, oi, ra);
break;
case MO_BEUQ:
helper_be_stq_mmu(env, taddr, val, oi, ra);
case MO_UQ:
helper_stq_mmu(env, taddr, val, oi, ra);
break;
default:
g_assert_not_reached();
}
#else
void *haddr = g2h(env_cpu(env), taddr);
unsigned a_mask = (1u << get_alignment_bits(mop)) - 1;

set_helper_retaddr(ra);
if (taddr & a_mask) {
helper_unaligned_st(env, taddr);
}
switch (mop & (MO_BSWAP | MO_SIZE)) {
case MO_UB:
stb_p(haddr, val);
break;
case MO_LEUW:
stw_le_p(haddr, val);
break;
case MO_LEUL:
stl_le_p(haddr, val);
break;
case MO_LEUQ:
stq_le_p(haddr, val);
break;
case MO_BEUW:
stw_be_p(haddr, val);
break;
case MO_BEUL:
stl_be_p(haddr, val);
break;
case MO_BEUQ:
stq_be_p(haddr, val);
break;
default:
g_assert_not_reached();
}
clear_helper_retaddr();
#endif
}

#if TCG_TARGET_REG_BITS == 64
Expand Down Expand Up @@ -480,10 +372,9 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
TCGReg r0, r1, r2, r3, r4, r5;
tcg_target_ulong t1;
TCGCond condition;
target_ulong taddr;
uint8_t pos, len;
uint32_t tmp32;
uint64_t tmp64;
uint64_t tmp64, taddr;
uint64_t T1, T2;
MemOpIdx oi;
int32_t ofs;
Expand Down Expand Up @@ -1030,30 +921,41 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
tb_ptr = ptr;
break;

case INDEX_op_qemu_ld_i32:
if (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS) {
case INDEX_op_qemu_ld_a32_i32:
tci_args_rrm(insn, &r0, &r1, &oi);
taddr = (uint32_t)regs[r1];
goto do_ld_i32;
case INDEX_op_qemu_ld_a64_i32:
if (TCG_TARGET_REG_BITS == 64) {
tci_args_rrm(insn, &r0, &r1, &oi);
taddr = regs[r1];
} else {
tci_args_rrrm(insn, &r0, &r1, &r2, &oi);
taddr = tci_uint64(regs[r2], regs[r1]);
}
tmp32 = tci_qemu_ld(env, taddr, oi, tb_ptr);
regs[r0] = tmp32;
do_ld_i32:
regs[r0] = tci_qemu_ld(env, taddr, oi, tb_ptr);
break;

case INDEX_op_qemu_ld_i64:
case INDEX_op_qemu_ld_a32_i64:
if (TCG_TARGET_REG_BITS == 64) {
tci_args_rrm(insn, &r0, &r1, &oi);
taddr = regs[r1];
} else if (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS) {
taddr = (uint32_t)regs[r1];
} else {
tci_args_rrrm(insn, &r0, &r1, &r2, &oi);
taddr = regs[r2];
taddr = (uint32_t)regs[r2];
}
goto do_ld_i64;
case INDEX_op_qemu_ld_a64_i64:
if (TCG_TARGET_REG_BITS == 64) {
tci_args_rrm(insn, &r0, &r1, &oi);
taddr = regs[r1];
} else {
tci_args_rrrrr(insn, &r0, &r1, &r2, &r3, &r4);
taddr = tci_uint64(regs[r3], regs[r2]);
oi = regs[r4];
}
do_ld_i64:
tmp64 = tci_qemu_ld(env, taddr, oi, tb_ptr);
if (TCG_TARGET_REG_BITS == 32) {
tci_write_reg64(regs, r1, r0, tmp64);
Expand All @@ -1062,34 +964,45 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
}
break;

case INDEX_op_qemu_st_i32:
if (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS) {
case INDEX_op_qemu_st_a32_i32:
tci_args_rrm(insn, &r0, &r1, &oi);
taddr = (uint32_t)regs[r1];
goto do_st_i32;
case INDEX_op_qemu_st_a64_i32:
if (TCG_TARGET_REG_BITS == 64) {
tci_args_rrm(insn, &r0, &r1, &oi);
taddr = regs[r1];
} else {
tci_args_rrrm(insn, &r0, &r1, &r2, &oi);
taddr = tci_uint64(regs[r2], regs[r1]);
}
tmp32 = regs[r0];
tci_qemu_st(env, taddr, tmp32, oi, tb_ptr);
do_st_i32:
tci_qemu_st(env, taddr, regs[r0], oi, tb_ptr);
break;

case INDEX_op_qemu_st_i64:
case INDEX_op_qemu_st_a32_i64:
if (TCG_TARGET_REG_BITS == 64) {
tci_args_rrm(insn, &r0, &r1, &oi);
taddr = regs[r1];
tmp64 = regs[r0];
taddr = (uint32_t)regs[r1];
} else {
if (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS) {
tci_args_rrrm(insn, &r0, &r1, &r2, &oi);
taddr = regs[r2];
} else {
tci_args_rrrrr(insn, &r0, &r1, &r2, &r3, &r4);
taddr = tci_uint64(regs[r3], regs[r2]);
oi = regs[r4];
}
tci_args_rrrm(insn, &r0, &r1, &r2, &oi);
tmp64 = tci_uint64(regs[r1], regs[r0]);
taddr = (uint32_t)regs[r2];
}
goto do_st_i64;
case INDEX_op_qemu_st_a64_i64:
if (TCG_TARGET_REG_BITS == 64) {
tci_args_rrm(insn, &r0, &r1, &oi);
tmp64 = regs[r0];
taddr = regs[r1];
} else {
tci_args_rrrrr(insn, &r0, &r1, &r2, &r3, &r4);
tmp64 = tci_uint64(regs[r1], regs[r0]);
taddr = tci_uint64(regs[r3], regs[r2]);
oi = regs[r4];
}
do_st_i64:
tci_qemu_st(env, taddr, tmp64, oi, tb_ptr);
break;

Expand Down Expand Up @@ -1359,15 +1272,21 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info)
str_r(r3), str_r(r4), str_r(r5));
break;

case INDEX_op_qemu_ld_i64:
case INDEX_op_qemu_st_i64:
len = DIV_ROUND_UP(64, TCG_TARGET_REG_BITS);
case INDEX_op_qemu_ld_a32_i32:
case INDEX_op_qemu_st_a32_i32:
len = 1 + 1;
goto do_qemu_ldst;
case INDEX_op_qemu_ld_a32_i64:
case INDEX_op_qemu_st_a32_i64:
case INDEX_op_qemu_ld_a64_i32:
case INDEX_op_qemu_st_a64_i32:
len = 1 + DIV_ROUND_UP(64, TCG_TARGET_REG_BITS);
goto do_qemu_ldst;
case INDEX_op_qemu_ld_a64_i64:
case INDEX_op_qemu_st_a64_i64:
len = 2 * DIV_ROUND_UP(64, TCG_TARGET_REG_BITS);
goto do_qemu_ldst;
case INDEX_op_qemu_ld_i32:
case INDEX_op_qemu_st_i32:
len = 1;
do_qemu_ldst:
len += DIV_ROUND_UP(TARGET_LONG_BITS, TCG_TARGET_REG_BITS);
switch (len) {
case 2:
tci_args_rrm(insn, &r0, &r1, &oi);
Expand Down
58 changes: 33 additions & 25 deletions tcg/tci/tcg-target.c.inc
Expand Up @@ -156,22 +156,22 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_setcond2_i32:
return C_O1_I4(r, r, r, r, r);

case INDEX_op_qemu_ld_i32:
return (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS
? C_O1_I1(r, r)
: C_O1_I2(r, r, r));
case INDEX_op_qemu_ld_i64:
return (TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r)
: TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? C_O2_I1(r, r, r)
: C_O2_I2(r, r, r, r));
case INDEX_op_qemu_st_i32:
return (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS
? C_O0_I2(r, r)
: C_O0_I3(r, r, r));
case INDEX_op_qemu_st_i64:
return (TCG_TARGET_REG_BITS == 64 ? C_O0_I2(r, r)
: TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? C_O0_I3(r, r, r)
: C_O0_I4(r, r, r, r));
case INDEX_op_qemu_ld_a32_i32:
return C_O1_I1(r, r);
case INDEX_op_qemu_ld_a64_i32:
return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r) : C_O1_I2(r, r, r);
case INDEX_op_qemu_ld_a32_i64:
return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r) : C_O2_I1(r, r, r);
case INDEX_op_qemu_ld_a64_i64:
return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r) : C_O2_I2(r, r, r, r);
case INDEX_op_qemu_st_a32_i32:
return C_O0_I2(r, r);
case INDEX_op_qemu_st_a64_i32:
return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(r, r) : C_O0_I3(r, r, r);
case INDEX_op_qemu_st_a32_i64:
return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(r, r) : C_O0_I3(r, r, r);
case INDEX_op_qemu_st_a64_i64:
return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(r, r) : C_O0_I4(r, r, r, r);

default:
g_assert_not_reached();
Expand Down Expand Up @@ -243,7 +243,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
return false;
}

static void stack_bounds_check(TCGReg base, target_long offset)
static void stack_bounds_check(TCGReg base, intptr_t offset)
{
if (base == TCG_REG_CALL_STACK) {
tcg_debug_assert(offset >= 0);
Expand Down Expand Up @@ -849,21 +849,24 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
tcg_out_op_rrrr(s, opc, args[0], args[1], args[2], args[3]);
break;

case INDEX_op_qemu_ld_i32:
case INDEX_op_qemu_st_i32:
if (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS) {
case INDEX_op_qemu_ld_a32_i32:
case INDEX_op_qemu_st_a32_i32:
tcg_out_op_rrm(s, opc, args[0], args[1], args[2]);
break;
case INDEX_op_qemu_ld_a64_i32:
case INDEX_op_qemu_st_a64_i32:
case INDEX_op_qemu_ld_a32_i64:
case INDEX_op_qemu_st_a32_i64:
if (TCG_TARGET_REG_BITS == 64) {
tcg_out_op_rrm(s, opc, args[0], args[1], args[2]);
} else {
tcg_out_op_rrrm(s, opc, args[0], args[1], args[2], args[3]);
}
break;

case INDEX_op_qemu_ld_i64:
case INDEX_op_qemu_st_i64:
case INDEX_op_qemu_ld_a64_i64:
case INDEX_op_qemu_st_a64_i64:
if (TCG_TARGET_REG_BITS == 64) {
tcg_out_op_rrm(s, opc, args[0], args[1], args[2]);
} else if (TARGET_LONG_BITS <= TCG_TARGET_REG_BITS) {
tcg_out_op_rrrm(s, opc, args[0], args[1], args[2], args[3]);
} else {
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, args[4]);
tcg_out_op_rrrrr(s, opc, args[0], args[1],
Expand Down Expand Up @@ -963,3 +966,8 @@ static void tcg_target_init(TCGContext *s)
static inline void tcg_target_qemu_prologue(TCGContext *s)
{
}

bool tcg_target_has_memory_bswap(MemOp memop)
{
return true;
}
4 changes: 2 additions & 2 deletions tcg/tci/tcg-target.h
Expand Up @@ -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

Expand Down Expand Up @@ -176,6 +178,4 @@ typedef enum {
We prefer consistency across hosts on this. */
#define TCG_TARGET_DEFAULT_MO (0)

#define TCG_TARGET_HAS_MEMORY_BSWAP 1

#endif /* TCG_TARGET_H */