]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add support for the cu41 insn. This completes the unicode conversion
authorFlorian Krohm <florian@eich-krohm.de>
Mon, 6 Aug 2012 00:07:54 +0000 (00:07 +0000)
committerFlorian Krohm <florian@eich-krohm.de>
Mon, 6 Aug 2012 00:07:54 +0000 (00:07 +0000)
insns and fixes #289839.

git-svn-id: svn://svn.valgrind.org/vex/trunk@2461

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

index c6e77469e4dbb8935fb38491a185d0ad98bcbe0a..ab49217d6852a2a9e68cbd0f218f8681ce9dbe89 100644 (file)
@@ -88,6 +88,7 @@ ULong s390_do_cu14_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
                            ULong stuff);
 ULong s390_do_cu21(UInt srcvalue, UInt low_surrogate);
 ULong s390_do_cu24(UInt srcvalue, UInt low_surrogate);
+ULong s390_do_cu41(UInt srcvalue);
 ULong s390_do_cu42(UInt srcvalue);
 UInt  s390_do_cvb(ULong decimal);
 ULong s390_do_cvd(ULong binary);
index 120f69788bfd912b0bc8b54ff15056b05e3c1d27..4a5a26211ca9ad58bd8667952635bbc1493c180f 100644 (file)
@@ -530,6 +530,76 @@ s390_do_cu42(UInt srcval)
 }
 
 
+/*------------------------------------------------------------*/
+/*--- Clean helper for CU41.                               ---*/
+/*------------------------------------------------------------*/
+
+/* The function performs a CU41 operation. It returns three things
+   encoded in an ULong value:
+   - the converted bytes (at most 4)
+   - the number of converted bytes (1, 2, 3, or 4; 0 if invalid character)
+   - an indication whether the UTF-32 character is invalid
+
+   64      48                16           8                   0
+    +-------+-----------------+-----------+-------------------+
+    |  0x0  | converted bytes | num_bytes | invalid_character |
+    +-------+-----------------+-----------+-------------------+
+*/
+ULong
+s390_do_cu41(UInt srcval)
+{
+   ULong retval;
+   UInt num_bytes, invalid_character = 0;
+
+   if (srcval <= 0x7f) {
+      retval = srcval;
+      num_bytes = 1;
+   } else if (srcval >= 0x80 && srcval <= 0x7ff) {
+      UInt fghij  = srcval >> 6;
+      UInt klmnop = srcval & 0x3f;
+      UInt byte1  = (0xc0 | fghij);
+      UInt byte2  = (0x80 | klmnop);
+
+      retval = (byte1 << 8) | byte2;
+      num_bytes = 2;
+   } else if ((srcval >= 0x800  && srcval <= 0xd7ff) ||
+              (srcval >= 0xdc00 && srcval <= 0xffff)) {
+      UInt abcd   = srcval >> 12;
+      UInt efghij = (srcval >> 6) & 0x3f;
+      UInt klmnop = srcval & 0x3f;
+      UInt byte1  = 0xe0 | abcd;
+      UInt byte2  = 0x80 | efghij;
+      UInt byte3  = 0x80 | klmnop;
+
+      retval = (byte1 << 16) | (byte2 << 8) | byte3;
+      num_bytes = 3;
+   } else if (srcval >= 0x10000 && srcval <= 0x10ffff) {
+      UInt uvw    = (srcval >> 18) & 0x7;
+      UInt xy     = (srcval >> 16) & 0x3;
+      UInt efgh   = (srcval >> 12) & 0xf;
+      UInt ijklmn = (srcval >>  6) & 0x3f;
+      UInt opqrst = srcval & 0x3f;
+      UInt byte1  = 0xf0 | uvw;
+      UInt byte2  = 0x80 | (xy << 4) | efgh;
+      UInt byte3  = 0x80 | ijklmn;
+      UInt byte4  = 0x80 | opqrst;
+
+      retval = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
+      num_bytes = 4;
+   } else {
+      /* d800 ... dbff or 00110000 ... ffffffff */
+      invalid_character = 1;
+
+      retval = 0;
+      num_bytes = 0;
+   }
+
+   /* At this point RETVAL contains the converted bytes.
+      Build up the final return value. */
+   return (retval << 16) | (num_bytes << 8) | invalid_character;
+}
+
+
 /*------------------------------------------------------------*/
 /*--- Clean helpers for CU12.                              ---*/
 /*------------------------------------------------------------*/
index 3bc34a781ac0cc4f47cdb81059238933931a6d73..188992f748f2de09ef92e89b078e07b2aa3f3abb 100644 (file)
@@ -11471,6 +11471,97 @@ s390_irgen_CU42(UChar r1, UChar r2)
    return "cu42";
 }
 
