]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add support for the CU24 insn (s390x). Part of fixing #289839.
authorFlorian Krohm <florian@eich-krohm.de>
Sat, 21 Jul 2012 17:41:36 +0000 (17:41 +0000)
committerFlorian Krohm <florian@eich-krohm.de>
Sat, 21 Jul 2012 17:41:36 +0000 (17:41 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@2442

VEX/priv/guest_s390_defs.h
VEX/priv/guest_s390_helpers.c
VEX/priv/guest_s390_toIR.c

index 634b91290e32f73e0420ba812e04c91d83ed9b3a..168ea364153baeb28cb0ef0263e14e281f8a6d29 100644 (file)
@@ -83,6 +83,7 @@ ULong s390x_dirtyhelper_STFLE(VexGuestS390XState *guest_state, HWord addr);
 void  s390x_dirtyhelper_CUxy(UChar *addr, ULong data, ULong num_bytes);
 
 ULong s390_do_cu21(UInt srcvalue, UInt low_surrogate);
+ULong s390_do_cu24(UInt srcvalue, UInt low_surrogate);
 UInt  s390_do_cvb(ULong decimal);
 ULong s390_do_cvd(ULong binary);
 
index 0205644e672a0519000c9d930f698cf1d37175fe..de52c3247c367733493f77bbaa66e0ea1e8d85aa 100644 (file)
@@ -455,6 +455,49 @@ s390_do_cu21(UInt srcval, UInt low_surrogate)
 }
 
 
+/*------------------------------------------------------------*/
+/*--- Clean helper for CU24.                               ---*/
+/*------------------------------------------------------------*/
+
+/* The function performs a CU24 operation. It returns two things
+   encoded in an ULong value:
+   - the 4 converted bytes
+   - an indication whether LOW_SURROGATE, if any, is invalid
+
+   64     40                 8                       0
+    +------------------------+-----------------------+
+    |  0x0 | converted bytes | invalid_low_surrogate |
+    +------------------------+-----------------------+
+*/
+ULong
+s390_do_cu24(UInt srcval, UInt low_surrogate)
+{
+   ULong retval;
+   UInt invalid_low_surrogate = 0;
+
+   srcval &= 0xffff;
+
+   if ((srcval >= 0x0000 && srcval <= 0xd7ff) ||
+       (srcval >= 0xdc00 && srcval <= 0xffff)) {
+      retval = srcval;
+   } else {
+      /* D800 - DBFF */
+      UInt high_surrogate = srcval;
+      UInt uvwxy  = ((high_surrogate >> 6) & 0xf) + 1;   // abcd + 1
+      UInt efghij = high_surrogate & 0x3f;
+      UInt klmnoprst = low_surrogate & 0x3ff;
+
+      retval = (uvwxy << 16) | (efghij << 10) | klmnoprst;
+
+      invalid_low_surrogate = (low_surrogate & 0xfc00) != 0xdc00;
+   }
+
+   /* At this point RETVAL contains the converted bytes.
+      Build up the final return value. */
+   return (retval << 8) | invalid_low_surrogate;
+}
+
+
 /*------------------------------------------------------------*/
 /*--- Clean helper for "convert to binary".                ---*/
 /*------------------------------------------------------------*/
index 3df2602be3f46b1e69ee2851e22c7da1899fe4c7..a1f3e06d5d64f4892b11fbbf2c68f34d8c8eb440 100644 (file)
@@ -11324,6 +11324,115 @@ s390_irgen_CU21(UChar m3, UChar r1, UChar r2)
    return "cu21";
 }
 
