target-s390: Perform COMPARE AND SWAP inline

Still no proper solution for CONFIG_USER_ONLY, but the system
version is significantly better.

Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2012-09-20 17:09:35 -07:00
parent bacf43c62e
commit b7886de3f3
4 changed files with 124 additions and 96 deletions

View File

@ -17,9 +17,6 @@ DEF_HELPER_4(srst, i64, env, i64, i64, i64)
DEF_HELPER_4(clst, i64, env, i64, i64, i64)
DEF_HELPER_4(mvpg, void, env, i64, i64, i64)
DEF_HELPER_4(mvst, i64, env, i64, i64, i64)
DEF_HELPER_4(csg, i64, env, i64, i64, i64)
DEF_HELPER_4(cdsg, i32, env, i32, i64, i32)
DEF_HELPER_4(cs, i64, env, i64, i64, i64)
DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64)
DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32)
DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32)

View File

@ -193,13 +193,13 @@
D(0xec7d, CLGIJ, RIE_c, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1)
/* COMPARE AND SWAP */
C(0xba00, CS, RS_a, Z, r1_o, a2, new, r1_32, cs, 0)
C(0xeb14, CSY, RSY_a, LD, r1_o, a2, new, r1_32, cs, 0)
C(0xeb30, CSG, RSY_a, Z, r1_o, a2, r1, 0, csg, 0)
D(0xba00, CS, RS_a, Z, r3_32u, r1_32u, new, r1_32, cs, 0, 0)
D(0xeb14, CSY, RSY_a, LD, r3_32u, r1_32u, new, r1_32, cs, 0, 0)
D(0xeb30, CSG, RSY_a, Z, r3_o, r1_o, new, r1, cs, 0, 1)
/* COMPARE DOUBLE AND SWAP */
C(0xbb00, CDS, RS_a, Z, r1_D32, a2, new, r1_D32, cds, 0)
C(0xeb31, CDSY, RSY_a, LD, r1_D32, a2, new, r1_D32, cds, 0)
C(0xeb3e, CDSG, RSY_a, Z, 0, a2, 0, 0, cdsg, 0)
D(0xbb00, CDS, RS_a, Z, r3_D32, r1_D32, new, r1_D32, cs, 0, 1)
D(0xeb31, CDSY, RSY_a, LD, r3_D32, r1_D32, new, r1_D32, cs, 0, 1)
C(0xeb3e, CDSG, RSY_a, Z, 0, 0, 0, 0, cdsg, 0)
/* COMPARE AND TRAP */
D(0xb972, CRT, RRF_c, GIE, r1_32s, r2_32s, 0, 0, ct, 0, 0)

View File