+static IRExpr *
+s390_call_cu41(IRExpr *srcval)
+{
+   IRExpr **args, *call;
+   args = mkIRExprVec_1(srcval);
+   call = mkIRExprCCall(Ity_I64, 0 /*regparm*/,
+                       "s390_do_cu41", &s390_do_cu41, args);
+
+   /* Nothing is excluded from definedness checking. */
+   call->Iex.CCall.cee->mcx_mask = 0;
+
+   return call;
+}
+
+static HChar *
+s390_irgen_CU41(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 4 bytes at a time. Therefore, if
+      there are less than 4 bytes left, then the 2nd operand is exhausted
+      and we're done here. cc = 0 */
+   s390_cc_set(0);
+   next_insn_if(binop(Iop_CmpLT64U, mkexpr(len2), mkU64(4)));
+
+   /* Read the 2nd operand. */
+   IRTemp srcval = newTemp(Ity_I32);
+   assign(srcval, load(Ity_I32, mkexpr(addr2)));
+
+   /* Call the helper */
+   IRTemp retval = newTemp(Ity_I64);
+   assign(retval, s390_call_cu41(mkexpr(srcval)));
+
+   /* If the UTF-32 character was invalid, set cc=2 and we're done.
+      cc=2 outranks cc=1 (1st operand exhausted) */
+   IRExpr *invalid_character = binop(Iop_And64, mkexpr(retval), mkU64(0xff));
+
+   s390_cc_set(2);
+   next_insn_if(binop(Iop_CmpEQ64, invalid_character, mkU64(1)));
+
+   /* Now test whether the 1st operand is exhausted */
+   IRTemp num_bytes = newTemp(Ity_I64);
+   assign(num_bytes, binop(Iop_And64,
+                           binop(Iop_Shr64, mkexpr(retval), mkU8(8)),
+                           mkU64(0xff)));
+   s390_cc_set(1);
+   next_insn_if(binop(Iop_CmpLT64U, mkexpr(len1), mkexpr(num_bytes)));
+
+   /* Extract the bytes to be stored at addr1 */
+   IRTemp data = newTemp(Ity_I64);
+   assign(data, binop(Iop_Shr64, mkexpr(retval), mkU8(16)));
+
+   /* To store the bytes construct 4 dirty helper calls. The helper calls
+      are guarded (num_bytes == 1, num_bytes == 2, etc) such that only
+      one of them will be called at runtime. */
+   int i;
+   for (i = 1; i <= 4; ++i) {
+      IRDirty *d;
+
+      d = unsafeIRDirty_0_N(0 /* regparms */, "s390x_dirtyhelper_CUxy",
+                            &s390x_dirtyhelper_CUxy,
+                            mkIRExprVec_3(mkexpr(addr1), mkexpr(data),
+                                          mkexpr(num_bytes)));
+      d->guard = binop(Iop_CmpEQ64, mkexpr(num_bytes), mkU64(i));
+      d->mFx   = Ifx_Write;
+      d->mAddr = mkexpr(addr1);
+      d->mSize = i;
+      stmt(IRStmt_Dirty(d));
+   }
+
+   /* Update source address and length */
+   put_gpr_dw0(r2,     binop(Iop_Add64, mkexpr(addr2), mkU64(4)));
+   put_gpr_dw0(r2 + 1, binop(Iop_Sub64, mkexpr(len2),  mkU64(4)));
+
+   /* Update destination address and length */
+   put_gpr_dw0(r1,     binop(Iop_Add64, mkexpr(addr1), mkexpr(num_bytes)));
+   put_gpr_dw0(r1 + 1, binop(Iop_Sub64, mkexpr(len1),  mkexpr(num_bytes)));
+
+   iterate();
+
+   return "cu41";
+}
+
 static IRExpr *
 s390_call_cu12_cu14_helper1(IRExpr *byte1, IRExpr *etf3_and_m3_is_1)
 {
@@ -12497,7 +12588,8 @@ s390_decode_4byte_and_irgen(UChar *bytes)
    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 0xb9b2: s390_format_RRE_RR(s390_irgen_CU41, ovl.fmt.RRE.r1,
+                                   ovl.fmt.RRE.r2);  goto ok;
    case 0xb9b3: s390_format_RRE_RR(s390_irgen_CU42, ovl.fmt.RRE.r1,
                                    ovl.fmt.RRE.r2);  goto ok;
    case 0xb9bd: /* TRTRE */ goto unimplemented;