Skip to content

Commit

Permalink
s390x: Support the deflate-conversion facility (DFLTCC)
Browse files Browse the repository at this point in the history
So far the DFLTCC (deflate conversion call) instruction is not supported
by Valgrind.  Similar to PRNO and NNPA, it is a "complex" instruction
whose memory effects cannot be adequately expressed with a dirty helper.

Add support for the DFLTCC instruction using the new "extension" mechanism
and reflect this accordingly in the supported facilities and HWCAPs.
  • Loading branch information
aarnez committed May 15, 2024
1 parent 76f2218 commit fef1d8f
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 5 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ AMD64/macOS 10.13 and nanoMIPS/Linux.

* ================== PLATFORM CHANGES =================

* S390X added support for the DFLTCC instruction provided by the
deflate-conversion facility (z15/arch13).

* ==================== TOOL CHANGES ===================

* ==================== FIXED BUGS ====================
Expand Down
2 changes: 1 addition & 1 deletion VEX/priv/guest_s390_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ s390x_dirtyhelper_STFLE(VexGuestS390XState *guest_state, ULong *addr)
/* 146: MSA8, not supported */
| s390_stfle_range(147, 149)
/* 150: unassigned */
/* 151: DEFLATE-conversion, not supported */
| s390_stfle_range(151, 151)
/* 152: vector packed decimal enhancement, not supported */
/* 153: unassigned */
/* 154: unassigned */
Expand Down
16 changes: 15 additions & 1 deletion VEX/priv/guest_s390_toIR.c
Original file line number Diff line number Diff line change
Expand Up @@ -17105,6 +17105,19 @@ s390_irgen_PPNO(UChar r1, UChar r2)
return "ppno";
}

static const HChar *
s390_irgen_DFLTCC(UChar r3, UChar r1, UChar r2)
{
s390_insn_assert("dfltcc", s390_host_has_dflt);

/* Check for obvious specification exceptions */
s390_insn_assert("dfltcc", r1 % 2 == 0 && r1 != 0 &&
r2 % 2 == 0 && r2 != 0 && r3 >= 2);

extension(S390_EXT_DFLT, r1 | (r2 << 4) | (r3 << 8));
return "dfltcc";
}

enum s390_VStrX {
s390_VStrX_VSTRC,
s390_VStrX_VFAE,
Expand Down Expand Up @@ -20452,7 +20465,8 @@ s390_decode_4byte_and_irgen(const UChar *bytes)
case 0xb931: s390_format_RRE_RR(s390_irgen_CLGFR, RRE_r1(ovl),
RRE_r2(ovl)); goto ok;
case 0xb938: /* SORTL */ goto unimplemented;
case 0xb939: /* DFLTCC */ goto unimplemented;
case 0xb939: s390_format_RRF_R0RR2(s390_irgen_DFLTCC, RRF4_r3(ovl),
RRF4_r1(ovl), RRF4_r2(ovl)); goto ok;
case 0xb93a: /* KDSA */ goto unimplemented;
case 0xb93b: s390_format_E(s390_irgen_NNPA); goto ok;
case 0xb93c: s390_format_RRE_RR(s390_irgen_PPNO, RRE_r1(ovl),
Expand Down
2 changes: 2 additions & 0 deletions VEX/priv/host_s390_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,8 @@ extern UInt s390_host_hwcaps;
(s390_host_hwcaps & (VEX_HWCAPS_S390X_VXE))
#define s390_host_has_nnpa \
(s390_host_hwcaps & (VEX_HWCAPS_S390X_NNPA))
#define s390_host_has_dflt \
(s390_host_hwcaps & (VEX_HWCAPS_S390X_DFLT))
#endif /* ndef __VEX_HOST_S390_DEFS_H */

/*---------------------------------------------------------------*/
Expand Down
3 changes: 2 additions & 1 deletion VEX/priv/main_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1824,7 +1824,8 @@ static const HChar* show_hwcaps_s390x ( UInt hwcaps )
{ VEX_HWCAPS_S390X_MSA5, "msa5" },
{ VEX_HWCAPS_S390X_MI2, "mi2" },
{ VEX_HWCAPS_S390X_LSC2, "lsc2" },
{ VEX_HWCAPS_S390X_LSC2, "vxe" },
{ VEX_HWCAPS_S390X_VXE, "vxe" },
{ VEX_HWCAPS_S390X_DFLT, "dflt" },
};
/* Allocate a large enough buffer */
static HChar buf[sizeof prefix +
Expand Down
4 changes: 3 additions & 1 deletion VEX/pub/libvex.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ typedef
#define VEX_HWCAPS_S390X_LSC2 (1<<21) /* Conditional load/store facility2 */
#define VEX_HWCAPS_S390X_VXE (1<<22) /* Vector-enhancements facility */
#define VEX_HWCAPS_S390X_NNPA (1<<23) /* NNPA facility */
#define VEX_HWCAPS_S390X_DFLT (1<<24) /* Deflate-conversion facility */

/* Special value representing all available s390x hwcaps */
#define VEX_HWCAPS_S390X_ALL (VEX_HWCAPS_S390X_LDISP | \
Expand All @@ -197,7 +198,8 @@ typedef
VEX_HWCAPS_S390X_MI2 | \
VEX_HWCAPS_S390X_LSC2 | \
VEX_HWCAPS_S390X_VXE | \
VEX_HWCAPS_S390X_NNPA)
VEX_HWCAPS_S390X_NNPA | \
VEX_HWCAPS_S390X_DFLT)

