Support the cu14 insn. That insn is very much like cu12 except the
converted value is always 4 byte wide. The only other difference is
the encoding of a 4-byte UTF-8 character.
Some code refactoring does the trick.
Part of fixing #289839.
git-svn-id: svn://svn.valgrind.org/vex/trunk@2459 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest_s390_defs.h b/priv/guest_s390_defs.h
index 7a05736..c6e7746 100644
--- a/priv/guest_s390_defs.h
+++ b/priv/guest_s390_defs.h
@@ -81,9 +81,11 @@
ULong s390x_dirtyhelper_STFLE(VexGuestS390XState *guest_state, ULong *addr);
void s390x_dirtyhelper_CUxy(UChar *addr, ULong data, ULong num_bytes);
-ULong s390_do_cu12_helper1(UInt byte1, UInt etf3_and_m3_is_1);
+ULong s390_do_cu12_cu14_helper1(UInt byte1, UInt etf3_and_m3_is_1);
ULong s390_do_cu12_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
ULong stuff);
+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_cu42(UInt srcvalue);
diff --git a/priv/guest_s390_helpers.c b/priv/guest_s390_helpers.c
index 7969b27..120f697 100644
--- a/priv/guest_s390_helpers.c
+++ b/priv/guest_s390_helpers.c
@@ -546,7 +546,7 @@
+-------+-----------+-------------------+
*/
ULong
-s390_do_cu12_helper1(UInt byte, UInt etf3_and_m3_is_1)
+s390_do_cu12_cu14_helper1(UInt byte, UInt etf3_and_m3_is_1)
{
vassert(byte <= 0xff);
@@ -567,7 +567,7 @@
return 4 << 8; // 4 bytes
}
-/* The function performs a CU12 operation. BYTE1, BYTE2, etc are the
+/* The function performs a CU12 or CU14 operation. BYTE1, BYTE2, etc are the
bytes as read from the input stream, left to right. BYTE1 is a valid
byte. The function returns three things encoded in an ULong value:
@@ -580,13 +580,13 @@
| 0x0 | converted bytes | num_bytes | invalid_character |
+-------+-----------------+-----------+-------------------+
*/
-ULong
-s390_do_cu12_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
- ULong stuff)
+static ULong
+s390_do_cu12_cu14_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
+ ULong stuff, Bool is_cu12)
{
+ UInt num_src_bytes = stuff >> 1, etf3_and_m3_is_1 = stuff & 0x1;
UInt num_bytes = 0, invalid_character = 0;
ULong retval = 0;
- UInt num_src_bytes = stuff >> 1, etf3_and_m3_is_1 = stuff & 0x1;
vassert(num_src_bytes <= 4);
@@ -684,26 +684,50 @@
UInt uvw = byte1 & 0x7;
UInt xy = (byte2 >> 4) & 0x3;
UInt uvwxy = (uvw << 2) | xy;
- UInt abcd = (uvwxy - 1) & 0xf;
UInt efgh = byte2 & 0xf;
UInt ij = (byte3 >> 4) & 0x3;
UInt klmn = byte3 & 0xf;
UInt opqrst = byte4 & 0x3f;
- UInt high_surrogate = (0xd8 << 8) | (abcd << 6) | (efgh << 2) | ij;
- UInt low_surrogate = (0xdc << 8) | (klmn << 6) | opqrst;
+ if (is_cu12) {
+ UInt abcd = (uvwxy - 1) & 0xf;
+ UInt high_surrogate = (0xd8 << 8) | (abcd << 6) | (efgh << 2) | ij;
+ UInt low_surrogate = (0xdc << 8) | (klmn << 6) | opqrst;
- num_bytes = 4;
- retval = (high_surrogate << 16) | low_surrogate;
+ num_bytes = 4;
+ retval = (high_surrogate << 16) | low_surrogate;
+ } else {
+ num_bytes = 4;
+ retval =
+ (uvwxy << 16) | (efgh << 12) | (ij << 10) | (klmn << 6) | opqrst;
+ }
break;
}
}
+ if (! is_cu12) num_bytes = 4; // for CU14, by definition
+
/* At this point RETVAL contains the converted bytes.
Build up the final return value. */
return (retval << 16) | (num_bytes << 8) | invalid_character;
}
+ULong
+s390_do_cu12_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
+ ULong stuff)
+{
+ return s390_do_cu12_cu14_helper2(byte1, byte2, byte3, byte4, stuff,
+ /* is_cu12 = */ 1);
+}
+
+ULong
+s390_do_cu14_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
+ ULong stuff)
+{
+ return s390_do_cu12_cu14_helper2(byte1, byte2, byte3, byte4, stuff,
+ /* is_cu12 = */ 0);
+}
+
/*------------------------------------------------------------*/
/*--- Clean helper for "convert to binary". ---*/
diff --git a/priv/guest_s390_toIR.c b/priv/guest_s390_toIR.c
index 10fe3b0..3bc34a7 100644
--- a/priv/guest_s390_toIR.c
+++ b/priv/guest_s390_toIR.c
@@ -11472,12 +11472,12 @@
}
static IRExpr *
-s390_call_cu12_helper1(IRExpr *byte1, IRExpr *etf3_and_m3_is_1)
+s390_call_cu12_cu14_helper1(IRExpr *byte1, IRExpr *etf3_and_m3_is_1)
{
IRExpr **args, *call;
args = mkIRExprVec_2(byte1, etf3_and_m3_is_1);
- call = mkIRExprCCall(Ity_I64, 0 /*regparm*/,
- "s390_do_cu12_helper1", &s390_do_cu12_helper1, args);
+ call = mkIRExprCCall(Ity_I64, 0 /*regparm*/, "s390_do_cu12_cu14_helper1",
+ &s390_do_cu12_cu14_helper1, args);
/* Nothing is excluded from definedness checking. */
call->Iex.CCall.cee->mcx_mask = 0;
@@ -11500,8 +11500,23 @@
return call;
}
-static HChar *
-s390_irgen_CU12(UChar m3, UChar r1, UChar r2)
+static IRExpr *
+s390_call_cu14_helper2(IRExpr *byte1, IRExpr *byte2, IRExpr *byte3,
+ IRExpr *byte4, IRExpr *stuff)
+{
+ IRExpr **args, *call;
+ args = mkIRExprVec_5(byte1, byte2, byte3, byte4, stuff);
+ call = mkIRExprCCall(Ity_I64, 0 /*regparm*/,
+ "s390_do_cu14_helper2", &s390_do_cu14_helper2, args);
+
+ /* Nothing is excluded from definedness checking. */
+ call->Iex.CCall.cee->mcx_mask = 0;
+
+ return call;
+}
+
+static void
+s390_irgen_cu12_cu14(UChar m3, UChar r1, UChar r2, Bool is_cu12)
{
IRTemp addr1 = newTemp(Ity_I64);
IRTemp addr2 = newTemp(Ity_I64);
@@ -11527,8 +11542,8 @@
/* Call the helper to get number of bytes and invalid byte indicator */
IRTemp retval1 = newTemp(Ity_I64);
- assign(retval1, s390_call_cu12_helper1(mkexpr(byte1),
- mkU32(extended_checking)));
+ assign(retval1, s390_call_cu12_cu14_helper1(mkexpr(byte1),
+ mkU32(extended_checking)));
/* Check for invalid 1st byte */
IRExpr *is_invalid = unop(Iop_64to1, mkexpr(retval1));
@@ -11563,8 +11578,14 @@
binop(Iop_Shl64, mkexpr(num_src_bytes), mkU8(1)),
mkU64(extended_checking));
IRTemp retval2 = newTemp(Ity_I64);
- assign(retval2, s390_call_cu12_helper2(mkexpr(byte1), byte2, byte3, byte4,
- stuff));
+
+ if (is_cu12) {
+ assign(retval2, s390_call_cu12_helper2(mkexpr(byte1), byte2, byte3,
+ byte4, stuff));
+ } else {
+ assign(retval2, s390_call_cu14_helper2(mkexpr(byte1), byte2, byte3,
+ byte4, stuff));
+ }
/* Check for invalid character */
s390_cc_set(2);
@@ -11583,25 +11604,30 @@
IRTemp data = newTemp(Ity_I64);
assign(data, binop(Iop_Shr64, mkexpr(retval2), mkU8(16)));
- /* To store the bytes construct 2 dirty helper calls. The helper calls
- are guarded (num_bytes == 2 and num_bytes == 4, respectively) such
- that only one of them will be called at runtime. */
+ if (is_cu12) {
+ /* To store the bytes construct 2 dirty helper calls. The helper calls
+ are guarded (num_bytes == 2 and num_bytes == 4, respectively) such
+ that only one of them will be called at runtime. */
- Int i;
- for (i = 2; i <= 4; ++i) {
- IRDirty *d;
+ Int i;
+ for (i = 2; i <= 4; ++i) {
+ IRDirty *d;
- if (i == 3) continue; // skip this one
+ if (i == 3) continue; // skip this one
- 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));
+ 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));
+ }
+ } else {
+ // cu14
+ store(mkexpr(addr1), unop(Iop_64to32, mkexpr(data)));
}
/* Update source address and length */
@@ -11613,10 +11639,24 @@
put_gpr_dw0(r1 + 1, binop(Iop_Sub64, mkexpr(len1), mkexpr(num_bytes)));
iterate();
+}
+
+static HChar *
+s390_irgen_CU12(UChar m3, UChar r1, UChar r2)
+{
+ s390_irgen_cu12_cu14(m3, r1, r2, /* is_cu12 = */ 1);
return "cu12";
}
+static HChar *
+s390_irgen_CU14(UChar m3, UChar r1, UChar r2)
+{
+ s390_irgen_cu12_cu14(m3, r1, r2, /* is_cu12 = */ 0);
+
+ return "cu14";
+}
+
/*------------------------------------------------------------*/
/*--- Build IR for special instructions ---*/
/*------------------------------------------------------------*/
@@ -12451,7 +12491,9 @@
case 0xb9aa: /* LPTEA */ goto unimplemented;
case 0xb9ae: /* RRBM */ goto unimplemented;
case 0xb9af: /* PFMF */ goto unimplemented;
- case 0xb9b0: /* CU14 */ goto unimplemented;
+ case 0xb9b0: s390_format_RRF_M0RERE(s390_irgen_CU14, ovl.fmt.RRF3.r3,
+ ovl.fmt.RRF3.r1, ovl.fmt.RRF3.r2);
+ goto ok;
case 0xb9b1: s390_format_RRF_M0RERE(s390_irgen_CU24, ovl.fmt.RRF3.r3,
ovl.fmt.RRF3.r1, ovl.fmt.RRF3.r2);
goto ok;