+static IRExpr *
+s390_call_cu24(IRExpr *srcval, IRExpr *low_surrogate)
+{
+   IRExpr **args, *call;
+   args = mkIRExprVec_2(srcval, low_surrogate);
+   call = mkIRExprCCall(Ity_I64, 0 /*regparm*/,
+                       "s390_do_cu24", &s390_do_cu24, args);
+
+   /* Nothing is excluded from definedness checking. */
+   call->Iex.CCall.cee->mcx_mask = 0;
+
+   return call;
+}
+
+static HChar *
+s390_irgen_CU24(UChar m3, UChar r1, UChar r2)
+{
+   IRTemp addr1 = newTemp(Ity_I64);
+   IRTemp addr2 = newTemp(Ity_I64);
+   IRTemp len1 = newTemp(Ity_I64);
+   IRTemp len2 = newTemp(Ity_I64);
+
+   assign(addr1, get_gpr_dw0(r1));
+   assign(addr2, get_gpr_dw0(r2));
+   assign(len1, get_gpr_dw0(r1 + 1));
+   assign(len2, get_gpr_dw0(r2 + 1));
+
+   /* We're processing the 2nd operand 2 bytes at a time. Therefore, if
+      there are less than 2 bytes left, then the 2nd operand is exhausted
+      and we're done here. cc = 0 */
+   s390_cc_set(0);
+   if_condition_goto(binop(Iop_CmpLT64U, mkexpr(len2), mkU64(2)),
+                     guest_IA_next_instr);
+
+   /* There are at least two bytes there. Read them. */
+   IRTemp srcval = newTemp(Ity_I32);
+   assign(srcval, unop(Iop_16Uto32, load(Ity_I16, mkexpr(addr2))));
+
+   /* Find out whether this is a high surrogate. I.e. SRCVAL lies
+      inside the interval [0xd800 - 0xdbff] */
+   IRTemp  is_high_surrogate = newTemp(Ity_I32);
+   IRExpr *flag1 = mkite(binop(Iop_CmpLE32U, mkU32(0xd800), mkexpr(srcval)),
+                         mkU32(1), mkU32(0));
+   IRExpr *flag2 = mkite(binop(Iop_CmpLE32U, mkexpr(srcval), mkU32(0xdbff)),
+                         mkU32(1), mkU32(0));
+   assign(is_high_surrogate, binop(Iop_And32, flag1, flag2));
+
+   /* If SRCVAL is a high surrogate and there are less than 4 bytes left,
+      then the 2nd operand is exhausted and we're done here. cc = 0 */
+   IRExpr *not_enough_bytes =
+      mkite(binop(Iop_CmpLT64U, mkexpr(len2), mkU64(4)), mkU32(1), mkU32(0));
+
+   if_condition_goto(binop(Iop_CmpEQ32,
+                           binop(Iop_And32, mkexpr(is_high_surrogate),
+                                 not_enough_bytes),
+                           mkU32(1)), guest_IA_next_instr);
+
+   /* The 2nd operand is not exhausted. If the first 2 bytes are a high
+      surrogate, read the next two bytes (low surrogate). */
+   IRTemp  low_surrogate = newTemp(Ity_I32);
+   IRExpr *low_surrogate_addr = binop(Iop_Add64, mkexpr(addr2), mkU64(2));
+
+   assign(low_surrogate,
+          mkite(binop(Iop_CmpEQ32, mkexpr(is_high_surrogate), mkU32(1)),
+                unop(Iop_16Uto32, load(Ity_I16, low_surrogate_addr)),
+                mkU32(0)));  // any value is fine; it will not be used
+
+   /* Call the helper */
+   IRTemp retval = newTemp(Ity_I64);
+   assign(retval, s390_call_cu24(mkexpr(srcval), mkexpr(low_surrogate)));
+
+   /* Before we can test whether the 1st operand is exhausted we need to
+      test for an invalid low surrogate. Because cc=2 outranks cc=1. */
+   if (s390_host_has_etf3 && (m3 & 0x1) == 1) {
+      IRExpr *invalid_low_surrogate =
+         binop(Iop_And64, mkexpr(retval), mkU64(0xff));
+
+      s390_cc_set(2);
+      if_condition_goto(binop(Iop_CmpEQ64, invalid_low_surrogate, mkU64(1)),
+                        guest_IA_next_instr);
+   }
+
+   /* Now test whether the 1st operand is exhausted */
+   s390_cc_set(1);
+   if_condition_goto(binop(Iop_CmpLT64U, mkexpr(len1), mkU64(4)),
+                     guest_IA_next_instr);
+
+   /* Extract the bytes to be stored at addr1 */
+   IRExpr *data = unop(Iop_64to32, binop(Iop_Shr64, mkexpr(retval), mkU8(8)));
+
+   store(mkexpr(addr1), data);
+
+   /* Update source address and length */
+   IRTemp num_src_bytes = newTemp(Ity_I64);
+   assign(num_src_bytes,
+          mkite(binop(Iop_CmpEQ32, mkexpr(is_high_surrogate), mkU32(1)),
+                mkU64(4), mkU64(2)));
+   put_gpr_dw0(r2,     binop(Iop_Add64, mkexpr(addr2), mkexpr(num_src_bytes)));
+   put_gpr_dw0(r2 + 1, binop(Iop_Sub64, mkexpr(len2),  mkexpr(num_src_bytes)));
+
+   /* Update destination address and length */
+   put_gpr_dw0(r1,     binop(Iop_Add64, mkexpr(addr1), mkU64(4)));
+   put_gpr_dw0(r1 + 1, binop(Iop_Sub64, mkexpr(len1),  mkU64(4)));
+
+   /* Iterate */
+   always_goto_and_chase(guest_IA_curr_instr);
+
+   return "cu24";
+}
 
 /*------------------------------------------------------------*/
 /*--- Build IR for special instructions                    ---*/
@@ -12160,7 +12269,9 @@ s390_decode_4byte_and_irgen(UChar *bytes)
    case 0xb9ae: /* RRBM */ goto unimplemented;
    case 0xb9af: /* PFMF */ goto unimplemented;
    case 0xb9b0: /* CU14 */ goto unimplemented;
-   case 0xb9b1: /* CU24 */ goto unimplemented;
+   case 0xb9b1: s390_format_RRF_M0RERE(s390_irgen_CU24, ovl.fmt.RRF3.r3,
+                                       ovl.fmt.RRF3.r1, ovl.fmt.RRF3.r2);
+      goto ok;
    case 0xb9b2: /* CU41 */ goto unimplemented;
    case 0xb9b3: /* CU42 */ goto unimplemented;
    case 0xb9bd: /* TRTRE */ goto unimplemented;