#define VEX_HWCAPS_S390X(x) ((x) & ~VEX_S390X_MODEL_MASK)
#define VEX_S390X_MODEL(x) ((x) & VEX_S390X_MODEL_MASK)
Expand Down
1 change: 1 addition & 0 deletions VEX/pub/libvex_s390x_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@

#define S390_EXT_PRNO 1
#define S390_EXT_NNPA 2
#define S390_EXT_DFLT 3

/*--------------------------------------------------------------*/
/*--- Miscellaneous ---*/
Expand Down
168 changes: 168 additions & 0 deletions coregrind/m_extension/extension-s390x.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,172 @@ static enum ExtensionError do_extension_NNPA(ThreadState* tst, ULong variant)
return ExtErr_OK;
}

/*---------------------------------------------------------------*/
/*--- DFLTCC (deflate conversion call) ---*/
/*---------------------------------------------------------------*/

static Int do_DFLTCC_insn(UChar func,
ULong parms,
ULong* addr1,
ULong* len1,
ULong* addr2,
ULong* len2,
ULong addr3)
{
register UChar reg0 asm("0") = func;
register void* reg1 asm("1") = (void*)parms;
union reg_pair op1 = {{*addr1, *len1}};
union reg_pair op2 = {{*addr2, *len2}};
Int cc;

asm volatile(".insn rrf, 0xb9390000, %[op1], %[op2], %[op3], 0\n"
"ipm %[cc]\n"
"srl %[cc], 28\n"
: [cc] "=d"(cc), [op1] "+a"(op1.pair), [op2] "+a"(op2.pair)
: "d"(reg0), "d"(reg1), [op3] "d"(addr3)
: "cc", "memory");
*addr1 = op1.a;
*len1 = op1.b;
*addr2 = op2.a;
*len2 = op2.b;
return cc;
}

struct s390_DFLTCC_parms0 {
UShort pbvn;
UChar mvn;
UChar ribm[3];
UShort reserved0 : 15;
UShort cf : 1;
ULong reserved1;
UShort nt : 1;
UShort reserved2 : 1;
UShort cvt : 1;
UShort reserved3 : 1;
UShort htt : 1;
UShort bcf : 1;
UShort bcc : 1;
UShort bhf : 1;
UShort reserved4 : 1;
UShort reserved5 : 1;
UShort dhtgc : 1;
UShort reserved6 : 5;
UChar reserved7 : 5;
UChar sbb : 3;
UChar oesc : 8;
UShort reserved8 : 12;
UShort ifs : 4;
UShort ifl;
UChar reserved9[20];
UShort hl;
UShort reserved10 : 1;
UShort ho : 15;
UChar data[1488];
};

