Support conditional load and store for s390x (VEX side).
Fixes #269209. (Christian Borntraeger, borntraeger@de.ibm.com)
git-svn-id: svn://svn.valgrind.org/vex/trunk@2121 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest_s390_toIR.c b/priv/guest_s390_toIR.c
index fdd2cf4..4537fc5 100644
--- a/priv/guest_s390_toIR.c
+++ b/priv/guest_s390_toIR.c
@@ -1564,6 +1564,16 @@
}
static void
+s390_format_RRF_U0RR(HChar *(*irgen)(UChar m3, UChar r1, UChar r2),
+ UChar m3, UChar r1, UChar r2, Int xmnm_kind)
+{
+ irgen(m3, r1, r2);
+
+ if (unlikely(vex_traceflags & VEX_TRACE_FE))
+ s390_disasm(ENC3(XMNM, GPR, GPR), xmnm_kind, m3, r1, r2);
+}
+
+static void
s390_format_RRF_U0RF(HChar *(*irgen)(UChar r3, UChar r1, UChar r2),
UChar r3, UChar r1, UChar r2)
{
@@ -1739,6 +1749,26 @@
}
static void
+s390_format_RSY_RDRM(HChar *(*irgen)(UChar r1, IRTemp op2addr),
+ UChar r1, UChar m3, UChar b2, UShort dl2, UChar dh2,
+ Int xmnm_kind)
+{
+ IRTemp op2addr = newTemp(Ity_I64);
+ IRTemp d2 = newTemp(Ity_I64);
+
+ if_condition_goto(binop(Iop_CmpEQ32, s390_call_calculate_cond(m3), mkU32(0)),
+ guest_IA_next_instr);
+ assign(d2, mkU64(((ULong)(Long)(Char)dh2 << 12) | ((ULong)dl2)));
+ assign(op2addr, binop(Iop_Add64, mkexpr(d2), b2 != 0 ? get_gpr_dw0(b2) :
+ mkU64(0)));
+
+ irgen(r1, op2addr);
+
+ if (unlikely(vex_traceflags & VEX_TRACE_FE))
+ s390_disasm(ENC3(XMNM, GPR, SDXB), xmnm_kind, m3, r1, dh2, dl2, 0, b2);
+}
+
+static void
s390_format_RX(HChar *(*irgen)(UChar r1, UChar x2, UChar b2, UShort d2,
IRTemp op2addr),
UChar r1, UChar x2, UChar b2, UShort d2)
@@ -5755,6 +5785,44 @@
}
static HChar *
+s390_irgen_LOCR(UChar m3, UChar r1, UChar r2)
+{
+ if_condition_goto(binop(Iop_CmpEQ32, s390_call_calculate_cond(m3), mkU32(0)),
+ guest_IA_next_instr);
+ put_gpr_w1(r1, get_gpr_w1(r2));
+
+ return "locr";
+}
+
+static HChar *
+s390_irgen_LOCGR(UChar m3, UChar r1, UChar r2)
+{
+ if_condition_goto(binop(Iop_CmpEQ32, s390_call_calculate_cond(m3), mkU32(0)),
+ guest_IA_next_instr);
+ put_gpr_dw0(r1, get_gpr_dw0(r2));
+
+ return "locgr";
+}
+
+static HChar *
+s390_irgen_LOC(UChar r1, IRTemp op2addr)
+{
+ /* condition is checked in format handler */
+ put_gpr_w1(r1, load(Ity_I32, mkexpr(op2addr)));
+
+ return "loc";
+}
+
+static HChar *
+s390_irgen_LOCG(UChar r1, IRTemp op2addr)
+{
+ /* condition is checked in format handler */
+ put_gpr_dw0(r1, load(Ity_I64, mkexpr(op2addr)));
+
+ return "locg";
+}
+
+static HChar *
s390_irgen_LPQ(UChar r1, IRTemp op2addr)
{
put_gpr_dw0(r1, load(Ity_I64, mkexpr(op2addr)));
@@ -7164,6 +7232,24 @@
}
static HChar *
+s390_irgen_STOC(UChar r1, IRTemp op2addr)
+{
+ /* condition is checked in format handler */
+ store(mkexpr(op2addr), get_gpr_w1(r1));
+
+ return "stoc";
+}
+
+static HChar *
+s390_irgen_STOCG(UChar r1, IRTemp op2addr)
+{
+ /* condition is checked in format handler */
+ store(mkexpr(op2addr), get_gpr_dw0(r1));
+
+ return "stocg";
+}
+
+static HChar *
s390_irgen_STPQ(UChar r1, IRTemp op2addr)
{
store(mkexpr(op2addr), get_gpr_dw0(r1));
@@ -11276,7 +11362,9 @@
case 0xb9df: s390_format_RRE_RR(s390_irgen_CLHLR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
case 0xb9e1: /* POPCNT */ goto unimplemented;
- case 0xb9e2: /* LOCGR */ goto unimplemented;
+ case 0xb9e2: s390_format_RRF_U0RR(s390_irgen_LOCGR, ovl.fmt.RRF3.r3,
+ ovl.fmt.RRF3.r1, ovl.fmt.RRF3.r2,
+ S390_XMNM_LOCGR); goto ok;
case 0xb9e4: s390_format_RRF_R0RR2(s390_irgen_NGRK, ovl.fmt.RRF4.r3,
ovl.fmt.RRF4.r1, ovl.fmt.RRF4.r2);
goto ok;
@@ -11298,7 +11386,9 @@
case 0xb9eb: s390_format_RRF_R0RR2(s390_irgen_SLGRK, ovl.fmt.RRF4.r3,
ovl.fmt.RRF4.r1, ovl.fmt.RRF4.r2);
goto ok;
- case 0xb9f2: /* LOCR */ goto unimplemented;
+ case 0xb9f2: s390_format_RRF_U0RR(s390_irgen_LOCR, ovl.fmt.RRF3.r3,
+ ovl.fmt.RRF3.r1, ovl.fmt.RRF3.r2,
+ S390_XMNM_LOCR); goto ok;
case 0xb9f4: s390_format_RRF_R0RR2(s390_irgen_NRK, ovl.fmt.RRF4.r3,
ovl.fmt.RRF4.r1, ovl.fmt.RRF4.r2);
goto ok;
@@ -12185,8 +12275,16 @@
ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
ovl.fmt.RSY.dl2,
ovl.fmt.RSY.dh2); goto ok;
- case 0xeb00000000e2ULL: /* LOCG */ goto unimplemented;
- case 0xeb00000000e3ULL: /* STOCG */ goto unimplemented;
+ case 0xeb00000000e2ULL: s390_format_RSY_RDRM(s390_irgen_LOCG, ovl.fmt.RSY.r1,
+ ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
+ ovl.fmt.RSY.dl2,
+ ovl.fmt.RSY.dh2,
+ S390_XMNM_LOCG); goto ok;
+ case 0xeb00000000e3ULL: s390_format_RSY_RDRM(s390_irgen_STOCG,
+ ovl.fmt.RSY.r1, ovl.fmt.RSY.r3,
+ ovl.fmt.RSY.b2, ovl.fmt.RSY.dl2,
+ ovl.fmt.RSY.dh2,
+ S390_XMNM_STOCG); goto ok;
case 0xeb00000000e4ULL: s390_format_RSY_RRRD(s390_irgen_LANG, ovl.fmt.RSY.r1,
ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
ovl.fmt.RSY.dl2,
@@ -12207,8 +12305,16 @@
ovl.fmt.RSY.r1, ovl.fmt.RSY.r3,
ovl.fmt.RSY.b2, ovl.fmt.RSY.dl2,
ovl.fmt.RSY.dh2); goto ok;
- case 0xeb00000000f2ULL: /* LOC */ goto unimplemented;
- case 0xeb00000000f3ULL: /* STOC */ goto unimplemented;
+ case 0xeb00000000f2ULL: s390_format_RSY_RDRM(s390_irgen_LOC, ovl.fmt.RSY.r1,
+ ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
+ ovl.fmt.RSY.dl2,
+ ovl.fmt.RSY.dh2, S390_XMNM_LOC);
+ goto ok;
+ case 0xeb00000000f3ULL: s390_format_RSY_RDRM(s390_irgen_STOC, ovl.fmt.RSY.r1,
+ ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
+ ovl.fmt.RSY.dl2,
+ ovl.fmt.RSY.dh2,
+ S390_XMNM_STOC); goto ok;
case 0xeb00000000f4ULL: s390_format_RSY_RRRD(s390_irgen_LAN, ovl.fmt.RSY.r1,
ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
ovl.fmt.RSY.dl2,
diff --git a/priv/host_s390_disasm.c b/priv/host_s390_disasm.c
index 62de0c3..35f1010 100644
--- a/priv/host_s390_disasm.c
+++ b/priv/host_s390_disasm.c
@@ -121,31 +121,52 @@
return buf;
}
+/* Common function used to construct a mnemonic based on a condition code
+ mask. */
+static const HChar *
+construct_mnemonic(const HChar *prefix, const HChar *suffix, UInt mask)
+{
+ HChar *to;
+ const HChar *from;
+
+ static HChar buf[10];
+
+ static HChar mask_id[16][4] = {
+ "", /* 0 -> unused */
+ "o", "h", "nle", "l", "nhe", "lh", "ne",
+ "e", "nlh", "he", "nl", "le", "nh", "no",
+ "" /* 15 -> unused */
+ };
+
+ /* Guard against buffer overflow */
+ vassert(vex_strlen(prefix) + vex_strlen(suffix) + sizeof mask_id[0] <= sizeof buf);
+
+ /* strcpy(buf, prefix); */
+ for (from = prefix, to = buf; *from; ++from, ++to) {
+ *to = *from;
+ }
+ /* strcat(buf, mask_id); */
+ for (from = mask_id[mask]; *from; ++from, ++to) {
+ *to = *from;
+ }
+ /* strcat(buf, suffix); */
+ for (from = suffix; *from; ++from, ++to) {
+ *to = *from;
+ }
+ *to = '\0';
+
+ return buf;
+}
+
/* Return the special mnemonic for the BCR opcode */
static const HChar *
bcr_operand(UInt m1)
{
- static const HChar mnemonic[16][6] = {
- /* 0 */ "nopr", /* no operation */
- /* 1 */ "bor", /* branch on overflow / if ones */
- /* 2 */ "bhr", /* branch on high */
- /* 3 */ "bnler", /* branch on not low or equal */
- /* 4 */ "blr", /* branch on low */
- /* 5 */ "bnher", /* branch on not high or equal */
- /* 6 */ "blhr", /* branch on low or high */
- /* 7 */ "bner", /* branch on not equal */
- /* 8 */ "ber", /* branch on equal */
- /* 9 */ "bnlhr", /* branch on not low or high */
- /* a */ "bher", /* branch on high or equal */
- /* b */ "bnlr", /* branch on not low */
- /* c */ "bler", /* brach on low or equal */
- /* d */ "bnhr", /* branch on not high */
- /* e */ "bnor", /* branch on not overflow / if not ones */
- /* f */ "br", /* unconditional branch */
- };
+ if (m1 == 0) return "nopr";
+ if (m1 == 15) return "br";
- return mnemonic[m1];
+ return construct_mnemonic("b", "r", m1);
}
@@ -153,26 +174,10 @@
static const HChar *
bc_operand(UInt m1)
{
- static const HChar mnemonic[16][5] = {
- /* 0 */ "nop", // no operation
- /* 1 */ "bo", // branch on overflow / if ones
- /* 2 */ "bh", // branch on high
- /* 3 */ "bnle", // branch on not low or equal
- /* 4 */ "bl", // branch on low
- /* 5 */ "bnhe", // branch on not high or equal
- /* 6 */ "blh", // branch on low or high
- /* 7 */ "bne", // branch on not equal
- /* 8 */ "be", // branch on equal
- /* 9 */ "bnlh", // branch on not low or high
- /* a */ "bhe", // branch on high or equal
- /* b */ "bnl", // branch on not low
- /* c */ "ble", // branch on low or equal
- /* d */ "bnh", // branch on not high
- /* e */ "bno", // branch on not overflow / if not ones
- /* f */ "b" // unconditional branch
- };
+ if (m1 == 0) return "nop";
+ if (m1 == 15) return "b";
- return mnemonic[m1];
+ return construct_mnemonic("b", "", m1);
}
@@ -180,26 +185,10 @@
static const HChar *
brc_operand(UInt m1)
{
- static const HChar mnemonic[16][5] = {
- /* 0 */ "brc", /* no special mnemonic */
- /* 1 */ "jo", /* jump on overflow / if ones */
- /* 2 */ "jh", /* jump on A high */
- /* 3 */ "jnle", /* jump on not low or equal */
- /* 4 */ "jl", /* jump on A low */
- /* 5 */ "jnhe", /* jump on not high or equal */
- /* 6 */ "jlh", /* jump on low or high */
- /* 7 */ "jne", /* jump on A not equal B */
- /* 8 */ "je", /* jump on A equal B */
- /* 9 */ "jnlh", /* jump on not low or high */
- /* a */ "jhe", /* jump on high or equal */
- /* b */ "jnl", /* jump on A not low */
- /* c */ "jle", /* jump on low or equal */
- /* d */ "jnh", /* jump on A not high */
- /* e */ "jno", /* jump on not overflow / if not ones */
- /* f */ "j", /* jump */
- };
+ if (m1 == 0) return "brc";
+ if (m1 == 15) return "j";
- return mnemonic[m1];
+ return construct_mnemonic("j", "", m1);
}
@@ -207,26 +196,31 @@
static const HChar *
brcl_operand(UInt m1)
{
- static const HChar mnemonic[16][6] = {
- /* 0 */ "brcl", /* no special mnemonic */
- /* 1 */ "jgo", /* jump long on overflow / if ones */
- /* 2 */ "jgh", /* jump long on high */
- /* 3 */ "jgnle", /* jump long on not low or equal */
- /* 4 */ "jgl", /* jump long on low */
- /* 5 */ "jgnhe", /* jump long on not high or equal */
- /* 6 */ "jglh", /* jump long on low or high */
- /* 7 */ "jgne", /* jump long on not equal */
- /* 8 */ "jge", /* jump long on equal */
- /* 9 */ "jgnlh", /* jump long on not low or high */
- /* a */ "jghe", /* jump long on high or equal */
- /* b */ "jgnl", /* jump long on not low */
- /* c */ "jgle", /* jump long on low or equal */
- /* d */ "jgnh", /* jump long on not high */
- /* e */ "jgno", /* jump long on not overflow / if not ones */
- /* f */ "jg", /* jump long */
- };
+ if (m1 == 0) return "brcl";
+ if (m1 == 15) return "jg";
- return mnemonic[m1];
+ return construct_mnemonic("jg", "", m1);
+}
+
+
+/* Return the special mnemonic for a conditional load/store opcode */
+static const HChar *
+cls_operand(Int kind, UInt mask)
+{
+ HChar *prefix;
+
+ switch (kind) {
+ case S390_XMNM_LOCR: prefix = "locr"; break;
+ case S390_XMNM_LOCGR: prefix = "locgr"; break;
+ case S390_XMNM_LOC: prefix = "loc"; break;
+ case S390_XMNM_LOCG: prefix = "locg"; break;
+ case S390_XMNM_STOC: prefix = "stoc"; break;
+ case S390_XMNM_STOCG: prefix = "stocg"; break;
+ default:
+ vpanic("cls_operand");
+ }
+
+ return construct_mnemonic(prefix, "", mask);
}
@@ -291,6 +285,7 @@
HChar buf[128]; /* holds the disassembled insn */
HChar *p;
HChar separator;
+ Int mask_suffix = -1;
va_start(args, command);
@@ -350,6 +345,20 @@
mask = va_arg(args, UInt);
p += vex_sprintf(p, s390_mnm_fmt, cab_operand(mnm, mask));
break;
+
+ case S390_XMNM_LOCR:
+ case S390_XMNM_LOCGR:
+ case S390_XMNM_LOC:
+ case S390_XMNM_LOCG:
+ case S390_XMNM_STOC:
+ case S390_XMNM_STOCG:
+ mask = va_arg(args, UInt);
+ mnm = cls_operand(kind, mask);
+ p += vex_sprintf(p, s390_mnm_fmt, mnm);
+ /* There are no special opcodes when mask == 0 or 15. In that case
+ the integer mask is appended as the final operand */
+ if (mask == 0 || mask == 15) mask_suffix = mask;
+ break;
}
}
continue;
@@ -439,6 +448,8 @@
done:
va_end(args);
+ if (mask_suffix != -1)
+ p += vex_sprintf(p, ",%d", mask_suffix);
*p = '\0';
vassert(p < buf + sizeof buf); /* detect buffer overwrite */
diff --git a/priv/host_s390_disasm.h b/priv/host_s390_disasm.h
index c7f75cc..c01aa34 100644
--- a/priv/host_s390_disasm.h
+++ b/priv/host_s390_disasm.h
@@ -75,7 +75,13 @@
S390_XMNM_BCR = 1,
S390_XMNM_BC = 2,
S390_XMNM_BRC = 3,
- S390_XMNM_BRCL = 4
+ S390_XMNM_BRCL = 4,
+ S390_XMNM_LOCR = 5,
+ S390_XMNM_LOCGR = 6,
+ S390_XMNM_LOC = 7,
+ S390_XMNM_LOCG = 8,
+ S390_XMNM_STOC = 9,
+ S390_XMNM_STOCG = 10
};
void s390_disasm(UInt command, ...);
diff --git a/priv/main_util.c b/priv/main_util.c
index d12380e..a4706cf 100644
--- a/priv/main_util.c
+++ b/priv/main_util.c
@@ -235,7 +235,7 @@
New code for vex_util.c should go above this point. */
#include <stdarg.h>
-static Int vex_strlen ( const HChar* str )
+Int vex_strlen ( const HChar* str )
{
Int i = 0;
while (str[i] != 0) i++;
diff --git a/priv/main_util.h b/priv/main_util.h
index 1392b4b..ca63d8c 100644
--- a/priv/main_util.h
+++ b/priv/main_util.h
@@ -73,6 +73,7 @@
/* String ops */
extern Bool vex_streq ( const HChar* s1, const HChar* s2 );
+extern Int vex_strlen ( const HChar* str );
/* Storage management: clear the area, and allocate from it. */