s390x: improve IR generation for XC.  Fixes #268621.
(Florian Krohm, britzel@acm.org)


git-svn-id: svn://svn.valgrind.org/vex/trunk@2113 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest_s390_toIR.c b/priv/guest_s390_toIR.c
index 34c3ade..fdd2cf4 100644
--- a/priv/guest_s390_toIR.c
+++ b/priv/guest_s390_toIR.c
@@ -9112,6 +9112,45 @@
    return "xc";
 }
 
+static void
+s390_irgen_XC_sameloc(UChar length, UChar b, UShort d)
+{
+   IRTemp counter = newTemp(Ity_I32);
+   IRTemp start = newTemp(Ity_I64);
+   IRTemp addr  = newTemp(Ity_I64);
+
+   assign(start,
+          binop(Iop_Add64, mkU64(d), b != 0 ? get_gpr_dw0(b) : mkU64(0)));
+
+   if (length < 8) {
+      UInt i;
+
+      for (i = 0; i <= length; ++i) {
+         store(binop(Iop_Add64, mkexpr(start), mkU64(i)), mkU8(0));
+      }
+   } else {
+     assign(counter, get_counter_w0());
+
+     assign(addr, binop(Iop_Add64, mkexpr(start),
+                        unop(Iop_32Uto64, mkexpr(counter))));
+
+     store(mkexpr(addr), mkU8(0));
+
+     /* Check for end of field */
+     put_counter_w0(binop(Iop_Add32, mkexpr(counter), mkU32(1)));
+     if_condition_goto(binop(Iop_CmpNE32, mkexpr(counter), mkU32(length)),
+                       guest_IA_curr_instr);
+
+     /* Reset counter */
+     put_counter_dw0(mkU64(0));
+   }
+
+   s390_cc_thunk_put1(S390_CC_OP_BITWISE, mktemp(Ity_I32, mkU32(0)), False);
+
+   if (unlikely(vex_traceflags & VEX_TRACE_FE))
+      s390_disasm(ENC3(MNM, UDLB, UDXB), "xc", d, length, b, d, 0, b);
+}
+
 static HChar *
 s390_irgen_NC(UChar length, IRTemp start1, IRTemp start2)
 {
@@ -12565,9 +12604,14 @@
    case 0xd6ULL: s390_format_SS_L0RDRD(s390_irgen_OC, ovl.fmt.SS.l,
                                        ovl.fmt.SS.b1, ovl.fmt.SS.d1,
                                        ovl.fmt.SS.b2, ovl.fmt.SS.d2);  goto ok;
-   case 0xd7ULL: s390_format_SS_L0RDRD(s390_irgen_XC, ovl.fmt.SS.l,
-                                       ovl.fmt.SS.b1, ovl.fmt.SS.d1,
-                                       ovl.fmt.SS.b2, ovl.fmt.SS.d2);  goto ok;
+   case 0xd7ULL:
+      if (ovl.fmt.SS.b1 == ovl.fmt.SS.b2 && ovl.fmt.SS.d1 == ovl.fmt.SS.d2)
+         s390_irgen_XC_sameloc(ovl.fmt.SS.l, ovl.fmt.SS.b1, ovl.fmt.SS.d1);
+      else
+        s390_format_SS_L0RDRD(s390_irgen_XC, ovl.fmt.SS.l,
+                              ovl.fmt.SS.b1, ovl.fmt.SS.d1,
+                              ovl.fmt.SS.b2, ovl.fmt.SS.d2);
+      goto ok;
    case 0xd9ULL: /* MVCK */ goto unimplemented;
    case 0xdaULL: /* MVCP */ goto unimplemented;
    case 0xdbULL: /* MVCS */ goto unimplemented;