/* DFLTCC functions that we support if the hardware does. */
static const ULong DFLTCC_functions[] = {
(S390_SETBIT(0) // Query
| S390_SETBIT(1) // GDHT
| S390_SETBIT(2) // CMPR
| S390_SETBIT(4)), // XPND
};

static UWord do_extension_DFLTCC(ThreadState* tst, ULong variant)
{
enum { circ_hist_len = 32768 };
UChar r1 = variant & 0xf;
UChar r2 = (variant >> 4) & 0xf;
UChar r3 = (variant >> 8) & 0xf;
UChar func = READ_FUNCTION_CODE(tst, "DFLTCC");
UChar fc = func & 0x7f;
Bool hbt = (func & 128) != 0;
ULong parms = READ_GPR(tst, "DFLTCC(r1)", 1);
ULong parms_len;
Int cc = 0;
ULong orig_addr1 = 0, orig_len1 = 0;
ULong addr1 = 0, len1 = 0, addr2 = 0, len2 = 0, addr3 = 0;
Bool do_compress = 0;

switch (fc) {
case 0: // Query
parms_len = 32;
PRE_MEM_WRITE(tst, "DFLTCC(parms)", parms, parms_len);
cc = do_DFLTCC_insn(func, parms, &addr1, &len1, &addr2, &len2, addr3);
s390_filter_functions((ULong*)parms, 16, DFLTCC_functions,
sizeof(DFLTCC_functions));
POST_MEM_WRITE(tst, parms, parms_len);
break;
case 1: // GDHT
parms_len = 384;
PRE_MEM_READ(tst, "DFLTCC(parms)", parms, parms_len);
PRE_MEM_WRITE(tst, "DFLTCC(parms)", parms, parms_len);
addr2 = READ_GPR(tst, "DFLTCC(op2_addr)", r2);
len2 = READ_GPR(tst, "DFLTCC(op2_len)", r2 + 1);
if (len2 > 32768)
len2 = 32768;
PRE_MEM_READ(tst, "DFLTCC(parms)", addr2, len2);
cc = do_DFLTCC_insn(func, parms, &addr1, &len1, &addr2, &len2, addr3);
POST_MEM_WRITE(tst, parms, parms_len);
break;
case 2: // CMPR
do_compress = 1;
/* fallthrough */
case 4: // XPND
{
struct s390_DFLTCC_parms0* p;
parms_len = 1536;
PRE_MEM_READ(tst, "DFLTCC(parms)", parms, parms_len);
p = (void*)parms;
addr1 = orig_addr1 = READ_GPR(tst, "DFLTCC(op1_addr)", r1);
len1 = orig_len1 = READ_GPR(tst, "DFLTCC(op1_len)", r1 + 1);
PRE_MEM_WRITE(tst, "DFLTCC(op1)", addr1, len1);
addr2 = READ_GPR(tst, "DFLTCC(op2_addr)", r2);
len2 = READ_GPR(tst, "DFLTCC(op2_len)", r2 + 1);
PRE_MEM_READ(tst, "DFLTCC(op2)", addr2, len2);
addr3 = READ_GPR(tst, "DFLTCC(op3)", r3);
if (hbt) {
PRE_MEM_WRITE(tst, "DFLTCC(op3)", addr3, circ_hist_len);
}
if (!p->nt) {
if (hbt) {
ULong hl1 = circ_hist_len - p->ho;
if (hl1 >= p->hl) {
hl1 = p->hl;
} else {
PRE_MEM_READ(tst, "DFLTCC(op3)", addr3, p->hl - hl1);
}
PRE_MEM_READ(tst, "DFLTCC(op3)", addr3 + p->ho, hl1);
} else {
PRE_MEM_READ(tst, "DFLTCC(op2.hist)", addr2 - p->hl, p->hl);
}
}
cc = do_DFLTCC_insn(func, parms, &addr1, &len1, &addr2, &len2, addr3);
POST_MEM_WRITE(tst, parms, parms_len);
POST_MEM_WRITE(tst, orig_addr1,
orig_len1 - len1 + (do_compress && p->sbb ? 1 : 0));
if (hbt) {
ULong hl1 = circ_hist_len - p->ho;
if (hl1 >= p->hl) {
hl1 = p->hl;
} else {
POST_MEM_WRITE(tst, addr3, p->hl - hl1);
}
POST_MEM_WRITE(tst, addr3 + p->ho, hl1);
}
WRITE_GPR(tst, r1, addr1);
WRITE_GPR(tst, r1 + 1, len1);
WRITE_GPR(tst, r2, addr2);
WRITE_GPR(tst, r2 + 1, len2);
break;
}
default:
return INSN_ERR("DFLTCC: unknown function code\n");
}
WRITE_CC(tst, cc);
return ExtErr_OK;
}

