From: Florian Krohm Date: Mon, 6 Aug 2012 00:07:54 +0000 (+0000) Subject: Add support for the cu41 insn. This completes the unicode conversion X-Git-Tag: svn/VALGRIND_3_8_1^2~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=869aff78146fa5b2591d6b386e2fd41a8cc99e4e;p=thirdparty%2Fvalgrind.git Add support for the cu41 insn. This completes the unicode conversion insns and fixes #289839. git-svn-id: svn://svn.valgrind.org/vex/trunk@2461 --- diff --git a/VEX/priv/guest_s390_defs.h b/VEX/priv/guest_s390_defs.h index c6e77469e4..ab49217d68 100644 --- a/VEX/priv/guest_s390_defs.h +++ b/VEX/priv/guest_s390_defs.h @@ -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); diff --git a/VEX/priv/guest_s390_helpers.c b/VEX/priv/guest_s390_helpers.c index 120f69788b..4a5a26211c 100644 --- a/VEX/priv/guest_s390_helpers.c +++ b/VEX/priv/guest_s390_helpers.c @@ -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. ---*/ /*------------------------------------------------------------*/ diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index 3bc34a781a..188992f748 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -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;