aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-s390x/insn-data.def2
-rw-r--r--target-s390x/translate.c50
2 files changed, 48 insertions, 4 deletions
diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def
index e915984828..480f1fdf51 100644
--- a/target-s390x/insn-data.def
+++ b/target-s390x/insn-data.def
@@ -271,7 +271,7 @@
C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64)
C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64)
C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64)
- C(0xd700, XC, SS_a, Z, la1, a2, 0, 0, xc, 0)
+ C(0xd700, XC, SS_a, Z, 0, 0, 0, 0, xc, 0)
/* EXCLUSIVE OR IMMEDIATE */
D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020)
D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000)
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 34b9cdf127..7f8a5503d9 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -3403,10 +3403,54 @@ static ExitStatus op_unpk(DisasContext *s, DisasOps *o)
static ExitStatus op_xc(DisasContext *s, DisasOps *o)
{
- TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
+ int d1 = get_field(s->fields, d1);
+ int d2 = get_field(s->fields, d2);
+ int b1 = get_field(s->fields, b1);
+ int b2 = get_field(s->fields, b2);
+ int l = get_field(s->fields, l1);
+ TCGv_i32 t32;
+
+ o->addr1 = get_address(s, 0, b1, d1);
+
+ /* If the addresses are identical, this is a store/memset of zero. */
+ if (b1 == b2 && d1 == d2 && (l + 1) <= 32) {
+ o->in2 = tcg_const_i64(0);
+
+ l++;
+ while (l >= 8) {
+ tcg_gen_qemu_st64(o->in2, o->addr1, get_mem_index(s));
+ l -= 8;
+ if (l > 0) {
+ tcg_gen_addi_i64(o->addr1, o->addr1, 8);
+ }
+ }
+ if (l >= 4) {
+ tcg_gen_qemu_st32(o->in2, o->addr1, get_mem_index(s));
+ l -= 4;
+ if (l > 0) {
+ tcg_gen_addi_i64(o->addr1, o->addr1, 4);
+ }
+ }
+ if (l >= 2) {
+ tcg_gen_qemu_st16(o->in2, o->addr1, get_mem_index(s));
+ l -= 2;
+ if (l > 0) {
+ tcg_gen_addi_i64(o->addr1, o->addr1, 2);
+ }
+ }
+ if (l) {
+ tcg_gen_qemu_st8(o->in2, o->addr1, get_mem_index(s));
+ }
+ gen_op_movi_cc(s, 0);
+ return NO_EXIT;
+ }
+
+ /* But in general we'll defer to a helper. */
+ o->in2 = get_address(s, 0, b2, d2);
+ t32 = tcg_const_i32(l);
potential_page_fault(s);
- gen_helper_xc(cc_op, cpu_env, l, o->addr1, o->in2);
- tcg_temp_free_i32(l);
+ gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2);
+ tcg_temp_free_i32(t32);
set_cc_static(s);
return NO_EXIT;
}