/*---------------------------------------------------------------*/
/*--- Main function: select and call appropriate extension ---*/
/*---------------------------------------------------------------*/
Expand All @@ -600,6 +766,8 @@ enum ExtensionError ML_(do_client_extension)(ThreadState* tst)
return do_extension_PRNO(tst, variant);
case S390_EXT_NNPA:
return do_extension_NNPA(tst, variant);
case S390_EXT_DFLT:
return do_extension_DFLTCC(tst, variant);
default:
VG_(core_panic)("unknown extension ID");
}
Expand Down
1 change: 1 addition & 0 deletions coregrind/m_initimg/initimg-linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,7 @@ Addr setup_client_stack( void* init_sp,
| VKI_HWCAP_S390_VXRS
| VKI_HWCAP_S390_VXRS_EXT
| VKI_HWCAP_S390_VXRS_EXT2
| VKI_HWCAP_S390_DFLT
| VKI_HWCAP_S390_NNPA);
}
# elif defined(VGP_arm64_linux)
Expand Down
1 change: 1 addition & 0 deletions coregrind/m_machine.c
Original file line number Diff line number Diff line change
Expand Up @@ -1597,6 +1597,7 @@ Bool VG_(machine_get_hwcaps)( void )
{ False, S390_FAC_MI2, VEX_HWCAPS_S390X_MI2, "MI2" },
{ False, S390_FAC_LSC2, VEX_HWCAPS_S390X_LSC2, "LSC2" },
{ False, S390_FAC_VXE, VEX_HWCAPS_S390X_VXE, "VXE" },
{ False, S390_FAC_DFLT, VEX_HWCAPS_S390X_DFLT, "DFLT" },
{ False, S390_FAC_NNPA, VEX_HWCAPS_S390X_NNPA, "NNPA" },
};

Expand Down
2 changes: 1 addition & 1 deletion docs/internals/s390-opcodes.csv
Original file line number Diff line number Diff line change
Expand Up @@ -1743,7 +1743,7 @@ wcfeb,"vector fp convert to fixed 32 bit",implemented,arch13
vclfp,"vector fp convert to logical",implemented,arch13
vclfeb,"vector fp convert to logical 32 bit",implemented,arch13
wclfeb,"vector fp convert to logical 32 bit",implemented,arch13
dfltcc,"deflate conversion call","not implemented",arch13
dfltcc,"deflate conversion call",implemented,arch13
sortl,"sort lists","not implemented",arch13
kdsa,"compute digital signature authentication","not implemented",arch13
vschp,"decimal scale and convert to hfp","not implemented",arch14
Expand Down
1 change: 1 addition & 0 deletions include/vki/vki-s390x-linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,7 @@ typedef vki_s390_regs vki_elf_gregset_t;
#define VKI_HWCAP_S390_VXRS 2048
#define VKI_HWCAP_S390_VXRS_EXT 8192
#define VKI_HWCAP_S390_VXRS_EXT2 32768
#define VKI_HWCAP_S390_DFLT (1<<18)
#define VKI_HWCAP_S390_NNPA (1<<20)


Expand Down

0 comments on commit fef1d8f

Please sign in to comment.