mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 10:05:29 +00:00
Bug 385412 - s390x: new non-vector z13 instructions not implemented
Apart from instructions with vector operands, Valgrind does not implement the additional z/Architecture instructions introduced with z13. These are: - load and zero rightmost byte (LZRF, LZRG); - load logical and zero rightmost byte (LLZRGF); - load halfword high immediate on condition (LOCHHI); - load halfword immediate on condition (LOCHI, LOCGHI); - load high on condition (LOCFHR, LOCFH); - store high on condition (STOCFH); - perform pseudorandom number operation (PPNO), with the functions PPNO-Query and PPNO-SHA-512-DRNG; - load count to block boundary (LCBB). Patches from Vadim Barkov (vbrkov@gmail.com), with coordination, testing and format cleanups from Andreas Arnez (arnez@linux.ibm.com).
This commit is contained in:
parent
53cf5739b3
commit
d44563c49e
2
.gitignore
vendored
2
.gitignore
vendored
@ -1875,6 +1875,8 @@
|
||||
/none/tests/s390x/fixbr
|
||||
/none/tests/s390x/popcnt
|
||||
/none/tests/s390x/vector
|
||||
/none/tests/s390x/lsc2
|
||||
/none/tests/s390x/ppno
|
||||
|
||||
# /none/tests/scripts/
|
||||
/none/tests/scripts/*.dSYM
|
||||
|
||||
@ -95,7 +95,9 @@ UInt s390_do_cvb(ULong decimal);
|
||||
ULong s390_do_cvd(ULong binary);
|
||||
ULong s390_do_ecag(ULong op2addr);
|
||||
UInt s390_do_pfpo(UInt gpr0);
|
||||
|
||||
void s390x_dirtyhelper_PPNO_query(VexGuestS390XState *guest_state, ULong r1, ULong r2);
|
||||
ULong s390x_dirtyhelper_PPNO_sha512(VexGuestS390XState *guest_state, ULong r1, ULong r2);
|
||||
void s390x_dirtyhelper_PPNO_sha512_load_param_block( void );
|
||||
/* The various ways to compute the condition code. */
|
||||
enum {
|
||||
S390_CC_OP_BITWISE = 0,
|
||||
|
||||
@ -365,6 +365,7 @@ s390x_dirtyhelper_STFLE(VexGuestS390XState *guest_state, ULong *addr)
|
||||
s390_set_facility_bit(addr, S390_FAC_GIE, 1);
|
||||
s390_set_facility_bit(addr, S390_FAC_EXEXT, 1);
|
||||
s390_set_facility_bit(addr, S390_FAC_HIGHW, 1);
|
||||
s390_set_facility_bit(addr, S390_FAC_LSC2, 1);
|
||||
|
||||
s390_set_facility_bit(addr, S390_FAC_HFPMAS, 0);
|
||||
s390_set_facility_bit(addr, S390_FAC_HFPUNX, 0);
|
||||
@ -2525,6 +2526,75 @@ s390x_dirtyhelper_vec_binop(VexGuestS390XState *guest_state, ULong opcode,
|
||||
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/*--- Dirty helper for Perform Pseudorandom number instruction ---*/
|
||||
/*-----------------------------------------------------------------*/
|
||||
|
||||
/* Dummy helper that is needed to indicate load of parameter block.
|
||||
We have to use it because dirty helper cannot have two memory side
|
||||
effects.
|
||||
*/
|
||||
void s390x_dirtyhelper_PPNO_sha512_load_param_block( void )
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(VGA_s390x)
|
||||
|
||||
/* IMPORTANT!
|
||||
We return here bit mask where only supported functions are set to one.
|
||||
If you implement new functions don't forget the supported array.
|
||||
*/
|
||||
void
|
||||
s390x_dirtyhelper_PPNO_query(VexGuestS390XState *guest_state, ULong r1, ULong r2)
|
||||
{
|
||||
ULong supported[2] = {0x9000000000000000ULL, 0x0000000000000000ULL};
|
||||
ULong *result = (ULong*) guest_state->guest_r1;
|
||||
|
||||
result[0] = supported[0];
|
||||
result[1] = supported[1];
|
||||
}
|
||||
|
||||
ULong
|
||||
s390x_dirtyhelper_PPNO_sha512(VexGuestS390XState *guest_state, ULong r1, ULong r2)
|
||||
{
|
||||
ULong* op1 = (ULong*) (((ULong)(&guest_state->guest_r0)) + r1 * sizeof(ULong));
|
||||
ULong* op2 = (ULong*) (((ULong)(&guest_state->guest_r0)) + r2 * sizeof(ULong));
|
||||
|
||||
register ULong reg0 asm("0") = guest_state->guest_r0;
|
||||
register ULong reg1 asm("1") = guest_state->guest_r1;
|
||||
register ULong reg2 asm("2") = op1[0];
|
||||
register ULong reg3 asm("3") = op1[1];
|
||||
register ULong reg4 asm("4") = op2[0];
|
||||
register ULong reg5 asm("5") = op2[1];
|
||||
|
||||
ULong cc = 0;
|
||||
asm volatile(".insn rre, 0xb93c0000, %%r2, %%r4\n"
|
||||
"ipm %[cc]\n"
|
||||
"srl %[cc], 28\n"
|
||||
: "+d"(reg0), "+d"(reg1),
|
||||
"+d"(reg2), "+d"(reg3),
|
||||
"+d"(reg4), "+d"(reg5),
|
||||
[cc] "=d"(cc)
|
||||
:
|
||||
: "cc", "memory");
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
s390x_dirtyhelper_PPNO_query(VexGuestS390XState *guest_state, ULong r1, ULong r2)
|
||||
{
|
||||
}
|
||||
|
||||
ULong
|
||||
s390x_dirtyhelper_PPNO_sha512(VexGuestS390XState *guest_state, ULong r1, ULong r2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* VGA_s390x */
|
||||
/*---------------------------------------------------------------*/
|
||||
/*--- end guest_s390_helpers.c ---*/
|
||||
/*---------------------------------------------------------------*/
|
||||
|
||||
@ -2243,6 +2243,18 @@ s390_format_RIE_RUPI(const HChar *(*irgen)(UChar r1, UChar m3, UShort i4,
|
||||
(Int)(Char)i2, m3, (Int)(Short)i4);
|
||||
}
|
||||
|
||||
static void
|
||||
s390_format_RIE_RUPIX(const HChar *(*irgen)(UChar r1, UChar m3, UShort i4,
|
||||
UChar i2),
|
||||
UChar r1, UChar m3, UShort i4, UChar i2, Int xmnm_kind)
|
||||
{
|
||||
const HChar *mnm = irgen(r1, m3, i4, i2);
|
||||
|
||||
if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
|
||||
s390_disasm(ENC5(XMNM, GPR, INT, CABM, PCREL), xmnm_kind, mnm, m3, r1,
|
||||
(Int)(Char)i2, m3, (Int)(Short)i4);
|
||||
}
|
||||
|
||||
static void
|
||||
s390_format_RIL(const HChar *(*irgen)(UChar r1, UInt i2),
|
||||
UChar r1, UInt i2)
|
||||
@ -2787,6 +2799,23 @@ s390_format_RXE_FRRD(const HChar *(*irgen)(UChar r1, IRTemp op2addr),
|
||||
s390_disasm(ENC3(MNM, FPR, UDXB), mnm, r1, d2, x2, b2);
|
||||
}
|
||||
|
||||
static void
|
||||
s390_format_RXE_RRRDR(const HChar *(*irgen)(UChar r1, IRTemp op2addr, UChar m3),
|
||||
UChar r1, UChar x2, UChar b2, UShort d2, UChar m3)
|
||||
{
|
||||
const HChar *mnm;
|
||||
IRTemp op2addr = newTemp(Ity_I64);
|
||||
|
||||
assign(op2addr, binop(Iop_Add64, binop(Iop_Add64, mkU64(d2),
|
||||
b2 != 0 ? get_gpr_dw0(b2) : mkU64(0)), x2 != 0 ? get_gpr_dw0(x2) :
|
||||
mkU64(0)));
|
||||
|
||||
mnm = irgen(r1, op2addr, m3);
|
||||
|
||||
if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
|
||||
s390_disasm(ENC3(MNM, GPR, UDXB), mnm, r1, d2, x2, b2);
|
||||
}
|
||||
|
||||
static void
|
||||
s390_format_RXF_FRRDF(const HChar *(*irgen)(UChar, IRTemp, UChar),
|
||||
UChar r3, UChar x2, UChar b2, UShort d2, UChar r1)
|
||||
@ -15699,6 +15728,288 @@ s390_irgen_VNO(UChar v1, UChar v2, UChar v3)
|
||||
return "vno";
|
||||
}
|
||||
|
||||
static const HChar *
|
||||
s390_irgen_LZRF(UChar r1, IRTemp op2addr)
|
||||
{
|
||||
IRTemp op2 = newTemp(Ity_I32);
|
||||
|
||||
assign(op2, binop(Iop_And32, load(Ity_I32, mkexpr(op2addr)), mkU32(0xffffff00)));
|
||||
put_gpr_w1(r1, mkexpr(op2));
|
||||
|
||||
return "lzrf";
|
||||
}
|
||||
|
||||
static const HChar *
|
||||
s390_irgen_LZRG(UChar r1, IRTemp op2addr)
|
||||
{
|
||||
IRTemp op2 = newTemp(Ity_I64);
|
||||
|
||||
assign(op2, binop(Iop_And64, load(Ity_I64, mkexpr(op2addr)), mkU64(0xffffffffffffff00UL)));
|
||||
put_gpr_dw0(r1, mkexpr(op2));
|
||||
|
||||
return "lzrg";
|
||||
}
|
||||
|
||||
static const HChar *
|
||||
s390_irgen_LLZRGF(UChar r1, IRTemp op2addr)
|
||||
{
|
||||
IRTemp op2 = newTemp(Ity_I32);
|
||||
|
||||
assign(op2, binop(Iop_And32, load(Ity_I32, mkexpr(op2addr)), mkU32(0xffffff00)));
|
||||
put_gpr_w1(r1, mkexpr(op2));
|
||||
put_gpr_w0(r1, mkU32(0));
|
||||
|
||||
return "llzrgf";
|
||||
}
|
||||
|
||||
static const HChar *
|
||||
s390_irgen_LOCFH(UChar r1, IRTemp op2addr)
|
||||
{
|
||||
/* condition is checked in format handler */
|
||||
put_gpr_w0(r1, load(Ity_I32, mkexpr(op2addr)));
|
||||
|
||||
return "locfh";
|
||||
}
|
||||
|
||||
static const HChar *
|
||||
s390_irgen_LOCFHR(UChar m3, UChar r1, UChar r2)
|
||||
{
|
||||
next_insn_if(binop(Iop_CmpEQ32, s390_call_calculate_cond(m3), mkU32(0)));
|
||||
put_gpr_w0(r1, get_gpr_w0(r2));
|
||||
|
||||
return "locfhr";
|
||||
}
|
||||
|
||||
static const HChar *
|
||||
s390_irgen_LOCHHI(UChar r1, UChar m3, UShort i2, UChar unused)
|
||||
{
|
||||
next_insn_if(binop(Iop_CmpEQ32, s390_call_calculate_cond(m3), mkU32(0)));
|
||||
put_gpr_w0(r1, mkU32(i2));
|
||||
|
||||
return "lochhi";
|
||||
}
|
||||
|
||||
static const HChar *
|
||||
s390_irgen_LOCHI(UChar r1, UChar m3, UShort i2, UChar unused)
|
||||
{
|
||||
next_insn_if(binop(Iop_CmpEQ32, s390_call_calculate_cond(m3), mkU32(0)));
|
||||
put_gpr_w1(r1, mkU32(i2));
|
||||
|
||||
return "lochi";
|
||||
}
|
||||
|
||||
static const HChar *
|
||||
s390_irgen_LOCGHI(UChar r1, UChar m3, UShort i2, UChar unused)
|
||||
{
|
||||
next_insn_if(binop(Iop_CmpEQ32, s390_call_calculate_cond(m3), mkU32(0)));
|
||||
put_gpr_dw0(r1, mkU64(i2));
|
||||
|
||||
return "locghi";
|
||||
}
|
||||
|
||||
static const HChar *
|
||||
s390_irgen_STOCFH(UChar r1, IRTemp op2addr)
|
||||
{
|
||||
/* condition is checked in format handler */
|
||||
store(mkexpr(op2addr), get_gpr_w1(r1));
|
||||
|
||||
return "stocfh";
|
||||
}
|
||||
|
||||
static const HChar *
|
||||
s390_irgen_LCBB(UChar r1, IRTemp op2addr, UChar m3)
|
||||
{
|
||||
IRTemp op2 = newTemp(Ity_I32);
|
||||
assign(op2, s390_getCountToBlockBoundary(op2addr, m3));
|
||||
put_gpr_w1(r1, mkexpr(op2));
|
||||
|
||||
IRExpr* cc = mkite(binop(Iop_CmpEQ32, mkexpr(op2), mkU32(16)), mkU64(0), mkU64(3));
|
||||
s390_cc_thunk_fill(mkU64(S390_CC_OP_SET), cc, mkU64(0), mkU64(0));
|
||||
|
||||
return "lcbb";
|
||||
}
|
||||
|
||||
/* Regarding the use of
|
||||
// Dummy helper which is used to signal VEX library that memory was loaded
|
||||
sha512_loadparam
|
||||
= unsafeIRDirty_0_N(0, "s390x_dirtyhelper_PPNO_sha512_load_param_block",
|
||||
&s390x_dirtyhelper_PPNO_sha512_load_param_block,
|
||||
mkIRExprVec_0());
|
||||
|
||||
in the following function (s390_irgen_PPNO). This is a workaround to get
|
||||
around the fact that IRDirty annotations cannot indicate two memory side
|
||||
effects, which are unfortunately necessary here. It will possibly lead to
|
||||
losing undefinedness (undefinedness in some inputs might not be propagated
|
||||
to the outputs as it shouod, in Memcheck). The correct fix would be to
|
||||
extend IRDirty to represent two memory side effects, but that's quite a bit
|
||||
of work.
|
||||
|
||||
Here's a summary of what this insn does.
|
||||
|
||||
// getReg(RegisterNumber n) returns the value of GPR number 'n'
|
||||
|
||||
// reg1 and reg2 are even
|
||||
void ppno(RegisterNumber reg1, RegisterNumber reg2) {
|
||||
|
||||
switch(getReg(0)) {
|
||||
case 0x0:
|
||||
// Query mode, ignore reg1 and reg2
|
||||
// Write 16 bytes at getReg(1)
|
||||
break;
|
||||
|
||||
case 0x3:
|
||||
// SHA-512 generate mode, ignore reg2
|
||||
|
||||
// Read 240 bytes at getReg(1)
|
||||
// Write getReg(reg1 + 1) bytes at getReg(reg1)
|
||||
// Write some of 240 bytes starting at getReg(1)
|
||||
break;
|
||||
|
||||
case 0x83:
|
||||
// SHA-512 seed mode, ignore reg1
|
||||
|
||||
// Read some of 240 bytes starting at getReg(1)
|
||||
// Read getReg(reg2 + 1) bytes at getReg(reg2)
|
||||
// Write 240 bytes at getReg(1)
|
||||
break;
|
||||
|
||||
default:
|
||||
// Specification exception, abort execution.
|
||||
}
|
||||
}
|
||||
*/
|
||||
/* Also known as "prno"
|
||||
If you implement new functions please don't forget to update
|
||||
"s390x_dirtyhelper_PPNO_query" function.
|
||||
*/
|
||||
static const HChar *
|
||||
s390_irgen_PPNO(UChar r1, UChar r2)
|
||||
{
|
||||
if (!s390_host_has_msa5) {
|
||||
emulation_failure(EmFail_S390X_ppno);
|
||||
return "ppno";
|
||||
}
|
||||
|
||||
/* Theese conditions lead to specification exception */
|
||||
vassert(r1 % 2 == 0);
|
||||
vassert(r2 % 2 == 0);
|
||||
vassert((r1 != 0) && (r2 != 0));
|
||||
|
||||
IRDirty *query, *sha512_gen, *sha512_seed, *sha512_loadparam;
|
||||
IRTemp gpr1num = newTemp(Ity_I64);
|
||||
IRTemp gpr2num = newTemp(Ity_I64);
|
||||
|
||||
IRTemp funcCode = newTemp(Ity_I8);
|
||||
IRTemp is_query = newTemp(Ity_I1);
|
||||
IRTemp is_sha512_gen = newTemp(Ity_I1);
|
||||
IRTemp is_sha512_seed = newTemp(Ity_I1);
|
||||
IRTemp is_sha512 = newTemp(Ity_I1);
|
||||
|
||||
assign(funcCode, unop(Iop_64to8, binop(Iop_And64, get_gpr_dw0(0), mkU64(0xffULL))));
|
||||
assign(gpr1num, mkU64(r1));
|
||||
assign(gpr2num, mkU64(r2));
|
||||
|
||||
assign(is_query, binop(Iop_CmpEQ8, mkexpr(funcCode), mkU8(S390_PPNO_QUERY)));
|
||||
assign(is_sha512_gen, binop(Iop_CmpEQ8, mkexpr(funcCode), mkU8(S390_PPNO_SHA512_GEN)));
|
||||
assign(is_sha512_seed, binop(Iop_CmpEQ8, mkexpr(funcCode), mkU8(S390_PPNO_SHA512_SEED)));
|
||||
assign(is_sha512, binop(Iop_CmpEQ8,
|
||||
mkU8(S390_PPNO_SHA512_GEN),
|
||||
binop(Iop_And8,
|
||||
mkexpr(funcCode),
|
||||
mkU8(S390_PPNO_SHA512_GEN)
|
||||
)
|
||||
));
|
||||
|
||||
query = unsafeIRDirty_0_N(0, "s390x_dirtyhelper_PPNO_query",
|
||||
&s390x_dirtyhelper_PPNO_query,
|
||||
mkIRExprVec_3(IRExpr_GSPTR(), mkexpr(gpr1num), mkexpr(gpr2num)));
|
||||
query->guard = mkexpr(is_query);
|
||||
query->nFxState = 1;
|
||||
vex_bzero(&query->fxState, sizeof(query->fxState));
|
||||
query->fxState[0].fx = Ifx_Read;
|
||||
query->fxState[0].offset = S390X_GUEST_OFFSET(guest_r0);
|
||||
query->fxState[0].size = 2 * sizeof(ULong); /* gpr0 and gpr1 are read */
|
||||
query->mAddr = get_gpr_dw0(1);
|
||||
query->mSize = S390_PPNO_PARAM_BLOCK_SIZE_QUERY;
|
||||
query->mFx = Ifx_Write;
|
||||
|
||||
IRTemp gen_cc = newTemp(Ity_I64);
|
||||
sha512_gen = unsafeIRDirty_1_N(gen_cc, 0, "s390x_dirtyhelper_PPNO_sha512",
|
||||
&s390x_dirtyhelper_PPNO_sha512,
|
||||
mkIRExprVec_3(IRExpr_GSPTR(), mkexpr(gpr1num), mkexpr(gpr2num)));
|
||||
sha512_gen->guard = mkexpr(is_sha512_gen);
|
||||
sha512_gen->nFxState = 3;
|
||||
vex_bzero(&sha512_gen->fxState, sizeof(sha512_gen->fxState));
|
||||
sha512_gen->fxState[0].fx = Ifx_Read;
|
||||
sha512_gen->fxState[0].offset = S390X_GUEST_OFFSET(guest_r0);
|
||||
sha512_gen->fxState[0].size = 2 * sizeof(ULong); /* gpr0 and gpr1 are read */
|
||||
sha512_gen->fxState[1].fx = Ifx_Read;
|
||||
sha512_gen->fxState[1].offset = S390X_GUEST_OFFSET(guest_r0) + r1 * sizeof(ULong);
|
||||
sha512_gen->fxState[1].size = sizeof(ULong);
|
||||
sha512_gen->fxState[2].fx = Ifx_Modify;
|
||||
sha512_gen->fxState[2].offset = S390X_GUEST_OFFSET(guest_r0) + (r1 + 1) * sizeof(ULong);
|
||||
sha512_gen->fxState[2].size = sizeof(ULong);
|
||||
sha512_gen->mAddr = get_gpr_dw0(r1);
|
||||
sha512_gen->mSize = S390_PPNO_MAX_SIZE_SHA512_GEN;
|
||||
sha512_gen->mFx = Ifx_Write;
|
||||
|
||||
IRTemp unused = newTemp(Ity_I64);
|
||||
sha512_seed = unsafeIRDirty_1_N(unused, 0, "s390x_dirtyhelper_PPNO_sha512",
|
||||
&s390x_dirtyhelper_PPNO_sha512,
|
||||
mkIRExprVec_3(IRExpr_GSPTR(), mkexpr(gpr1num), mkexpr(gpr2num)));
|
||||
sha512_seed->guard = mkexpr(is_sha512_seed);
|
||||
sha512_seed->nFxState = 2;
|
||||
vex_bzero(&sha512_seed->fxState, sizeof(sha512_seed->fxState));
|
||||
sha512_seed->fxState[0].fx = Ifx_Read;
|
||||
sha512_seed->fxState[0].offset = S390X_GUEST_OFFSET(guest_r0);
|
||||
sha512_seed->fxState[0].size = 2 * sizeof(ULong); /* gpr0 and gpr1 are read */
|
||||
sha512_seed->fxState[1].fx = Ifx_Read;
|
||||
sha512_seed->fxState[1].offset = S390X_GUEST_OFFSET(guest_r0) + r2 * sizeof(ULong);
|
||||
sha512_seed->fxState[1].size = 2 * sizeof(ULong); /* r2 and r2 + 1 are read */
|
||||
sha512_seed->mAddr = get_gpr_dw0(r2);
|
||||
sha512_seed->mSize = S390_PPNO_MAX_SIZE_SHA512_SEED;
|
||||
sha512_seed->mFx = Ifx_Write;
|
||||
|
||||
/* Dummy helper which is used to signal VEX library that memory was loaded */
|
||||
sha512_loadparam = unsafeIRDirty_0_N(0, "s390x_dirtyhelper_PPNO_sha512_load_param_block",
|
||||
&s390x_dirtyhelper_PPNO_sha512_load_param_block,
|
||||
mkIRExprVec_0());
|
||||
sha512_loadparam->guard = mkexpr(is_sha512);
|
||||
sha512_loadparam->nFxState = 0;
|
||||
vex_bzero(&sha512_loadparam->fxState, sizeof(sha512_loadparam->fxState));
|
||||
sha512_loadparam->mAddr = get_gpr_dw0(1);
|
||||
sha512_loadparam->mSize = S390_PPNO_PARAM_BLOCK_SIZE_SHA512;
|
||||
sha512_loadparam->mFx = Ifx_Read;
|
||||
|
||||
IRDirty*
|
||||
sha512_saveparam = unsafeIRDirty_0_N(0, "s390x_dirtyhelper_PPNO_sha512_save_param_block",
|
||||
&s390x_dirtyhelper_PPNO_sha512_load_param_block,
|
||||
mkIRExprVec_0());
|
||||
sha512_saveparam->guard = mkexpr(is_sha512);
|
||||
sha512_saveparam->nFxState = 0;
|
||||
vex_bzero(&sha512_saveparam->fxState, sizeof(sha512_saveparam->fxState));
|
||||
sha512_saveparam->mAddr = get_gpr_dw0(1);
|
||||
sha512_saveparam->mSize = S390_PPNO_PARAM_BLOCK_SIZE_SHA512;
|
||||
sha512_saveparam->mFx = Ifx_Write;
|
||||
|
||||
stmt(IRStmt_Dirty(query));
|
||||
stmt(IRStmt_Dirty(sha512_loadparam));
|
||||
stmt(IRStmt_Dirty(sha512_gen));
|
||||
stmt(IRStmt_Dirty(sha512_seed));
|
||||
stmt(IRStmt_Dirty(sha512_saveparam));
|
||||
|
||||
IRTemp cc = newTemp(Ity_I64);
|
||||
assign(cc,
|
||||
mkite(mkexpr(is_sha512_gen),
|
||||
mkexpr(gen_cc),
|
||||
mkU64(0)
|
||||
)
|
||||
);
|
||||
|
||||
s390_cc_thunk_fill(mkU64(S390_CC_OP_SET), mkexpr(cc), mkU64(0), mkU64(0));
|
||||
|
||||
return "ppno";
|
||||
}
|
||||
|
||||
/* New insns are added here.
|
||||
If an insn is contingent on a facility being installed also
|
||||
@ -16590,7 +16901,8 @@ s390_decode_4byte_and_irgen(const UChar *bytes)
|
||||
ovl.fmt.RRE.r2); goto ok;
|
||||
case 0xb931: s390_format_RRE_RR(s390_irgen_CLGFR, ovl.fmt.RRE.r1,
|
||||
ovl.fmt.RRE.r2); goto ok;
|
||||
case 0xb93c: /* PPNO */ goto unimplemented;
|
||||
case 0xb93c: s390_format_RRE_RR(s390_irgen_PPNO, ovl.fmt.RRE.r1,
|
||||
ovl.fmt.RRE.r2); goto ok;
|
||||
case 0xb93e: /* KIMD */ goto unimplemented;
|
||||
case 0xb93f: /* KLMD */ goto unimplemented;
|
||||
case 0xb941: s390_format_RRF_UURF(s390_irgen_CFDTR, ovl.fmt.RRF2.m3,
|
||||
@ -16733,7 +17045,9 @@ s390_decode_4byte_and_irgen(const UChar *bytes)
|
||||
ovl.fmt.RRE.r2); goto ok;
|
||||
case 0xb9df: s390_format_RRE_RR(s390_irgen_CLHLR, ovl.fmt.RRE.r1,
|
||||
ovl.fmt.RRE.r2); goto ok;
|
||||
case 0xb9e0: /* LOCFHR */ goto unimplemented;
|
||||
case 0xb9e0: s390_format_RRF_U0RR(s390_irgen_LOCFHR, ovl.fmt.RRF3.r3,
|
||||
ovl.fmt.RRF3.r1, ovl.fmt.RRF3.r2,
|
||||
S390_XMNM_LOCFHR); goto ok;
|
||||
case 0xb9e1: s390_format_RRE_RR(s390_irgen_POPCNT, ovl.fmt.RRE.r1,
|
||||
ovl.fmt.RRE.r2); goto ok;
|
||||
case 0xb9e2: s390_format_RRF_U0RR(s390_irgen_LOCGR, ovl.fmt.RRF3.r3,
|
||||
@ -17310,7 +17624,10 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
|
||||
ovl.fmt.RXY.x2, ovl.fmt.RXY.b2,
|
||||
ovl.fmt.RXY.dl2,
|
||||
ovl.fmt.RXY.dh2); goto ok;
|
||||
case 0xe3000000002aULL: /* LZRG */ goto unimplemented;
|
||||
case 0xe3000000002aULL: s390_format_RXY_RRRD(s390_irgen_LZRG, ovl.fmt.RXY.r1,
|
||||
ovl.fmt.RXY.x2, ovl.fmt.RXY.b2,
|
||||
ovl.fmt.RXY.dl2,
|
||||
ovl.fmt.RXY.dh2); goto ok;
|
||||
case 0xe3000000002eULL: /* CVDG */ goto unimplemented;
|
||||
case 0xe3000000002fULL: s390_format_RXY_RRRD(s390_irgen_STRVG,
|
||||
ovl.fmt.RXY.r1, ovl.fmt.RXY.x2,
|
||||
@ -17338,8 +17655,14 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
|
||||
ovl.fmt.RXY.dh2); goto ok;
|
||||
case 0xe30000000038ULL: /* AGH */ goto unimplemented;
|
||||
case 0xe30000000039ULL: /* SGH */ goto unimplemented;
|
||||
case 0xe3000000003aULL: /* LLZRGF */ goto unimplemented;
|
||||
case 0xe3000000003bULL: /* LZRF */ goto unimplemented;
|
||||
case 0xe3000000003aULL: s390_format_RXY_RRRD(s390_irgen_LLZRGF, ovl.fmt.RXY.r1,
|
||||
ovl.fmt.RXY.x2, ovl.fmt.RXY.b2,
|
||||
ovl.fmt.RXY.dl2,
|
||||
ovl.fmt.RXY.dh2); goto ok;
|
||||
case 0xe3000000003bULL: s390_format_RXY_RRRD(s390_irgen_LZRF, ovl.fmt.RXY.r1,
|
||||
ovl.fmt.RXY.x2, ovl.fmt.RXY.b2,
|
||||
ovl.fmt.RXY.dl2,
|
||||
ovl.fmt.RXY.dh2); goto ok;
|
||||
case 0xe3000000003cULL: /* MGH */ goto unimplemented;
|
||||
case 0xe3000000003eULL: s390_format_RXY_RRRD(s390_irgen_STRV, ovl.fmt.RXY.r1,
|
||||
ovl.fmt.RXY.x2, ovl.fmt.RXY.b2,
|
||||
@ -17665,10 +17988,12 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
|
||||
case 0xe70000000021ULL: s390_format_VRS_RRDVM(s390_irgen_VLGV, ovl.fmt.VRS.v1,
|
||||
ovl.fmt.VRS.b2, ovl.fmt.VRS.d2, ovl.fmt.VRS.v3,
|
||||
ovl.fmt.VRS.m4, ovl.fmt.VRS.rxb); goto ok;
|
||||
case 0xe70000000027ULL: /* LCBB */ goto unimplemented;
|
||||
case 0xe70000000022ULL: s390_format_VRS_VRRDM(s390_irgen_VLVG, ovl.fmt.VRS.v1,
|
||||
ovl.fmt.VRS.b2, ovl.fmt.VRS.d2, ovl.fmt.VRS.v3,
|
||||
ovl.fmt.VRS.m4, ovl.fmt.VRS.rxb); goto ok;
|
||||
case 0xe70000000027ULL: s390_format_RXE_RRRDR(s390_irgen_LCBB, ovl.fmt.RXE.r1,
|
||||
ovl.fmt.RXE.x2, ovl.fmt.RXE.b2,
|
||||
ovl.fmt.RXE.d2, ovl.fmt.RXE.m3); goto ok;
|
||||
case 0xe70000000030ULL: /* VESL */ goto unimplemented;
|
||||
case 0xe70000000033ULL: /* VERLL */ goto unimplemented;
|
||||
case 0xe70000000036ULL: s390_format_VRS_VRDV(s390_irgen_VLM, ovl.fmt.VRS.v1,
|
||||
@ -17941,7 +18266,7 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
|
||||
ovl.fmt.RSY.dh2); goto ok;
|
||||
case 0xeb000000004cULL: s390_format_RSY_RRRD(s390_irgen_ECAG, ovl.fmt.RSY.r1,
|
||||
ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
|
||||
ovl.fmt.RSY.dl2,
|
||||
ovl.fmt.RSY.dl2,
|
||||
ovl.fmt.RSY.dh2); goto ok;
|
||||
case 0xeb0000000051ULL: s390_format_SIY_URD(s390_irgen_TMY, ovl.fmt.SIY.i2,
|
||||
ovl.fmt.SIY.b1, ovl.fmt.SIY.dl1,
|
||||
@ -18020,8 +18345,16 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
|
||||
ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
|
||||
ovl.fmt.RSY.dl2,
|
||||
ovl.fmt.RSY.dh2); goto ok;
|
||||
case 0xeb00000000e0ULL: /* LOCFH */ goto unimplemented;
|
||||
case 0xeb00000000e1ULL: /* STOCFH */ goto unimplemented;
|
||||
case 0xeb00000000e0ULL: s390_format_RSY_RDRM(s390_irgen_LOCFH, ovl.fmt.RSY.r1,
|
||||
ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
|
||||
ovl.fmt.RSY.dl2,
|
||||
ovl.fmt.RSY.dh2,
|
||||
S390_XMNM_LOCFH); goto ok;
|
||||
case 0xeb00000000e1ULL: s390_format_RSY_RDRM(s390_irgen_STOCFH, ovl.fmt.RSY.r1,
|
||||
ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
|
||||
ovl.fmt.RSY.dl2,
|
||||
ovl.fmt.RSY.dh2,
|
||||
S390_XMNM_STOCFH); goto ok;
|
||||
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,
|
||||
@ -18082,15 +18415,30 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
|
||||
ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
|
||||
ovl.fmt.RSY.dl2,
|
||||
ovl.fmt.RSY.dh2); goto ok;
|
||||
case 0xec0000000042ULL: /* LOCHI */ goto unimplemented;
|
||||
case 0xec0000000042ULL: s390_format_RIE_RUPIX(s390_irgen_LOCHI,
|
||||
ovl.fmt.RIEv3.r1,
|
||||
ovl.fmt.RIEv3.m3,
|
||||
ovl.fmt.RIEv3.i4,
|
||||
ovl.fmt.RIEv3.i2,
|
||||
S390_XMNM_LOCHI); goto ok;
|
||||
case 0xec0000000044ULL: s390_format_RIE_RRP(s390_irgen_BRXHG, ovl.fmt.RIE.r1,
|
||||
ovl.fmt.RIE.r3, ovl.fmt.RIE.i2);
|
||||
goto ok;
|
||||
case 0xec0000000045ULL: s390_format_RIE_RRP(s390_irgen_BRXLG, ovl.fmt.RIE.r1,
|
||||
ovl.fmt.RIE.r3, ovl.fmt.RIE.i2);
|
||||
goto ok;
|
||||
case 0xec0000000046ULL: /* LOCGHI */ goto unimplemented;
|
||||
case 0xec000000004eULL: /* LOCHHI */ goto unimplemented;
|
||||
case 0xec0000000046ULL: s390_format_RIE_RUPIX(s390_irgen_LOCGHI,
|
||||
ovl.fmt.RIEv3.r1,
|
||||
ovl.fmt.RIEv3.m3,
|
||||
ovl.fmt.RIEv3.i4,
|
||||
ovl.fmt.RIEv3.i2,
|
||||
S390_XMNM_LOCGHI); goto ok;
|
||||
case 0xec000000004eULL: s390_format_RIE_RUPIX(s390_irgen_LOCHHI,
|
||||
ovl.fmt.RIEv3.r1,
|
||||
ovl.fmt.RIEv3.m3,
|
||||
ovl.fmt.RIEv3.i4,
|
||||
ovl.fmt.RIEv3.i2,
|
||||
S390_XMNM_LOCHHI); goto ok;
|
||||
case 0xec0000000051ULL: s390_format_RIE_RRUUU(s390_irgen_RISBLG,
|
||||
ovl.fmt.RIE_RRUUU.r1,
|
||||
ovl.fmt.RIE_RRUUU.r2,
|
||||
|
||||
@ -9289,36 +9289,37 @@ s390_insn_helper_call_emit(UChar *buf, const s390_insn *insn)
|
||||
{
|
||||
s390_cc_t cond;
|
||||
ULong target;
|
||||
UChar *ptmp = buf;
|
||||
Int delta;
|
||||
s390_helper_call *helper_call = insn->variant.helper_call.details;
|
||||
|
||||
cond = helper_call->cond;
|
||||
target = helper_call->target;
|
||||
|
||||
if (cond != S390_CC_ALWAYS
|
||||
&& helper_call->rloc.pri != RLPri_None) {
|
||||
/* The call might not happen (it isn't unconditional) and it
|
||||
returns a result. In this case we will need to generate a
|
||||
control flow diamond to put 0x555..555 in the return
|
||||
register(s) in the case where the call doesn't happen. If
|
||||
this ever becomes necessary, maybe copy code from the ARM
|
||||
equivalent. Until that day, just give up. */
|
||||
return buf; /* To denote failure. */
|
||||
}
|
||||
const Bool not_always = (cond != S390_CC_ALWAYS);
|
||||
const Bool not_void_return = (helper_call->rloc.pri != RLPri_None);
|
||||
|
||||
if (cond != S390_CC_ALWAYS) {
|
||||
/* So we have something like this
|
||||
if (cond) call X;
|
||||
Y: ...
|
||||
We convert this into
|
||||
if (! cond) goto Y; // BRC opcode; 4 bytes
|
||||
call X;
|
||||
Y:
|
||||
*/
|
||||
/* We have this situation:
|
||||
( *** code in this braces is for not_always && not_void_return*** )
|
||||
...
|
||||
before:
|
||||
brc{!cond} else
|
||||
call_helper
|
||||
preElse:
|
||||
*** j after ***
|
||||
else:
|
||||
*** load_64imm $0x5555555555555555, %%r2 *** // e.g. for Int RetLoc
|
||||
after:
|
||||
...
|
||||
*/
|
||||
|
||||
// before:
|
||||
UChar *pBefore = buf;
|
||||
if (not_always) {
|
||||
/* 4 bytes (a BRC insn) to be filled in here */
|
||||
buf += 4;
|
||||
}
|
||||
|
||||
// call_helper
|
||||
/* Load the target address into a register, that
|
||||
(a) is not used for passing parameters to the helper and
|
||||
(b) can be clobbered by the callee
|
||||
@ -9336,12 +9337,45 @@ s390_insn_helper_call_emit(UChar *buf, const s390_insn *insn)
|
||||
buf = s390_emit_LFPC(buf, S390_REGNO_STACK_POINTER, // restore FPC
|
||||
S390_OFFSET_SAVED_FPC_C);
|
||||
|
||||
if (cond != S390_CC_ALWAYS) {
|
||||
Int delta = buf - ptmp;
|
||||
// preElse:
|
||||
UChar* pPreElse = buf;
|
||||
if (not_always && not_void_return) {
|
||||
/* 4 bytes (a BRC insn) to be filled in here */
|
||||
buf += 4;
|
||||
}
|
||||
|
||||
// else:
|
||||
UChar* pElse = buf;
|
||||
if (not_always && not_void_return) {
|
||||
switch (helper_call->rloc.pri) {
|
||||
case RLPri_Int:
|
||||
buf = s390_emit_load_64imm(buf, S390_REGNO_RETURN_VALUE, 0x5555555555555555ULL);
|
||||
break;
|
||||
default:
|
||||
ppS390Instr(insn, True);
|
||||
vpanic("s390_insn_helper_call_emit: invalid conditional RetLoc.");
|
||||
}
|
||||
}
|
||||
|
||||
// after:
|
||||
UChar* pAfter = buf;
|
||||
|
||||
// fill "brc{!cond} else"
|
||||
if(not_always)
|
||||
{
|
||||
delta = pElse - pBefore;
|
||||
delta >>= 1; /* immediate constant is #half-words */
|
||||
vassert(delta > 0 && delta < (1 << 16));
|
||||
s390_emit_BRC(ptmp, s390_cc_invert(cond), delta);
|
||||
s390_emit_BRC(pBefore, s390_cc_invert(cond), delta);
|
||||
}
|
||||
|
||||
// fill "brc{ALWAYS} after"
|
||||
if (not_always && not_void_return)
|
||||
{
|
||||
delta = pAfter - pPreElse;
|
||||
delta >>= 1; /* immediate constant is #half-words */
|
||||
vassert(delta > 0 && delta < (1 << 16));
|
||||
s390_emit_BRC(pPreElse, S390_CC_ALWAYS, delta);
|
||||
}
|
||||
|
||||
return buf;
|
||||
|
||||
@ -873,7 +873,8 @@ extern UInt s390_host_hwcaps;
|
||||
(s390_host_hwcaps & (VEX_HWCAPS_S390X_PFPO))
|
||||
#define s390_host_has_vx \
|
||||
(s390_host_hwcaps & (VEX_HWCAPS_S390X_VX))
|
||||
|
||||
#define s390_host_has_msa5 \
|
||||
(s390_host_hwcaps & (VEX_HWCAPS_S390X_MSA5))
|
||||
#endif /* ndef __VEX_HOST_S390_DEFS_H */
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
|
||||
@ -146,6 +146,28 @@ typedef enum {
|
||||
S390_PFPO_D128_TO_F128 = 0x01070A
|
||||
} s390_pfpo_function_t;
|
||||
|
||||
/* PPNO function code as it is encoded in bits [57:63] of GR0
|
||||
when PPNO insn is executed. */
|
||||
typedef enum
|
||||
{
|
||||
S390_PPNO_QUERY = 0x00,
|
||||
S390_PPNO_SHA512_GEN = 0x03,
|
||||
S390_PPNO_SHA512_SEED = 0x83
|
||||
} s390_ppno_function_t;
|
||||
|
||||
/* Size of parameter block for PPNO functions.
|
||||
All values are in bytes.
|
||||
*/
|
||||
#define S390_PPNO_PARAM_BLOCK_SIZE_QUERY 16
|
||||
#define S390_PPNO_PARAM_BLOCK_SIZE_SHA512 240
|
||||
|
||||
/* Maximum length of modified memory for PPNO functions.
|
||||
All values are in bytes.
|
||||
*/
|
||||
#define S390_PPNO_MAX_SIZE_SHA512_SEED 512
|
||||
#define S390_PPNO_MAX_SIZE_SHA512_GEN 64
|
||||
|
||||
|
||||
/* The length of the longest mnemonic: locgrnhe */
|
||||
#define S390_MAX_MNEMONIC_LEN 8
|
||||
|
||||
|
||||
@ -251,6 +251,12 @@ cls_operand(Int kind, UInt mask)
|
||||
case S390_XMNM_LOCG: prefix = "locg"; break;
|
||||
case S390_XMNM_STOC: prefix = "stoc"; break;
|
||||
case S390_XMNM_STOCG: prefix = "stocg"; break;
|
||||
case S390_XMNM_STOCFH: prefix = "stocfh"; break;
|
||||
case S390_XMNM_LOCFH: prefix = "locgh"; break;
|
||||
case S390_XMNM_LOCFHR: prefix = "locghr"; break;
|
||||
case S390_XMNM_LOCHI: prefix = "lochi"; break;
|
||||
case S390_XMNM_LOCGHI: prefix = "locghi"; break;
|
||||
case S390_XMNM_LOCHHI: prefix = "lochhi"; break;
|
||||
default:
|
||||
vpanic("cls_operand");
|
||||
}
|
||||
@ -416,6 +422,12 @@ s390_disasm(UInt command, ...)
|
||||
case S390_XMNM_LOCG:
|
||||
case S390_XMNM_STOC:
|
||||
case S390_XMNM_STOCG:
|
||||
case S390_XMNM_STOCFH:
|
||||
case S390_XMNM_LOCFH:
|
||||
case S390_XMNM_LOCFHR:
|
||||
case S390_XMNM_LOCHI:
|
||||
case S390_XMNM_LOCGHI:
|
||||
case S390_XMNM_LOCHHI:
|
||||
mask = va_arg(args, UInt);
|
||||
mnm = cls_operand(kind, mask);
|
||||
p += vex_sprintf(p, "%s", mnemonic(mnm));
|
||||
|
||||
@ -83,7 +83,13 @@ enum {
|
||||
S390_XMNM_LOC = 7,
|
||||
S390_XMNM_LOCG = 8,
|
||||
S390_XMNM_STOC = 9,
|
||||
S390_XMNM_STOCG = 10
|
||||
S390_XMNM_STOCG = 10,
|
||||
S390_XMNM_STOCFH = 11,
|
||||
S390_XMNM_LOCFH = 12,
|
||||
S390_XMNM_LOCFHR = 13,
|
||||
S390_XMNM_LOCHI = 14,
|
||||
S390_XMNM_LOCGHI = 15,
|
||||
S390_XMNM_LOCHHI = 16
|
||||
};
|
||||
|
||||
void s390_disasm(UInt command, ...);
|
||||
|
||||
@ -159,6 +159,8 @@ typedef
|
||||
#define VEX_HWCAPS_S390X_LSC (1<<16) /* Conditional load/store facility */
|
||||
#define VEX_HWCAPS_S390X_PFPO (1<<17) /* Perform floating point ops facility */
|
||||
#define VEX_HWCAPS_S390X_VX (1<<18) /* Vector facility */
|
||||
#define VEX_HWCAPS_S390X_MSA5 (1<<19) /* message security assistance facility */
|
||||
|
||||
|
||||
/* Special value representing all available s390x hwcaps */
|
||||
#define VEX_HWCAPS_S390X_ALL (VEX_HWCAPS_S390X_LDISP | \
|
||||
@ -173,7 +175,8 @@ typedef
|
||||
VEX_HWCAPS_S390X_ETF3 | \
|
||||
VEX_HWCAPS_S390X_ETF2 | \
|
||||
VEX_HWCAPS_S390X_PFPO | \
|
||||
VEX_HWCAPS_S390X_VX)
|
||||
VEX_HWCAPS_S390X_VX | \
|
||||
VEX_HWCAPS_S390X_MSA5)
|
||||
|
||||
#define VEX_HWCAPS_S390X(x) ((x) & ~VEX_S390X_MODEL_MASK)
|
||||
#define VEX_S390X_MODEL(x) ((x) & VEX_S390X_MODEL_MASK)
|
||||
|
||||
@ -123,6 +123,9 @@ typedef
|
||||
/* some insn needs vector facility which is not available on this host */
|
||||
EmFail_S390X_vx,
|
||||
|
||||
/* ppno insn is not supported on this host */
|
||||
EmFail_S390X_ppno,
|
||||
|
||||
EmNote_NUMBER
|
||||
}
|
||||
VexEmNote;
|
||||
|
||||
@ -99,6 +99,8 @@
|
||||
#define S390_FAC_DFPZC 48 // DFP zoned-conversion
|
||||
#define S390_FAC_MISC 49 // miscellaneous insn
|
||||
#define S390_FAC_CTREXE 50 // constrained transactional execution
|
||||
#define S390_FAC_LSC2 53 // load/store on condition 2 and load and zero rightmost byte
|
||||
#define S390_FAC_MSA5 57 // message-security-assist 5
|
||||
#define S390_FAC_TREXE 73 // transactional execution
|
||||
#define S390_FAC_MSA4 77 // message-security-assist 4
|
||||
#define S390_FAC_VX 128 // vector facility
|
||||
|
||||
@ -1495,7 +1495,8 @@ Bool VG_(machine_get_hwcaps)( void )
|
||||
{ False, S390_FAC_FPEXT, VEX_HWCAPS_S390X_FPEXT, "FPEXT" },
|
||||
{ False, S390_FAC_LSC, VEX_HWCAPS_S390X_LSC, "LSC" },
|
||||
{ False, S390_FAC_PFPO, VEX_HWCAPS_S390X_PFPO, "PFPO" },
|
||||
{ False, S390_FAC_VX, VEX_HWCAPS_S390X_VX, "VX" }
|
||||
{ False, S390_FAC_VX, VEX_HWCAPS_S390X_VX, "VX" },
|
||||
{ False, S390_FAC_MSA5, VEX_HWCAPS_S390X_MSA5, "MSA5" }
|
||||
};
|
||||
|
||||
/* Set hwcaps according to the detected facilities */
|
||||
|
||||
@ -18,7 +18,7 @@ INSN_TESTS = clc clcle cvb cvd icm lpr tcxb lam_stam xc mvst add sub mul \
|
||||
spechelper-cr spechelper-clr \
|
||||
spechelper-ltr spechelper-or \
|
||||
spechelper-icm-1 spechelper-icm-2 spechelper-tmll \
|
||||
spechelper-tm laa vector
|
||||
spechelper-tm laa vector lsc2 ppno
|
||||
if BUILD_DFP_TESTS
|
||||
INSN_TESTS += dfp-1 dfp-2 dfp-3 dfp-4 dfptest dfpext dfpconv srnmt pfpo
|
||||
endif
|
||||
@ -65,3 +65,4 @@ fixbr_CFLAGS = $(AM_CFLAGS) @FLAG_MLONG_DOUBLE_128@
|
||||
fpext_CFLAGS = $(AM_CFLAGS) @FLAG_MLONG_DOUBLE_128@
|
||||
ex_clone_LDADD = -lpthread
|
||||
vector_CFLAGS = $(AM_CFLAGS) -march=z13
|
||||
lsc2_CFLAGS = -march=z13 -DS390_TESTS_NOCOLOR
|
||||
|
||||
490
none/tests/s390x/lsc2.c
Normal file
490
none/tests/s390x/lsc2.c
Normal file
@ -0,0 +1,490 @@
|
||||
/*
|
||||
* s390x z13 instructions test
|
||||
*
|
||||
* Copyright (c) 2017 Vadim Barkov
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include "assert.h"
|
||||
#include "math.h"
|
||||
#include "stdbool.h"
|
||||
#include "stdint.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
|
||||
/* Colors for output */
|
||||
#ifndef S390_TESTS_NOCOLOR
|
||||
# define RED "\033[31m"
|
||||
# define GREEN "\033[32m"
|
||||
# define RESET "\033[0m"
|
||||
#else
|
||||
# define RED
|
||||
# define GREEN
|
||||
# define RESET
|
||||
#endif
|
||||
|
||||
#define printPassed(insn) \
|
||||
printf(RESET "%15s :\t " GREEN "PASSED" RESET "\n", #insn)
|
||||
#define printFailed(insn) \
|
||||
printf(RESET "%15s :\t " RED "FAILED" RESET "\n", #insn)
|
||||
|
||||
#define test(insn) \
|
||||
{ \
|
||||
if (test_##insn()) \
|
||||
printPassed(insn); \
|
||||
else \
|
||||
printFailed(insn); \
|
||||
}
|
||||
|
||||
#define SMART_RETURN_R64(insn) \
|
||||
bool result = after == expected; \
|
||||
if (!result) { \
|
||||
printf("[ERROR] %s:\n", #insn); \
|
||||
printf("after: %lx\n", (uint64_t) after); \
|
||||
printf("expected: %lx\n", (uint64_t) expected); \
|
||||
} \
|
||||
return result
|
||||
|
||||
/* Constant value for immediate instructions' tests */
|
||||
#define IMMEDIATE_VALUE 0x0abc
|
||||
#define IMMEDIATE_VALUE_STR "0x0abc"
|
||||
|
||||
/* Useful macros for testing many input values
|
||||
and printing message after test execution
|
||||
*/
|
||||
#define test_each(type, var, instruction) \
|
||||
{ \
|
||||
type##_foreach((var), test_##instruction((var))); \
|
||||
}
|
||||
|
||||
#define test_range(var, from, to, instruction) \
|
||||
{ \
|
||||
bool result = true; \
|
||||
__int_foreach(var, from, to, result &= (test_##instruction((var)))); \
|
||||
if (result) \
|
||||
printPassed(instruction); \
|
||||
else \
|
||||
printFailed(instruction); \
|
||||
}
|
||||
|
||||
#define __int_foreach(var, minValue, maxValue, statement) \
|
||||
{ \
|
||||
for (var = minValue; var < maxValue; var++) { \
|
||||
statement; \
|
||||
} \
|
||||
\
|
||||
{ statement; } \
|
||||
}
|
||||
|
||||
#define uint32_foreach(var, statement) \
|
||||
__int_foreach(var, 0, UINT32_MAX, statement)
|
||||
#define int32_foreach(var, statement) \
|
||||
__int_foreach(var, INT32_MIN, INT32_MAX, statement)
|
||||
#define uint64_foreach(var, statement) \
|
||||
__int_foreach(var, 0, UINT64_MAX, statement)
|
||||
|
||||
/* load and zero rightmost byte */
|
||||
static bool test_lzrf(const uint32_t testedValue)
|
||||
{
|
||||
uint32_t after = testedValue;
|
||||
uint32_t expected = testedValue & 0xffffff00;
|
||||
__asm__ volatile("lzrf %%r6, %0\n"
|
||||
"st %%r6, %0\n"
|
||||
:
|
||||
: "g"(after));
|
||||
|
||||
SMART_RETURN_R64(lzrf);
|
||||
}
|
||||
|
||||
/* load and zero rightmost byte 64bit*/
|
||||
static bool test_lzrg(const uint64_t testedValue)
|
||||
{
|
||||
uint64_t after = testedValue;
|
||||
uint64_t expected = testedValue & 0xffffffffffffff00UL;
|
||||
|
||||
__asm__ volatile("lzrg %%r6, %0\n"
|
||||
"stg %%r6, %0\n"
|
||||
:
|
||||
: "g"(after));
|
||||
|
||||
SMART_RETURN_R64(lzrg);
|
||||
}
|
||||
|
||||
/* load logical and zero rightmost byte */
|
||||
static bool test_llzrgf(const uint32_t testedValue)
|
||||
{
|
||||
uint64_t after = 0;
|
||||
uint64_t expected = ((uint64_t)testedValue << 32) & 0xffffff0000000000UL;
|
||||
|
||||
__asm__ volatile("llzrgf %%r6, %0\n"
|
||||
"st %%r6, %1\n"
|
||||
:
|
||||
: "g"(testedValue), "g"(after));
|
||||
|
||||
SMART_RETURN_R64(llzrgf);
|
||||
}
|
||||
|
||||
/* compare instructions */
|
||||
#define __compare_r "cr"
|
||||
#define __compare_m "c"
|
||||
|
||||
/* load high on condition */
|
||||
#define declare_load_high_on_condition(TESTED_INSTRUCTION, CONDITION_SYMBOL, \
|
||||
ARGUMENT_ASM_TYPE) \
|
||||
bool test_##TESTED_INSTRUCTION(const int32_t testedValue) \
|
||||
{ \
|
||||
uint64_t expected; \
|
||||
const uint64_t valueBeforeTest = 0x6666666699999999UL; \
|
||||
const uint64_t overrideValue = 0xeeeeeeeeeeeeeeeeUL; \
|
||||
const int32_t invertedValue = testedValue ^ 0xffffffff; \
|
||||
uint64_t after = valueBeforeTest; \
|
||||
if (testedValue CONDITION_SYMBOL invertedValue) { \
|
||||
expected = 0xeeeeeeee99999999UL; \
|
||||
} else { \
|
||||
expected = valueBeforeTest; \
|
||||
} \
|
||||
\
|
||||
__asm__ volatile( \
|
||||
"cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION \
|
||||
" %[after], %[overrideValue]\n" \
|
||||
: [after] "=r"(after) \
|
||||
: [testedValue] "r"(testedValue), \
|
||||
[invertedValue] "r"(invertedValue), \
|
||||
[overrideValue] #ARGUMENT_ASM_TYPE(overrideValue), \
|
||||
"[after]"(after)); \
|
||||
\
|
||||
SMART_RETURN_R64(TESTED_INSTRUCTION); \
|
||||
}
|
||||
|
||||
declare_load_high_on_condition(locfhre, ==, r)
|
||||
declare_load_high_on_condition(locfhrne, !=, r)
|
||||
declare_load_high_on_condition(locfhrh, >, r)
|
||||
declare_load_high_on_condition(locfhrl, <, r)
|
||||
declare_load_high_on_condition(locfhe, ==, m)
|
||||
declare_load_high_on_condition(locfhne, !=, m)
|
||||
declare_load_high_on_condition(locfhh, >, m)
|
||||
declare_load_high_on_condition(locfhl, <, m)
|
||||
|
||||
/* store high on condition */
|
||||
#define declare_store_high_on_condition(TESTED_INSTRUCTION, CONDITION_SYMBOL, \
|
||||
ARGUMENT_ASM_TYPE) \
|
||||
bool test_##TESTED_INSTRUCTION(const int32_t testedValue) \
|
||||
{ \
|
||||
uint64_t expected; \
|
||||
const uint64_t valueBeforeTest = 0x6666666699999999UL; \
|
||||
const uint64_t overrideValue = 0xeeeeeeeeeeeeeeeeUL; \
|
||||
const int32_t invertedValue = testedValue ^ 0xffffffff; \
|
||||
uint64_t after = valueBeforeTest; \
|
||||
if (testedValue CONDITION_SYMBOL invertedValue) { \
|
||||
expected = 0xeeeeeeee99999999UL; \
|
||||
} else { \
|
||||
expected = valueBeforeTest; \
|
||||
} \
|
||||
\
|
||||
__asm__ volatile( \
|
||||
"cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION \
|
||||
" %[overrideValue], %[after]\n" \
|
||||
: [after] "=" #ARGUMENT_ASM_TYPE(after) \
|
||||
: [testedValue] "r"(testedValue), \
|
||||
[invertedValue] "r"(invertedValue), \
|
||||
[overrideValue] "r"(overrideValue)); \
|
||||
\
|
||||
SMART_RETURN_R64(TESTED_INSTRUCTION); \
|
||||
}
|
||||
|
||||
declare_store_high_on_condition(stocfhe, ==, m)
|
||||
declare_store_high_on_condition(stocfhne, !=, m)
|
||||
declare_store_high_on_condition(stocfhh, >, m)
|
||||
declare_store_high_on_condition(stocfhl, <, m)
|
||||
|
||||
#define __format_uint32_t "%x"
|
||||
#define __format_uint64_t "%lx"
|
||||
#define __halfword_valueBefore_uint32_t 0x66669999
|
||||
#define __halfword_valueBefore_uint64_t 0x6666666699999999UL
|
||||
/* load halfword immediate on condition */
|
||||
#define declare_load_halfword_immediate_on_condition( \
|
||||
TESTED_INSTRUCTION, ARGUMENT_TYPE, CONDITION_SYMBOL, ARGUMENT_ASM_TYPE) \
|
||||
bool test_##TESTED_INSTRUCTION(const int32_t testedValue) \
|
||||
{ \
|
||||
ARGUMENT_TYPE expected; \
|
||||
const ARGUMENT_TYPE valueBeforeTest = \
|
||||
__halfword_valueBefore_##ARGUMENT_TYPE; \
|
||||
const int32_t invertedValue = testedValue ^ 0xffffffff; \
|
||||
ARGUMENT_TYPE after = valueBeforeTest; \
|
||||
if (testedValue CONDITION_SYMBOL invertedValue) { \
|
||||
expected = IMMEDIATE_VALUE; \
|
||||
} else { \
|
||||
expected = valueBeforeTest; \
|
||||
} \
|
||||
\
|
||||
__asm__ volatile( \
|
||||
"cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION \
|
||||
" %[after], " IMMEDIATE_VALUE_STR "\n" \
|
||||
: [after] "=r"(after) \
|
||||
: [testedValue] "r"(testedValue), \
|
||||
[invertedValue] "r"(invertedValue), \
|
||||
"[after]"(after)); \
|
||||
\
|
||||
SMART_RETURN_R64(TESTED_INSTRUCTION); \
|
||||
}
|
||||
|
||||
declare_load_halfword_immediate_on_condition(lochie, uint32_t, ==, r)
|
||||
declare_load_halfword_immediate_on_condition(lochine, uint32_t, !=, r)
|
||||
declare_load_halfword_immediate_on_condition(lochih, uint32_t, >, r)
|
||||
declare_load_halfword_immediate_on_condition(lochil, uint32_t, <, r)
|
||||
declare_load_halfword_immediate_on_condition(locghie, uint64_t, ==, r)
|
||||
declare_load_halfword_immediate_on_condition(locghine, uint64_t, !=, r)
|
||||
declare_load_halfword_immediate_on_condition(locghih, uint64_t, >, r)
|
||||
declare_load_halfword_immediate_on_condition(locghil, uint64_t, <, r)
|
||||
|
||||
/* load halfword high immediate on condition */
|
||||
#define declare_load_halfword_high_immediate_on_condition( \
|
||||
TESTED_INSTRUCTION, CONDITION_SYMBOL, ARGUMENT_ASM_TYPE) \
|
||||
bool test_##TESTED_INSTRUCTION(const int32_t testedValue) \
|
||||
{ \
|
||||
uint64_t expected; \
|
||||
const uint64_t valueBeforeTest = __halfword_valueBefore_uint64_t; \
|
||||
const int32_t invertedValue = testedValue ^ 0xffffffff; \
|
||||
uint64_t after = valueBeforeTest; \
|
||||
if (testedValue CONDITION_SYMBOL invertedValue) { \
|
||||
expected = IMMEDIATE_VALUE; \
|
||||
expected <<= 32; \
|
||||
expected += \
|
||||
__halfword_valueBefore_uint64_t & 0x00000000ffffffffUL; \
|
||||
} else { \
|
||||
expected = valueBeforeTest; \
|
||||
} \
|
||||
\
|
||||
__asm__ volatile( \
|
||||
"cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION \
|
||||
" %[after], " IMMEDIATE_VALUE_STR "\n" \
|
||||
: [after] "=r"(after) \
|
||||
: [testedValue] "r"(testedValue), \
|
||||
[invertedValue] "r"(invertedValue), \
|
||||
"[after]"(after)); \
|
||||
\
|
||||
SMART_RETURN_R64(TESTED_INSTRUCTION); \
|
||||
}
|
||||
|
||||
declare_load_halfword_high_immediate_on_condition(lochhie, ==, r)
|
||||
declare_load_halfword_high_immediate_on_condition(lochhine, !=, r)
|
||||
declare_load_halfword_high_immediate_on_condition(lochhih, >, r)
|
||||
declare_load_halfword_high_immediate_on_condition(lochhil, <, r)
|
||||
|
||||
static void test_all_locfh()
|
||||
{
|
||||
int32_t signed32bit = 0;
|
||||
|
||||
test_each(int32, signed32bit, locfhe);
|
||||
test_each(int32, signed32bit, locfhne);
|
||||
test_each(int32, signed32bit, locfhh);
|
||||
test_each(int32, signed32bit, locfhl);
|
||||
|
||||
test_each(int32, signed32bit, locfhre);
|
||||
test_each(int32, signed32bit, locfhrne);
|
||||
test_each(int32, signed32bit, locfhrh);
|
||||
test_each(int32, signed32bit, locfhrl);
|
||||
}
|
||||
|
||||
/* load count to block boundary */
|
||||
#define declare_load_count_to_block_boundary(M_FIELD) \
|
||||
bool test_lcbb##M_FIELD(const uint32_t testedValue) \
|
||||
{ \
|
||||
const size_t boundary = 64 * pow(2, M_FIELD); \
|
||||
const uint32_t *testedPointer = \
|
||||
(uint32_t *)(boundary - \
|
||||
((testedValue < boundary) ? testedValue : 0)); \
|
||||
uint32_t after = 0; \
|
||||
uint32_t expected = boundary - ((size_t)testedPointer % boundary); \
|
||||
if (expected > 16) \
|
||||
expected = 16; \
|
||||
\
|
||||
__asm__ volatile("lcbb %[after], %[testedPointer], " #M_FIELD \
|
||||
"\n" \
|
||||
: [after] "=r"(after) \
|
||||
: [testedPointer] "m"(*testedPointer)); \
|
||||
\
|
||||
SMART_RETURN_R64(lcbb##M_FIELD); \
|
||||
}
|
||||
|
||||
declare_load_count_to_block_boundary(0)
|
||||
declare_load_count_to_block_boundary(1)
|
||||
declare_load_count_to_block_boundary(2)
|
||||
declare_load_count_to_block_boundary(3)
|
||||
declare_load_count_to_block_boundary(4)
|
||||
declare_load_count_to_block_boundary(5)
|
||||
declare_load_count_to_block_boundary(6)
|
||||
|
||||
static bool test_lcbb0_cc(const uint32_t testedValue)
|
||||
{
|
||||
const size_t boundary = 64;
|
||||
const uint32_t *testedPointer =
|
||||
(uint32_t *)(boundary -
|
||||
((testedValue < boundary) ? testedValue : 0));
|
||||
uint32_t expectedForLCBB = boundary - ((size_t)testedPointer % boundary);
|
||||
|
||||
uint32_t after = 0;
|
||||
uint32_t expected = (expectedForLCBB >= 16) ? 0 : 3;
|
||||
__asm__ volatile("lcbb %[cc], %[testedPointer], 0 \n"
|
||||
"ipm %[cc] \n"
|
||||
"srl %[cc], 28 \n"
|
||||
: [cc] "=d"(after)
|
||||
: [testedPointer] "m"(*testedPointer)
|
||||
: "cc");
|
||||
SMART_RETURN_R64(lcbb0_cc);
|
||||
}
|
||||
|
||||
|
||||
static void test_all_lzr()
|
||||
{
|
||||
uint32_t unsigned32bit = 0;
|
||||
|
||||
test_each(uint32, unsigned32bit, lzrf);
|
||||
test_each(uint32, unsigned32bit, lzrg);
|
||||
}
|
||||
|
||||
static void test_all_stocfh()
|
||||
{
|
||||
int32_t signed32bit = 0;
|
||||
|
||||
test_each(int32, signed32bit, stocfhne);
|
||||
test_each(int32, signed32bit, stocfhe);
|
||||
test_each(int32, signed32bit, stocfhh);
|
||||
test_each(int32, signed32bit, stocfhl);
|
||||
}
|
||||
|
||||
static void test_all_lochi()
|
||||
{
|
||||
int32_t signed32bit = 0;
|
||||
|
||||
test_each(int32, signed32bit, locghine);
|
||||
test_each(int32, signed32bit, locghine);
|
||||
test_each(int32, signed32bit, locghih);
|
||||
test_each(int32, signed32bit, locghil);
|
||||
|
||||
test_each(int32, signed32bit, lochine);
|
||||
test_each(int32, signed32bit, lochie);
|
||||
test_each(int32, signed32bit, lochil);
|
||||
test_each(int32, signed32bit, lochih);
|
||||
}
|
||||
|
||||
static void test_all_lochhi()
|
||||
{
|
||||
int32_t signed32bit = 0;
|
||||
|
||||
test_each(int32, signed32bit, lochhine);
|
||||
test_each(int32, signed32bit, lochhie);
|
||||
test_each(int32, signed32bit, lochhih);
|
||||
test_each(int32, signed32bit, lochhil);
|
||||
}
|
||||
|
||||
static void test_all_lcbb()
|
||||
{
|
||||
size_t tested = 0;
|
||||
|
||||
test_range(tested, 0, 64, lcbb0);
|
||||
test_range(tested, 0, 128, lcbb1);
|
||||
test_range(tested, 0, 256, lcbb2);
|
||||
test_range(tested, 0, 512, lcbb3);
|
||||
test_range(tested, 0, 1024, lcbb4);
|
||||
test_range(tested, 0, 2048, lcbb5);
|
||||
test_range(tested, 0, 4096, lcbb6);
|
||||
test_range(tested, 0, 64, lcbb0_cc);
|
||||
}
|
||||
|
||||
void test_long_all() {
|
||||
uint64_t unsigned64bit = 0;
|
||||
|
||||
test_all_lcbb();
|
||||
test_all_lochhi();
|
||||
test_all_lochi();
|
||||
test_all_stocfh();
|
||||
test_all_locfh();
|
||||
test_all_lzr();
|
||||
test_each(uint64, unsigned64bit, llzrgf);
|
||||
}
|
||||
|
||||
#define SHORT_TESTS_UNSIGNED_FROM 0
|
||||
#define SHORT_TESTS_SIGNED_FROM -0xffff
|
||||
#define SHORT_TESTS_TO 0xffff
|
||||
|
||||
void test_short_all()
|
||||
{
|
||||
uint32_t unsigned32bit = 0;
|
||||
int32_t signed32bit = 0;
|
||||
uint64_t unsigned64bit = 0;
|
||||
|
||||
test_range(unsigned32bit, SHORT_TESTS_UNSIGNED_FROM, SHORT_TESTS_TO, lzrf);
|
||||
test_range(unsigned64bit, SHORT_TESTS_UNSIGNED_FROM, SHORT_TESTS_TO, lzrg);
|
||||
test_range(unsigned64bit, SHORT_TESTS_UNSIGNED_FROM, SHORT_TESTS_TO, llzrgf);
|
||||
|
||||
/* stocfh */
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, stocfhne);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, stocfhe);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, stocfhh);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, stocfhl);
|
||||
|
||||
/* locfh */
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhe);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhne);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhh);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhl);
|
||||
|
||||
/* locfhr */
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhre);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhrne);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhrh);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhrl);
|
||||
|
||||
/* lochhi */
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochhine);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochhie);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochhih);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochhil);
|
||||
|
||||
/* lochi */
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochine);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochie);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochih);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochil);
|
||||
|
||||
/* locghi */
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locghine);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locghie);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locghih);
|
||||
test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locghil);
|
||||
|
||||
test_all_lcbb(); /* These test is not long, so we can run it on all range */
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
bool shouldRunLongTests = false;
|
||||
|
||||
/* --long option forces to test all possible values (it is very long)*/
|
||||
if (argc > 1)
|
||||
if (strcmp(argv[1], "--long") == 0)
|
||||
shouldRunLongTests = true;
|
||||
|
||||
printf("Tests started:\n");
|
||||
if (shouldRunLongTests)
|
||||
test_long_all();
|
||||
else
|
||||
test_short_all();
|
||||
|
||||
printf("Tests ended.\n");
|
||||
return 0;
|
||||
}
|
||||
2
none/tests/s390x/lsc2.stderr.exp
Normal file
2
none/tests/s390x/lsc2.stderr.exp
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
|
||||
37
none/tests/s390x/lsc2.stdout.exp
Normal file
37
none/tests/s390x/lsc2.stdout.exp
Normal file
@ -0,0 +1,37 @@
|
||||
Tests started:
|
||||
lzrf : PASSED
|
||||
lzrg : PASSED
|
||||
llzrgf : PASSED
|
||||
stocfhne : PASSED
|
||||
stocfhe : PASSED
|
||||
stocfhh : PASSED
|
||||
stocfhl : PASSED
|
||||
locfhe : PASSED
|
||||
locfhne : PASSED
|
||||
locfhh : PASSED
|
||||
locfhl : PASSED
|
||||
locfhre : PASSED
|
||||
locfhrne : PASSED
|
||||
locfhrh : PASSED
|
||||
locfhrl : PASSED
|
||||
lochhine : PASSED
|
||||
lochhie : PASSED
|
||||
lochhih : PASSED
|
||||
lochhil : PASSED
|
||||
lochine : PASSED
|
||||
lochie : PASSED
|
||||
lochih : PASSED
|
||||
lochil : PASSED
|
||||
locghine : PASSED
|
||||
locghie : PASSED
|
||||
locghih : PASSED
|
||||
locghil : PASSED
|
||||
lcbb0 : PASSED
|
||||
lcbb1 : PASSED
|
||||
lcbb2 : PASSED
|
||||
lcbb3 : PASSED
|
||||
lcbb4 : PASSED
|
||||
lcbb5 : PASSED
|
||||
lcbb6 : PASSED
|
||||
lcbb0_cc : PASSED
|
||||
Tests ended.
|
||||
1
none/tests/s390x/lsc2.vgtest
Normal file
1
none/tests/s390x/lsc2.vgtest
Normal file
@ -0,0 +1 @@
|
||||
prog: lsc2
|
||||
127
none/tests/s390x/ppno.c
Normal file
127
none/tests/s390x/ppno.c
Normal file
@ -0,0 +1,127 @@
|
||||
#include "stdio.h"
|
||||
#include "stdbool.h"
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
#include "vector.h"
|
||||
|
||||
#define S390_PPNO_SHA512_BLOCK_SIZE (240 / 8)
|
||||
static uint64_t block[S390_PPNO_SHA512_BLOCK_SIZE];
|
||||
#define HASH_COUNT 2 /* exactly two hashes for generate */
|
||||
static uint64_t hash[HASH_COUNT];
|
||||
|
||||
static void print_sha512_block()
|
||||
{
|
||||
printf("Current block state:\n");
|
||||
for(size_t elem = 0; elem < S390_PPNO_SHA512_BLOCK_SIZE; elem++)
|
||||
{
|
||||
print_uint64_t(block[elem]);
|
||||
}
|
||||
|
||||
printf("end of block.\n");
|
||||
}
|
||||
|
||||
static void print_sha512_hash()
|
||||
{
|
||||
printf("Current hash:\n");
|
||||
for(size_t index = 0; index < HASH_COUNT; index++)
|
||||
print_uint64_t(hash[index]);
|
||||
|
||||
printf("end of hash\n");
|
||||
}
|
||||
|
||||
/* The problem with this test is different results on different architectures.
|
||||
E.g. z13 will return (1 << 0)|(1 << 3) value while more recent versions of CPU
|
||||
can (and will!) add their own operations here. Anyway z13 or any later arch will
|
||||
have "SHA-512-DRNG" (3-rd bit of result) and "Query" (0-th bit) functions
|
||||
so we test only this bits and ignore others.
|
||||
*/
|
||||
static bool test_ppno_query()
|
||||
{
|
||||
uint32_t output[4];
|
||||
register uint64_t functionCode __asm__("0") = 0ULL;
|
||||
register uint64_t paramBlock __asm__("1") = (uint64_t) &output;
|
||||
|
||||
__asm__ volatile (
|
||||
".insn rre, 0xb93c0000, %%r2, %%r4 \n" // GPR's are ignored here
|
||||
: "+d"(functionCode), "+d"(paramBlock)
|
||||
:
|
||||
: "cc", "memory"
|
||||
);
|
||||
|
||||
/* 0x9 = (1 << 0)|(1 << 3), see explanation above */
|
||||
uint32_t expected = 0x90000000U;
|
||||
uint32_t after = output[0];
|
||||
|
||||
bool result = expected == after;
|
||||
if(!result)
|
||||
printf("ERROR: basic ppno functions are not supported : %d\n", after);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void test_ppno_sha512_seed()
|
||||
{
|
||||
/* Important! The program should zero paramBlock for seeding. */
|
||||
memset(block, 0, sizeof(block));
|
||||
|
||||
uint8_t seed[512];
|
||||
for(size_t index = 0; index < 512; index++)
|
||||
seed[index] = random_element();
|
||||
seed[511] = 0;
|
||||
const uint64_t seedLength = strlen((char*)seed);
|
||||
|
||||
register uint64_t functionCode __asm__("0") = 0x83ULL;
|
||||
register uint64_t paramBlock __asm__("1") = (uint64_t) █
|
||||
register uint64_t gpr2 __asm__("2") = (uint64_t) &seed;
|
||||
register uint64_t gpr3 __asm__("3") = seedLength;
|
||||
__asm__ volatile (
|
||||
".insn rre, 0xb93c0000, %%r4, %%r2 \n"
|
||||
:
|
||||
: "d"(functionCode), "d"(paramBlock), "d"(gpr2), "d"(gpr3)
|
||||
: "cc", "memory"
|
||||
);
|
||||
|
||||
printf("seedLength = %ld\n", seedLength);
|
||||
print_sha512_block();
|
||||
}
|
||||
|
||||
static void test_ppno_sha512_gen()
|
||||
{
|
||||
register uint64_t functionCode __asm__("0") = 0x3ULL;
|
||||
register uint64_t paramBlock __asm__("1") = (uint64_t) █
|
||||
register uint64_t gpr2 __asm__("2") = (uint64_t) &hash;
|
||||
register uint64_t gpr3 __asm__("3") = HASH_COUNT;
|
||||
|
||||
__asm__ volatile (
|
||||
"0: .insn rre, 0xb93c0000, %%r2, %%r4 \n"
|
||||
" brc 1, 0 \n" /* handle partial completion */
|
||||
:
|
||||
: "d"(functionCode), "d"(paramBlock), "d"(gpr2), "d"(gpr3)
|
||||
: "cc", "memory"
|
||||
);
|
||||
|
||||
print_sha512_hash();
|
||||
print_sha512_block();
|
||||
}
|
||||
|
||||
static void test_ppno_sha512()
|
||||
{
|
||||
printf(" === sha512_seed: ===\n");
|
||||
test_ppno_sha512_seed();
|
||||
return;
|
||||
printf(" === sha512_gen: ===\n");
|
||||
test_ppno_sha512_gen();
|
||||
|
||||
memset(hash, 0, sizeof(hash));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
size_t iteration;
|
||||
if(!test_ppno_query())
|
||||
return 1;
|
||||
|
||||
test(ppno_sha512);
|
||||
|
||||
return 0;
|
||||
}
|
||||
2
none/tests/s390x/ppno.stderr.exp
Normal file
2
none/tests/s390x/ppno.stderr.exp
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
|
||||
340
none/tests/s390x/ppno.stdout.exp
Normal file
340
none/tests/s390x/ppno.stdout.exp
Normal file
@ -0,0 +1,340 @@
|
||||
=== sha512_seed: ===
|
||||
seedLength = 0
|
||||
Current block state:
|
||||
0000000000000001
|
||||
0000000000000000
|
||||
003e226456bf592f
|
||||
441da979b2879409
|
||||
fc6f0e6192b8e7a7
|
||||
4ab3c33ebe6211bc
|
||||
4d4e1319fa123ab6
|
||||
5d34f1db2a58545c
|
||||
56fdbba651cffc31
|
||||
93bad6df02b799e3
|
||||
aaaa0c62548a2b53
|
||||
2621bf68328e3354
|
||||
678049ba8d9f1dc4
|
||||
ab9b96e348df64d6
|
||||
73f6e4aa1e2a772f
|
||||
8cd1a86bec20d436
|
||||
00f78e432b75bb7a
|
||||
60296ca43d1c6a9b
|
||||
ab6531522f5c1327
|
||||
2ceeb7b13076587a
|
||||
7becdef486f4f207
|
||||
ce5059ceb74ced11
|
||||
7309c2683f68a9d5
|
||||
e7458e632be82b57
|
||||
83754f8941faf016
|
||||
10f6eec6c45b195d
|
||||
018034f6220e3728
|
||||
9ac61bb9dc8e100c
|
||||
3f5e85d5a6537e0d
|
||||
8381c3f2ca21f4a5
|
||||
end of block.
|
||||
=== sha512_seed: ===
|
||||
seedLength = 11
|
||||
Current block state:
|
||||
0000000000000001
|
||||
0000000000000000
|
||||
004eb1b72a8a5538
|
||||
99417cd142461d13
|
||||
a4e7fdd4fe5bec3c
|
||||
2d84993f3c7dfecd
|
||||
81c7a13cd7a2e1dd
|
||||
1a72bbca637c9f35
|
||||
a9e73691ed4dab56
|
||||
2749ba30f6d1f93b
|
||||
4152bce5396879b3
|
||||
eddda1b12d8d083d
|
||||
a385ab81199f7f36
|
||||
1cf637397957dfd4
|
||||
bde5cab81dd1e412
|
||||
72931ea30835862a
|
||||
004469806a5b73d8
|
||||
aeaf1f9d0cae7c37
|
||||
8adf82179d0fca03
|
||||
e47741e426d6e305
|
||||
b84ebd07593a8225
|
||||
7f1c6928f7653501
|
||||
d1524486643b460f
|
||||
dc6c2402af8aa1af
|
||||
86043ac0ac159bb3
|
||||
41aaba7230c42a1f
|
||||
8be022ac67e2d5b1
|
||||
aa3c7ad10bb2f452
|
||||
7e91c25bb6bed695
|
||||
488c9efa3bedadcf
|
||||
end of block.
|
||||
=== sha512_seed: ===
|
||||
seedLength = 104
|
||||
Current block state:
|
||||
0000000000000001
|
||||
0000000000000000
|
||||
0065b7da3facb603
|
||||
a39ba35264e352c1
|
||||
528ff5b185090e96
|
||||
1e23953329b37e51
|
||||
ed239bc2b128f806
|
||||
f17aea98269226f8
|
||||
060c890a3052852c
|
||||
5df580976052e63a
|
||||
878588f4a8ee6646
|
||||
976b9a9768b6e005
|
||||
77bbd6d0c9343a00
|
||||
0faaa6e742c9dac8
|
||||
46a8a5506c2e9401
|
||||
9043d2bf21003936
|
||||
00a0ae8f2a4cb315
|
||||
782760f19dc3092d
|
||||
60060ae811f7ebda
|
||||
0b1b47143d57a5c2
|
||||
b15629bb9162d3cf
|
||||
c771535a7d6414b3
|
||||
e7e1adfb50e9534a
|
||||
bbb340f32c63cf50
|
||||
edf209d0db329cbc
|
||||
c4f31b47743eecc4
|
||||
04c3f5884af60998
|
||||
cfea12866218e29e
|
||||
5f2363a04592c804
|
||||
46d387494a63fec0
|
||||
end of block.
|
||||
=== sha512_seed: ===
|
||||
seedLength = 158
|
||||
Current block state:
|
||||
0000000000000001
|
||||
0000000000000000
|
||||
0045781698282993
|
||||
4da84904d0e89d9a
|
||||
edeaf6024283326f
|
||||
527c60b5a7aa2bab
|
||||
38e8d26031674b06
|
||||
ba0b249df891a67c
|
||||
5b364ea73ffea6c0
|
||||
e398d258a5ba5917
|
||||
c8b87f8f5e33b622
|
||||
a49b4ef408e3649e
|
||||
3da66fec9b5a6db0
|
||||
55d27c3cd383b31c
|
||||
5d5150f16c6d7451
|
||||
57b9fabe0e028fba
|
||||
003613e0f72a16fe
|
||||
dbddb109b3c327ba
|
||||
197eb5098dc8b240
|
||||
04add947f078aead
|
||||
6ce9e45c94c1ff24
|
||||
ea57dc533fec8520
|
||||
41bac59db19c7ac4
|
||||
6ebfb7055be23099
|
||||
e968ca0ae2f45635
|
||||
3a8096f2b2d33744
|
||||
c0c43d08f6797136
|
||||
c248bf582e5f5c5f
|
||||
e79d264972e8dc36
|
||||
f3045008abe8a6ca
|
||||
end of block.
|
||||
=== sha512_seed: ===
|
||||
seedLength = 37
|
||||
Current block state:
|
||||
0000000000000001
|
||||
0000000000000000
|
||||
00349033d29ca4c9
|
||||
dc2d01908a5791be
|
||||
c5cf75e0e3ca17cf
|
||||
7aed3a3df4990bcd
|
||||
87fc573cd5b13ba2
|
||||
6fdab83b8464cf82
|
||||
1a21797e3a9e7035
|
||||
3a06c2b83281705f
|
||||
f1d35bf5f068bc49
|
||||
a4ad202f6ce656e3
|
||||
4c56eb01058ce66d
|
||||
0e998ab91d77350a
|
||||
767fc3bc6bfa0b20
|
||||
07b6e69af6a59bea
|
||||
00ba228488e7ac41
|
||||
8c2d862fb775f15a
|
||||
d669a21dfa69f5b9
|
||||
4d134ec98379df9d
|
||||
81a2da79e623eca8
|
||||
b65a481b7aef0e89
|
||||
562a0f4743360402
|
||||
bde519a05363cbaf
|
||||
82608e5fe7ff8337
|
||||
c6030af815307cec
|
||||
fcef279b9735498b
|
||||
a90c7aebac65655a
|
||||
5871203aa8ec538e
|
||||
31f5e08b75f40311
|
||||
end of block.
|
||||
=== sha512_seed: ===
|
||||
seedLength = 301
|
||||
Current block state:
|
||||
0000000000000001
|
||||
0000000000000000
|
||||
00a2cd9e1108b253
|
||||
60f0f515f9436267
|
||||
6112b2da9b34e224
|
||||
b882cf25f62058f0
|
||||
e939aaef747e10f6
|
||||
796a3c2c0de9f9b5
|
||||
666e3c719678469c
|
||||
794413d6cc3ab283
|
||||
4d201dbffcbe9d75
|
||||
2e7826d27d1fd410
|
||||
e591db24ed522dae
|
||||
cda5699ea7ff7a10
|
||||
5ca19132941d57ed
|
||||
64cb80f5965dac83
|
||||
00b17bbb282a09b1
|
||||
3df5323781179ef5
|
||||
fcb78fac7c3e2aab
|
||||
88ba2880422809b2
|
||||
8d32558e30af18da
|
||||
c0030273bffaf70a
|
||||
0347475d9d030ce3
|
||||
6ce0c491d4a4f74d
|
||||
99daef279fdc1b49
|
||||
a0a862ab740eb859
|
||||
7dd377eaea992d4b
|
||||
ef9d973cb7138817
|
||||
303998590f022392
|
||||
e9a9a39e7ede4eaa
|
||||
end of block.
|
||||
=== sha512_seed: ===
|
||||
seedLength = 185
|
||||
Current block state:
|
||||
0000000000000001
|
||||
0000000000000000
|
||||
000108c265da6c80
|
||||
0192507c98a4c2c7
|
||||
452608dd4fe634a1
|
||||
c880a82e782378c7
|
||||
c66821bda7472a82
|
||||
ab84aa370d9c5dde
|
||||
316ce0a0348bc019
|
||||
b050cccaf67f178e
|
||||
d318738dab56b454
|
||||
ae5a95f3f935eb6b
|
||||
e77275efef5b7201
|
||||
e24690d9039b02b6
|
||||
21b3a48bf7ff98e4
|
||||
9fef58ec1f88fff7
|
||||
003caab18195c6df
|
||||
641cd44486e21c8e
|
||||
02c18c895dd6cda2
|
||||
e23b8cc41c9d0994
|
||||
bd7236c9322f655a
|
||||
298ee4aa4b23b737
|
||||
2c5feadf5cfcfe57
|
||||
6bf3bbd877e448eb
|
||||
bd1fcf1624ac28be
|
||||
041d143f9a9facda
|
||||
c9ae1027c3548419
|
||||
130e59d52f1d824e
|
||||
23af4bf89e504583
|
||||
fc017e2eb2a4d28a
|
||||
end of block.
|
||||
=== sha512_seed: ===
|
||||
seedLength = 125
|
||||
Current block state:
|
||||
0000000000000001
|
||||
0000000000000000
|
||||
00c4c2ecae21e662
|
||||
85b3e6f0042d2baf
|
||||
9e484b413ba43943
|
||||
9cd159886515ffad
|
||||
8cd8a3a5028ed440
|
||||
98f350a7b31a397c
|
||||
0eb36001904a1384
|
||||
07c57472df6c61f1
|
||||
a6f3ca8e6675078b
|
||||
d9d2325a92030fca
|
||||
2a1d516dcae5a8cb
|
||||
972cfde019bfcdc0
|
||||
74d1e498cb4f4882
|
||||
3308b466d31c3023
|
||||
00dd0698e4f695a1
|
||||
06257726d3b1f4bc
|
||||
3b9794261c1401d4
|
||||
fd1e82ac81472d04
|
||||
0afba5dedbf8003a
|
||||
4146305cf5b96e03
|
||||
9bb6672bd2ee8acc
|
||||
e00d1c05ee4d7639
|
||||
8313735518354ab0
|
||||
e3f1487cb8f79c96
|
||||
bc99d40d7a49afe8
|
||||
e8e1139b3864f068
|
||||
89ffd2a4948b1967
|
||||
e5cf0258f3082fd6
|
||||
end of block.
|
||||
=== sha512_seed: ===
|
||||
seedLength = 30
|
||||
Current block state:
|
||||
0000000000000001
|
||||
0000000000000000
|
||||
00b05877ea149ca9
|
||||
ddb7203e41de79bd
|
||||
f637815de27b89e1
|
||||
bda7afbb46634eec
|
||||
3f2f329c2509c348
|
||||
63a8e954764f99bc
|
||||
f0fb5d2ec9f2f996
|
||||
7c8cae8651e7b4e0
|
||||
4b3e2d33a90095eb
|
||||
42b1c6305af4487c
|
||||
3e116fc0b9700f1a
|
||||
94ac60577d4d1a47
|
||||
1c338f226410f72d
|
||||
d8231fa60e8f4e53
|
||||
0051e3f1e9e02151
|
||||
a1d8fc93f9d45b0c
|
||||
69e8fef198cb391e
|
||||
5952ee22ec3553e7
|
||||
fa6ddd6f23387117
|
||||
fa71fa2d88b1083d
|
||||
2bbc00ae1103daa2
|
||||
6eae1e34be4c53d0
|
||||
82cb422f047d0758
|
||||
f776d289c581ea5f
|
||||
b1f0959bef26d7fd
|
||||
da4c80f7309a266b
|
||||
755f72d68f47c6af
|
||||
6d1269427254b971
|
||||
end of block.
|
||||
=== sha512_seed: ===
|
||||
seedLength = 511
|
||||
Current block state:
|
||||
0000000000000001
|
||||
0000000000000000
|
||||
002c4bf217887798
|
||||
49700ed88f7abec4
|
||||
31f331722e562f90
|
||||
d3ada9dc23790d8d
|
||||
87dac381c4634a22
|
||||
5d32c8e62ee3fd4e
|
||||
19560e54b7464c02
|
||||
da8173723e36b679
|
||||
08dc7f22f28c9b8e
|
||||
8cfc13e645a13d68
|
||||
af4f40f6460007b6
|
||||
e98b97ba232b7049
|
||||
a8de0efcb7e74212
|
||||
187a977bfbe5ad54
|
||||
001f54f5715b6e7f
|
||||
dc7cec10e2fb028f
|
||||
7ff779259762f33f
|
||||
1342e9a91ff7015e
|
||||
5b12cfa2ab1afd2b
|
||||
af95a97ef7cf30ff
|
||||
cd5149f31f92a4e4
|
||||
c97e4b3af244ce23
|
||||
cc74abb567ed5f5b
|
||||
4de0d128dce98570
|
||||
f097484c991998fe
|
||||
3e17f4e5caa21f08
|
||||
1e33b2536984cae5
|
||||
48ace06455de2fc8
|
||||
end of block.
|
||||
2
none/tests/s390x/ppno.vgtest
Normal file
2
none/tests/s390x/ppno.vgtest
Normal file
@ -0,0 +1,2 @@
|
||||
prog: ppno
|
||||
prereq: test -e ppno && ../../../tests/s390x_features s390x-msa5
|
||||
@ -245,6 +245,8 @@ static int go(char *feature, char *cpu)
|
||||
match = facilities[0] & FAC_BIT(45);
|
||||
} else if (strcmp(feature, "s390x-vx") == 0 ) {
|
||||
match = facilities[2] & FAC_BIT(0);
|
||||
} else if (strcmp(feature, "s390x-msa5") == 0 ) {
|
||||
match = facilities[0] & FAC_BIT(57); /* message security assist 5 facility */
|
||||
} else {
|
||||
return 2; // Unrecognised feature.
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user