}
+/*------------------------------------------------------------*/
+/*--- 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. ---*/
/*------------------------------------------------------------*/
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)
{
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;