@ -442,59 +442,6 @@ uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
return d + len;
}
/* compare and swap 64-bit */
uint64_t HELPER(csg)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3)
{
/* FIXME: locking? */
uint64_t v2 = cpu_ldq_data(env, a2);
if (r1 == v2) {
cpu_stq_data(env, a2, r3);
env->cc_op = 0;
return r1;
} else {
env->cc_op = 1;
return v2;
}
}
/* compare double and swap 64-bit */
uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
{
/* FIXME: locking? */
uint32_t cc;
uint64_t v2_hi = cpu_ldq_data(env, a2);
uint64_t v2_lo = cpu_ldq_data(env, a2 + 8);
uint64_t v1_hi = env->regs[r1];
uint64_t v1_lo = env->regs[r1 + 1];
if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
cc = 0;
cpu_stq_data(env, a2, env->regs[r3]);
cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]);
} else {
cc = 1;
env->regs[r1] = v2_hi;
env->regs[r1 + 1] = v2_lo;
}
return cc;
}
/* compare and swap 32-bit */
uint64_t HELPER(cs)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3)
{
/* FIXME: locking? */
uint32_t v2 = cpu_ldl_data(env, a2);
if ((uint32_t)r1 == v2) {
cpu_stl_data(env, a2, (uint32_t)r3);
env->cc_op = 0;
return r1;
} else {
env->cc_op = 1;
return v2;
}
}
static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address,
uint32_t mask)
{

View File

@ -1078,8 +1078,9 @@ typedef struct {
#define SPEC_r1_even 1
#define SPEC_r2_even 2
#define SPEC_r1_f128 4
#define SPEC_r2_f128 8
#define SPEC_r3_even 4
#define SPEC_r1_f128 8
#define SPEC_r2_f128 16
/* Return values from translate_one, indicating the state of the TB. */
typedef enum {
@ -1124,9 +1125,9 @@ typedef enum DisasFacility {
struct DisasInsn {
unsigned opc:16;
DisasFormat fmt:6;
DisasFacility fac:6;
unsigned spec:4;
DisasFormat fmt:8;
DisasFacility fac:8;
unsigned spec:8;
const char *name;
@ -1828,18 +1829,102 @@ static ExitStatus op_cps(DisasContext *s, DisasOps *o)
static ExitStatus op_cs(DisasContext *s, DisasOps *o)
{
int r3 = get_field(s->fields, r3);
potential_page_fault(s);
gen_helper_cs(o->out, cpu_env, o->in1, o->in2, regs[r3]);
/* FIXME: needs an atomic solution for CONFIG_USER_ONLY. */
int d2 = get_field(s->fields, d2);
int b2 = get_field(s->fields, b2);
int is_64 = s->insn->data;
TCGv_i64 addr, mem, cc, z;
/* Note that in1 = R3 (new value) and
in2 = (zero-extended) R1 (expected value). */
/* Load the memory into the (temporary) output. While the PoO only talks
about moving the memory to R1 on inequality, if we include equality it
means that R1 is equal to the memory in all conditions. */
addr = get_address(s, 0, b2, d2);
if (is_64) {
tcg_gen_qemu_ld64(o->out, addr, get_mem_index(s));
} else {
tcg_gen_qemu_ld32u(o->out, addr, get_mem_index(s));
}
/* Are the memory and expected values (un)equal? Note that this setcond
produces the output CC value, thus the NE sense of the test. */
cc = tcg_temp_new_i64();
tcg_gen_setcond_i64(TCG_COND_NE, cc, o->in2, o->out);
/* If the memory and expected values are equal (CC==0), copy R3 to MEM.
Recall that we are allowed to unconditionally issue the store (and
thus any possible write trap), so (re-)store the original contents
of MEM in case of inequality. */
z = tcg_const_i64(0);
mem = tcg_temp_new_i64();
tcg_gen_movcond_i64(TCG_COND_EQ, mem, cc, z, o->in1, o->out);
if (is_64) {
tcg_gen_qemu_st64(mem, addr, get_mem_index(s));
} else {
tcg_gen_qemu_st32(mem, addr, get_mem_index(s));
}
tcg_temp_free_i64(z);
tcg_temp_free_i64(mem);
tcg_temp_free_i64(addr);
/* Store CC back to cc_op. Wait until after the store so that any
exception gets the old cc_op value. */
tcg_gen_trunc_i64_i32(cc_op, cc);
tcg_temp_free_i64(cc);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_csg(DisasContext *s, DisasOps *o)
static ExitStatus op_cdsg(DisasContext *s, DisasOps *o)
{
/* FIXME: needs an atomic solution for CONFIG_USER_ONLY. */
int r1 = get_field(s->fields, r1);
int r3 = get_field(s->fields, r3);
potential_page_fault(s);
gen_helper_csg(o->out, cpu_env, o->in1, o->in2, regs[r3]);
int d2 = get_field(s->fields, d2);
int b2 = get_field(s->fields, b2);
TCGv_i64 addrh, addrl, memh, meml, outh, outl, cc, z;
/* Note that R1:R1+1 = expected value and R3:R3+1 = new value. */
addrh = get_address(s, 0, b2, d2);
addrl = get_address(s, 0, b2, d2 + 8);
outh = tcg_temp_new_i64();
outl = tcg_temp_new_i64();
tcg_gen_qemu_ld64(outh, addrh, get_mem_index(s));
tcg_gen_qemu_ld64(outl, addrl, get_mem_index(s));
/* Fold the double-word compare with arithmetic. */
cc = tcg_temp_new_i64();
z = tcg_temp_new_i64();
tcg_gen_xor_i64(cc, outh, regs[r1]);
tcg_gen_xor_i64(z, outl, regs[r1 + 1]);
tcg_gen_or_i64(cc, cc, z);
tcg_gen_movi_i64(z, 0);
tcg_gen_setcond_i64(TCG_COND_NE, cc, cc, z);
memh = tcg_temp_new_i64();
meml = tcg_temp_new_i64();
tcg_gen_movcond_i64(TCG_COND_EQ, memh, cc, z, regs[r3], outh);
tcg_gen_movcond_i64(TCG_COND_EQ, meml, cc, z, regs[r3 + 1], outl);
tcg_temp_free_i64(z);
tcg_gen_qemu_st64(memh, addrh, get_mem_index(s));
tcg_gen_qemu_st64(meml, addrl, get_mem_index(s));
tcg_temp_free_i64(memh);
tcg_temp_free_i64(meml);
tcg_temp_free_i64(addrh);
tcg_temp_free_i64(addrl);
/* Save back state now that we've passed all exceptions. */
tcg_gen_mov_i64(regs[r1], outh);
tcg_gen_mov_i64(regs[r1 + 1], outl);
tcg_gen_trunc_i64_i32(cc_op, cc);
tcg_temp_free_i64(outh);
tcg_temp_free_i64(outl);
tcg_temp_free_i64(cc);
set_cc_static(s);
return NO_EXIT;
}
@ -1856,29 +1941,6 @@ static ExitStatus op_csp(DisasContext *s, DisasOps *o)
}
#endif
static ExitStatus op_cds(DisasContext *s, DisasOps *o)
{
int r3 = get_field(s->fields, r3);
TCGv_i64 in3 = tcg_temp_new_i64();
tcg_gen_deposit_i64(in3, regs[r3 + 1], regs[r3], 32, 32);
potential_page_fault(s);
gen_helper_csg(o->out, cpu_env, o->in1, o->in2, in3);
tcg_temp_free_i64(in3);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_cdsg(DisasContext *s, DisasOps *o)
{
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3));
potential_page_fault(s);
/* XXX rewrite in tcg */
gen_helper_cdsg(cc_op, cpu_env, r1, o->in2, r3);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_cvd(DisasContext *s, DisasOps *o)
{
TCGv_i64 t1 = tcg_temp_new_i64();
@ -4007,6 +4069,14 @@ static void in1_r3_32u(DisasContext *s, DisasFields *f, DisasOps *o)
}
#define SPEC_in1_r3_32u 0
static void in1_r3_D32(DisasContext *s, DisasFields *f, DisasOps *o)
{
int r3 = get_field(f, r3);
o->in1 = tcg_temp_new_i64();
tcg_gen_concat32_i64(o->in1, regs[r3 + 1], regs[r3]);
}
#define SPEC_in1_r3_D32 SPEC_r3_even
static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = load_freg32_i64(get_field(f, r1));
@ -4121,6 +4191,14 @@ static void in2_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o)
}
#define SPEC_in2_r1_32u 0
static void in2_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o)
{
int r1 = get_field(f, r1);
o->in2 = tcg_temp_new_i64();
tcg_gen_concat32_i64(o->in2, regs[r1 + 1], regs[r1]);
}
#define SPEC_in2_r1_D32 SPEC_r1_even
static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = load_reg(get_field(f, r2));
@ -4580,6 +4658,12 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s)
excp = PGM_SPECIFICATION;
}
}
if (spec & SPEC_r3_even) {
r = get_field(&f, r3);
if (r & 1) {
excp = PGM_SPECIFICATION;
}
}
if (spec & SPEC_r1_f128) {
r = get_field(&f, r1);
if (r > 13) {