From 20976f432dc5e4e2218d0fcd18ed4771d67a6d37 Mon Sep 17 00:00:00 2001 From: Andreas Arnez Date: Wed, 25 Jul 2018 14:23:02 +0200 Subject: [PATCH] s390x: Implement conditional trap instructions This implements various z/Architecture instructions that conditionally yield a data exception ("trap"). The condition is either based on a comparison being true ("compare and trap") or on a loaded value being zero ("load and trap"). These instructions haven't been widely used in the past, but may now be emitted by newer compilers. Note that the resulting signal for a data exception is SIGFPE, not SIGTRAP. Thus this patch also adds a new jump kind Ijk_SigFPE. --- .gitignore | 1 + VEX/priv/guest_s390_toIR.c | 307 ++++++++++++++++++++++++++++-- VEX/priv/host_s390_defs.c | 2 + VEX/priv/host_s390_isel.c | 6 +- VEX/pub/libvex_ir.h | 1 + VEX/pub/libvex_trc_values.h | 1 + coregrind/m_scheduler/scheduler.c | 4 + coregrind/m_signals.c | 4 +- docs/internals/s390-opcodes.csv | 30 +-- none/tests/s390x/Makefile.am | 2 +- none/tests/s390x/traps.c | 139 ++++++++++++++ none/tests/s390x/traps.stderr.exp | 2 + none/tests/s390x/traps.stdout.exp | 46 +++++ none/tests/s390x/traps.vgtest | 1 + 14 files changed, 511 insertions(+), 35 deletions(-) create mode 100644 none/tests/s390x/traps.c create mode 100644 none/tests/s390x/traps.stderr.exp create mode 100644 none/tests/s390x/traps.stdout.exp create mode 100644 none/tests/s390x/traps.vgtest diff --git a/.gitignore b/.gitignore index fc22c94425..7b93983116 100644 --- a/.gitignore +++ b/.gitignore @@ -1878,6 +1878,7 @@ /none/tests/s390x/vector /none/tests/s390x/lsc2 /none/tests/s390x/ppno +/none/tests/s390x/traps # /none/tests/scripts/ /none/tests/scripts/*.dSYM diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index 1697e9744b..8f3fb6d3d4 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -1068,6 +1068,23 @@ gpr_w0_offset(UInt archreg) return gpr_offset(archreg) + 0; } +/* Write an integer right-aligned into a gpr. */ +static __inline__ void +put_gpr_int(UInt archreg, IRExpr *expr) +{ + UInt siz = sizeofIRType(typeOfIRExpr(irsb->tyenv, expr)); + + vassert(siz <= 8); + stmt(IRStmt_Put(gpr_offset(archreg) + 8 - siz, expr)); +} + +/* Read an integer of given type from a gpr. */ +static __inline__ IRExpr * +get_gpr_int(UInt archreg, IRType ty) +{ + return IRExpr_Get(gpr_offset(archreg) + 8 - sizeofIRType(ty), ty); +} + /* Write word #0 of a gpr to the guest state. */ static __inline__ void put_gpr_w0(UInt archreg, IRExpr *expr) @@ -2207,6 +2224,16 @@ s390_format_RIE_RRUUU(const HChar *(*irgen)(UChar r1, UChar r2, UChar i3, i5); } +static void +s390_format_RIEv1(const HChar *(*irgen)(UChar r1, UShort i2, UChar m3), + UChar r1, UShort i2, UChar m3) +{ + const HChar *mnm = irgen(r1, i2, m3); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_FE)) + s390_disasm(ENC4(MNM, GPR, UINT, UINT), mnm, r1, i2, m3); +} + static void s390_format_RIE_RRPU(const HChar *(*irgen)(UChar r1, UChar r2, UShort i4, UChar m3), @@ -5537,6 +5564,214 @@ s390_irgen_CLGRB(UChar r1, UChar r2, UChar m3, IRTemp op4addr) return "clgrb"; } +/* Raise the appropriate signal for a compare-and-trap-instruction data + exception if the condition is true. */ +static void +s390_trap_on_condition(IRExpr *cond) +{ + stmt(IRStmt_Exit(cond, Ijk_SigFPE, IRConst_U64(guest_IA_next_instr), + S390X_GUEST_OFFSET(guest_IA))); +} + +/* Handle the various flavors of compare (logical) and trap. */ +static void +s390_irgen_CxRT(UChar m3, UChar r1, UChar r2, IRType type, UInt opc) +{ + IRExpr *cond; + + if (m3 == 0) { + /* Trap never (NOP) */ + return; + } else if (m3 == 14) { + /* Trap always */ + cond = IRExpr_Const(IRConst_U1 (True)); + } else { + IRTemp op1 = newTemp(type); + IRTemp op2 = newTemp(type); + + assign(op1, get_gpr_int(r1, type)); + assign(op2, get_gpr_int(r2, type)); + cond = binop(Iop_CmpNE32, + s390_call_calculate_icc(m3, opc, op1, op2), mkU32(0)); + } + s390_trap_on_condition(cond); +} + +static const HChar * +s390_irgen_CGRT(UChar m3, UChar r1, UChar r2) +{ + s390_irgen_CxRT(m3, r1, r2, Ity_I64, S390_CC_OP_SIGNED_COMPARE); + return "cgrt"; +} + +static const HChar * +s390_irgen_CRT(UChar m3, UChar r1, UChar r2) +{ + s390_irgen_CxRT(m3, r1, r2, Ity_I32, S390_CC_OP_SIGNED_COMPARE); + return "crt"; +} + +static const HChar * +s390_irgen_CLGRT(UChar m3, UChar r1, UChar r2) +{ + s390_irgen_CxRT(m3, r1, r2, Ity_I64, S390_CC_OP_UNSIGNED_COMPARE); + return "clgrt"; +} + +static const HChar * +s390_irgen_CLRT(UChar m3, UChar r1, UChar r2) +{ + s390_irgen_CxRT(m3, r1, r2, Ity_I32, S390_CC_OP_UNSIGNED_COMPARE); + return "clrt"; +} + +/* Handle the various flavors of compare (logical) immediate and trap. */ +static void +s390_irgen_CxIT(UChar m3, UChar r1, UShort i2, IRType type, UInt opc) +{ + IRExpr *cond; + + if (m3 == 0) { + /* Trap never (NOP) */ + return; + } else if (m3 == 14) { + /* Trap always */ + cond = IRExpr_Const(IRConst_U1 (True)); + } else { + IRTemp op1 = newTemp(type); + IRTemp op2 = newTemp(type); + + assign(op1, get_gpr_int(r1, type)); + if (opc == S390_CC_OP_SIGNED_COMPARE) { + assign(op2, type == Ity_I64 ? + mkU64((ULong)(Short)i2) : mkU32((UInt)(Short)i2)); + } else { + assign(op2, type == Ity_I64 ? + mkU64((ULong)i2) : mkU32((UInt)i2)); + } + cond = binop(Iop_CmpNE32, + s390_call_calculate_icc(m3, opc, op1, op2), mkU32(0)); + } + s390_trap_on_condition(cond); +} + +static const HChar * +s390_irgen_CGIT(UChar r1, UShort i2, UChar m3) +{ + s390_irgen_CxIT(m3, r1, i2, Ity_I64, S390_CC_OP_SIGNED_COMPARE); + return "cgit"; +} + +static const HChar * +s390_irgen_CIT(UChar r1, UShort i2, UChar m3) +{ + s390_irgen_CxIT(m3, r1, i2, Ity_I32, S390_CC_OP_SIGNED_COMPARE); + return "cit"; +} + +static const HChar * +s390_irgen_CLGIT(UChar r1, UShort i2, UChar m3) +{ + s390_irgen_CxIT(m3, r1, i2, Ity_I64, S390_CC_OP_UNSIGNED_COMPARE); + return "clgit"; +} + +static const HChar * +s390_irgen_CLFIT(UChar r1, UShort i2, UChar m3) +{ + s390_irgen_CxIT(m3, r1, i2, Ity_I32, S390_CC_OP_UNSIGNED_COMPARE); + return "clfit"; +} + +/* Handle the variants of compare logical and trap with memory operand. */ +static void +s390_irgen_CLxT(UChar r1, UChar m3, IRTemp op2addr, IRType type, UInt opc) +{ + IRExpr *cond; + + if (m3 == 0) { + /* Trap never (NOP) */ + return; + } else if (m3 == 14) { + /* Trap always */ + cond = IRExpr_Const(IRConst_U1 (True)); + } else { + IRTemp op1 = newTemp(type); + IRTemp op2 = newTemp(type); + + assign(op1, get_gpr_int(r1, type)); + assign(op2, load(type, mkexpr(op2addr))); + cond = binop(Iop_CmpNE32, + s390_call_calculate_icc(m3, opc, op1, op2), mkU32(0)); + } + s390_trap_on_condition(cond); +} + +static const HChar * +s390_irgen_CLT(UChar r1, UChar m3, IRTemp op2addr) +{ + s390_irgen_CLxT(r1, m3, op2addr, Ity_I32, S390_CC_OP_UNSIGNED_COMPARE); + return "clt"; +} + +static const HChar * +s390_irgen_CLGT(UChar r1, UChar m3, IRTemp op2addr) +{ + s390_irgen_CLxT(r1, m3, op2addr, Ity_I64, S390_CC_OP_UNSIGNED_COMPARE); + return "clgt"; +} + +static const HChar * +s390_irgen_LAT(UChar r1, IRTemp op2addr) +{ + IRTemp val = newTemp(Ity_I32); + assign(val, load(Ity_I32, mkexpr(op2addr))); + put_gpr_w1(r1, mkexpr(val)); + s390_trap_on_condition(binop(Iop_CmpEQ32, mkexpr(val), mkU32(0))); + return "lat"; +} + +static const HChar * +s390_irgen_LGAT(UChar r1, IRTemp op2addr) +{ + IRTemp val = newTemp(Ity_I64); + assign(val, load(Ity_I64, mkexpr(op2addr))); + put_gpr_dw0(r1, mkexpr(val)); + s390_trap_on_condition(binop(Iop_CmpEQ64, mkexpr(val), mkU64(0))); + return "lgat"; +} + +static const HChar * +s390_irgen_LFHAT(UChar r1, IRTemp op2addr) +{ + IRTemp val = newTemp(Ity_I32); + assign(val, load(Ity_I32, mkexpr(op2addr))); + put_gpr_w0(r1, mkexpr(val)); + s390_trap_on_condition(binop(Iop_CmpEQ32, mkexpr(val), mkU32(0))); + return "lfhat"; +} + +static const HChar * +s390_irgen_LLGFAT(UChar r1, IRTemp op2addr) +{ + IRTemp val = newTemp(Ity_I64); + assign(val, unop(Iop_32Uto64, load(Ity_I32, mkexpr(op2addr)))); + put_gpr_dw0(r1, mkexpr(val)); + s390_trap_on_condition(binop(Iop_CmpEQ64, mkexpr(val), mkU64(0))); + return "llgfat"; +} + +static const HChar * +s390_irgen_LLGTAT(UChar r1, IRTemp op2addr) +{ + IRTemp val = newTemp(Ity_I64); + assign(val, binop(Iop_And64, mkU64(0x7fffffff), + unop(Iop_32Uto64, load(Ity_I32, mkexpr(op2addr))))); + put_gpr_dw0(r1, mkexpr(val)); + s390_trap_on_condition(binop(Iop_CmpEQ64, mkexpr(val), mkU64(0))); + return "llgtat"; +} + static const HChar * s390_irgen_CLRJ(UChar r1, UChar r2, UShort i4, UChar m3) { @@ -16943,10 +17178,18 @@ s390_decode_4byte_and_irgen(const UChar *bytes) case 0xb95b: s390_format_RRF_UUFR(s390_irgen_CXLFTR, ovl.fmt.RRF2.m3, ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, ovl.fmt.RRF2.r2); goto ok; - case 0xb960: /* CGRT */ goto unimplemented; - case 0xb961: /* CLGRT */ goto unimplemented; - case 0xb972: /* CRT */ goto unimplemented; - case 0xb973: /* CLRT */ goto unimplemented; + case 0xb960: s390_format_RRF_U0RR(s390_irgen_CGRT, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.r1, ovl.fmt.RRF2.r2, + S390_XMNM_CAB); goto ok; + case 0xb961: s390_format_RRF_U0RR(s390_irgen_CLGRT, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.r1, ovl.fmt.RRF2.r2, + S390_XMNM_CAB); goto ok; + case 0xb972: s390_format_RRF_U0RR(s390_irgen_CRT, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.r1, ovl.fmt.RRF2.r2, + S390_XMNM_CAB); goto ok; + case 0xb973: s390_format_RRF_U0RR(s390_irgen_CLRT, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.r1, ovl.fmt.RRF2.r2, + S390_XMNM_CAB); goto ok; case 0xb980: s390_format_RRE_RR(s390_irgen_NGR, ovl.fmt.RRE.r1, ovl.fmt.RRE.r2); goto ok; case 0xb981: s390_format_RRE_RR(s390_irgen_OGR, ovl.fmt.RRE.r1, @@ -17796,7 +18039,11 @@ s390_decode_6byte_and_irgen(const UChar *bytes) ovl.fmt.RXY.dh2); goto ok; case 0xe30000000083ULL: /* MSGC */ goto unimplemented; case 0xe30000000084ULL: /* MG */ goto unimplemented; - case 0xe30000000085ULL: /* LGAT */ goto unimplemented; + case 0xe30000000085ULL: s390_format_RXY_RRRD(s390_irgen_LGAT, ovl.fmt.RXY.r1, + ovl.fmt.RXY.x2, ovl.fmt.RXY.b2, + ovl.fmt.RXY.dl2, + ovl.fmt.RXY.dh2); goto ok; + case 0xe30000000086ULL: s390_format_RXY_RRRD(s390_irgen_MLG, ovl.fmt.RXY.r1, ovl.fmt.RXY.x2, ovl.fmt.RXY.b2, ovl.fmt.RXY.dl2, @@ -17853,9 +18100,18 @@ 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 0xe3000000009cULL: /* LLGTAT */ goto unimplemented; - case 0xe3000000009dULL: /* LLGFAT */ goto unimplemented; - case 0xe3000000009fULL: /* LAT */ goto unimplemented; + case 0xe3000000009cULL: s390_format_RXY_RRRD(s390_irgen_LLGTAT, ovl.fmt.RXY.r1, + ovl.fmt.RXY.x2, ovl.fmt.RXY.b2, + ovl.fmt.RXY.dl2, + ovl.fmt.RXY.dh2); goto ok; + case 0xe3000000009dULL: s390_format_RXY_RRRD(s390_irgen_LLGFAT, ovl.fmt.RXY.r1, + ovl.fmt.RXY.x2, ovl.fmt.RXY.b2, + ovl.fmt.RXY.dl2, + ovl.fmt.RXY.dh2); goto ok; + case 0xe3000000009fULL: s390_format_RXY_RRRD(s390_irgen_LAT, ovl.fmt.RXY.r1, + ovl.fmt.RXY.x2, ovl.fmt.RXY.b2, + ovl.fmt.RXY.dl2, + ovl.fmt.RXY.dh2); goto ok; case 0xe300000000c0ULL: s390_format_RXY_RRRD(s390_irgen_LBH, ovl.fmt.RXY.r1, ovl.fmt.RXY.x2, ovl.fmt.RXY.b2, ovl.fmt.RXY.dl2, @@ -17880,7 +18136,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 0xe300000000c8ULL: /* LFHAT */ goto unimplemented; + case 0xe300000000c8ULL: s390_format_RXY_RRRD(s390_irgen_LFHAT, ovl.fmt.RXY.r1, + ovl.fmt.RXY.x2, ovl.fmt.RXY.b2, + ovl.fmt.RXY.dl2, + ovl.fmt.RXY.dh2); goto ok; case 0xe300000000caULL: s390_format_RXY_RRRD(s390_irgen_LFH, ovl.fmt.RXY.r1, ovl.fmt.RXY.x2, ovl.fmt.RXY.b2, ovl.fmt.RXY.dl2, @@ -18224,7 +18483,10 @@ 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 0xeb0000000023ULL: /* CLT */ goto unimplemented; + case 0xeb0000000023ULL: s390_format_RSY_RURD(s390_irgen_CLT, ovl.fmt.RSY.r1, + ovl.fmt.RSY.r3, ovl.fmt.RSY.b2, + ovl.fmt.RSY.dl2, + ovl.fmt.RSY.dh2); goto ok; case 0xeb0000000024ULL: s390_format_RSY_RRRD(s390_irgen_STMG, ovl.fmt.RSY.r1, ovl.fmt.RSY.r3, ovl.fmt.RSY.b2, ovl.fmt.RSY.dl2, @@ -18234,7 +18496,10 @@ 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 0xeb000000002bULL: /* CLGT */ goto unimplemented; + case 0xeb000000002bULL: s390_format_RSY_RURD(s390_irgen_CLGT, ovl.fmt.RSY.r1, + ovl.fmt.RSY.r3, ovl.fmt.RSY.b2, + ovl.fmt.RSY.dl2, + ovl.fmt.RSY.dh2); goto ok; case 0xeb000000002cULL: s390_format_RSY_RURD(s390_irgen_STCMH, ovl.fmt.RSY.r1, ovl.fmt.RSY.r3, ovl.fmt.RSY.b2, ovl.fmt.RSY.dl2, @@ -18498,10 +18763,22 @@ s390_decode_6byte_and_irgen(const UChar *bytes) ovl.fmt.RIE_RRPU.r2, ovl.fmt.RIE_RRPU.i4, ovl.fmt.RIE_RRPU.m3); goto ok; - case 0xec0000000070ULL: /* CGIT */ goto unimplemented; - case 0xec0000000071ULL: /* CLGIT */ goto unimplemented; - case 0xec0000000072ULL: /* CIT */ goto unimplemented; - case 0xec0000000073ULL: /* CLFIT */ goto unimplemented; + case 0xec0000000070ULL: s390_format_RIEv1(s390_irgen_CGIT, + ovl.fmt.RIEv1.r1, + ovl.fmt.RIEv1.i2, + ovl.fmt.RIEv1.m3); goto ok; + case 0xec0000000071ULL: s390_format_RIEv1(s390_irgen_CLGIT, + ovl.fmt.RIEv1.r1, + ovl.fmt.RIEv1.i2, + ovl.fmt.RIEv1.m3); goto ok; + case 0xec0000000072ULL: s390_format_RIEv1(s390_irgen_CIT, + ovl.fmt.RIEv1.r1, + ovl.fmt.RIEv1.i2, + ovl.fmt.RIEv1.m3); goto ok; + case 0xec0000000073ULL: s390_format_RIEv1(s390_irgen_CLFIT, + ovl.fmt.RIEv1.r1, + ovl.fmt.RIEv1.i2, + ovl.fmt.RIEv1.m3); goto ok; case 0xec0000000076ULL: s390_format_RIE_RRPU(s390_irgen_CRJ, ovl.fmt.RIE_RRPU.r1, ovl.fmt.RIE_RRPU.r2, diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index d41093eb01..6c35c67246 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -6917,6 +6917,7 @@ s390_jump_kind_as_string(IRJumpKind kind) case Ijk_InvalICache: return "Invalidate"; case Ijk_NoRedir: return "NoRedir"; case Ijk_SigTRAP: return "SigTRAP"; + case Ijk_SigFPE: return "SigFPE"; case Ijk_SigSEGV: return "SigSEGV"; case Ijk_SigBUS: return "SigBUS"; case Ijk_Sys_syscall: return "Sys_syscall"; @@ -10388,6 +10389,7 @@ s390_insn_xassisted_emit(UChar *buf, const s390_insn *insn, case Ijk_InvalICache: trcval = VEX_TRC_JMP_INVALICACHE; break; case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break; case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break; + case Ijk_SigFPE: trcval = VEX_TRC_JMP_SIGFPE; break; case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break; case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break; /* We don't expect to see the following being assisted. */ diff --git a/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index ab71afeb2d..dec1259f6e 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -4441,7 +4441,8 @@ no_memcpy_put: case Ijk_ClientReq: case Ijk_NoRedir: case Ijk_Yield: - case Ijk_SigTRAP: { + case Ijk_SigTRAP: + case Ijk_SigFPE: { HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst)); addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, stmt->Ist.Exit.jk)); @@ -4556,7 +4557,8 @@ iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP) case Ijk_ClientReq: case Ijk_NoRedir: case Ijk_Yield: - case Ijk_SigTRAP: { + case Ijk_SigTRAP: + case Ijk_SigFPE: { HReg dst = s390_isel_int_expr(env, next); addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk)); return; diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 2b07afd512..4beaabd387 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -2378,6 +2378,7 @@ typedef Ijk_SigTRAP, /* current instruction synths SIGTRAP */ Ijk_SigSEGV, /* current instruction synths SIGSEGV */ Ijk_SigBUS, /* current instruction synths SIGBUS */ + Ijk_SigFPE, /* current instruction synths generic SIGFPE */ Ijk_SigFPE_IntDiv, /* current instruction synths SIGFPE - IntDiv */ Ijk_SigFPE_IntOvf, /* current instruction synths SIGFPE - IntOvf */ /* Unfortunately, various guest-dependent syscall kinds. They diff --git a/VEX/pub/libvex_trc_values.h b/VEX/pub/libvex_trc_values.h index e46e0fba73..fb879b1e02 100644 --- a/VEX/pub/libvex_trc_values.h +++ b/VEX/pub/libvex_trc_values.h @@ -58,6 +58,7 @@ #define VEX_TRC_JMP_SIGSEGV 87 /* deliver segv (SIGSEGV) before continuing */ #define VEX_TRC_JMP_SIGBUS 93 /* deliver SIGBUS before continuing */ +#define VEX_TRC_JMP_SIGFPE 105 /* deliver SIGFPE before continuing */ #define VEX_TRC_JMP_SIGFPE_INTDIV 97 /* deliver SIGFPE (integer divide by zero) before continuing */ diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c index 87cb4d6646..68e9590a01 100644 --- a/coregrind/m_scheduler/scheduler.c +++ b/coregrind/m_scheduler/scheduler.c @@ -1591,6 +1591,10 @@ VgSchedReturnCode VG_(scheduler) ( ThreadId tid ) VG_(synth_sigbus)(tid); break; + case VEX_TRC_JMP_SIGFPE: + VG_(synth_sigfpe)(tid, 0); + break; + case VEX_TRC_JMP_SIGFPE_INTDIV: VG_(synth_sigfpe)(tid, VKI_FPE_INTDIV); break; diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c index e158fe3cb8..e572f17cc3 100644 --- a/coregrind/m_signals.c +++ b/coregrind/m_signals.c @@ -2157,8 +2157,8 @@ void VG_(synth_sigtrap)(ThreadId tid) // Synthesise a SIGFPE. void VG_(synth_sigfpe)(ThreadId tid, UInt code) { -// Only tested on mips32 and mips64 -#if !defined(VGA_mips32) && !defined(VGA_mips64) +// Only tested on mips32, mips64, and s390x +#if !defined(VGA_mips32) && !defined(VGA_mips64) && !defined(VGA_s390x) vg_assert(0); #else vki_siginfo_t info; diff --git a/docs/internals/s390-opcodes.csv b/docs/internals/s390-opcodes.csv index 36becfd073..fe84a7c136 100644 --- a/docs/internals/s390-opcodes.csv +++ b/docs/internals/s390-opcodes.csv @@ -759,10 +759,10 @@ cib,"compare immediate and branch (32<8)",implemented, cgib,"compare immediate and branch (64<8)",implemented, cij,"compare immediate and branch relative (32<8)",implemented, cgij,"compare immediate and branch relative (64<8)",implemented, -crt,"compare and trap","not implemented","issued by gcc" -cgrt,"compare and trap 64","not implemented","issued by gcc" -cit,"compare immediate and trap (32<16)","not implemented","issued by gcc" -cgit,"compare immediate and trap (64<16)","not implemented","issued by gcc" +crt,"compare and trap",implemented, +cgrt,"compare and trap 64",implemented, +cit,"compare immediate and trap (32<16)",implemented, +cgit,"compare immediate and trap (64<16)",implemented, cgh,"compare halfword (64<16)",implemented, chhsi,"compare halfword immediate (16<16)",implemented, chsi,"compare halfword immediate (32<16)",implemented, @@ -785,10 +785,10 @@ clib,"compare logical immediate and branch (32<8)",implemented, clgib,"compare logical immediate and branch (64<8)",implemented, clij,"compare logical immediate and branch relative (32<8)",implemented, clgij,"compare logical immediate and branch relative (64<8)",implemented, -clrt,"compare logical and trap (32)","not implemented", -clgrt,"compare logical and trap (64)","not implemented", -clfit,"compare logical and trap (32<16)","not implemented", -clgit,"compare logical and trap (64<16)","not implemented", +clrt,"compare logical and trap (32)",implemented, +clgrt,"compare logical and trap (64)",implemented, +clfit,"compare logical and trap (32<16)",implemented, +clgit,"compare logical and trap (64<16)",implemented, ecag,"extract cache attribute",implemented, lrl,"load relative long (32)",implemented, lgrl,"load relative long (64)",implemented, @@ -968,13 +968,13 @@ bprp,"branch prediction relative preload","not implemented",zEC12, ppa,"perform processor assist","not implemented",zEC12, niai,"next instruction access intent","not implemented",zEC12, crdte,"compare and replace DAT table entry",N/A,"privileged instruction" -lat,"load and trap 32 bit","not implemented",zEC12, -lgat,"load and trap 64 bit","not implemented",zEC12, -lfhat,"load high and trap","not implemented",zEC12, -llgfat,"load logical and trap 32>64","not implemented",zEC12, -llgtat,"load logical thirty one bits and trap 31>64","not implemented",zEC12, -clt,"compare logical and trap 32 bit reg-mem","not implemented",zEC12, -clgt,"compare logical and trap 64 bit reg-mem","not implemented",zEC12, +lat,"load and trap 32 bit",implemented,zEC12, +lgat,"load and trap 64 bit",implemented,zEC12, +lfhat,"load high and trap",implemented,zEC12, +llgfat,"load logical and trap 32>64",implemented,zEC12, +llgtat,"load logical thirty one bits and trap 31>64",implemented,zEC12, +clt,"compare logical and trap 32 bit reg-mem",implemented,zEC12, +clgt,"compare logical and trap 64 bit reg-mem",implemented,zEC12, risbgn,"rotate then insert selected bits nocc",implemented,zEC12, cdzt,"convert from zoned long","not implemented",zEC12, cxzt,"convert from zoned extended","not implemented",zEC12, diff --git a/none/tests/s390x/Makefile.am b/none/tests/s390x/Makefile.am index 29cd6a342f..ff9c291126 100644 --- a/none/tests/s390x/Makefile.am +++ b/none/tests/s390x/Makefile.am @@ -12,7 +12,7 @@ INSN_TESTS = clc clcle cvb cvd icm lpr tcxb lam_stam xc mvst add sub mul \ rounding-1 rounding-2 rounding-3 rounding-4 rounding-5 bfp-1 \ bfp-2 bfp-3 bfp-4 srnm srnmb comp-1 comp-2 exrl tmll tm stmg \ ex clst mvc test_fork test_sig rounding-6 rxsbg popcnt \ - high-word \ + high-word traps \ spechelper-alr spechelper-algr \ spechelper-slr spechelper-slgr \ spechelper-cr spechelper-clr \ diff --git a/none/tests/s390x/traps.c b/none/tests/s390x/traps.c new file mode 100644 index 0000000000..86874c3afd --- /dev/null +++ b/none/tests/s390x/traps.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSK_NEVER 0x0 +#define MSK_GT 0x2 +#define MSK_LT 0x4 +#define MSK_NE 0x6 +#define MSK_EQ 0x8 +#define MSK_GE 0xa +#define MSK_LE 0xc +#define MSK_ALWAYS 14 + +#define str(a) #a + +static const char *msk_op[] = { + "N", ">", "<", "!=", "==", ">=", "<=", "Y" +}; + +static void handle_sigfpe(int sig, siginfo_t *info, void *uc) +{ + printf(" [FPE %d]", info->si_code); + fflush(stdout); +} + +/* Load and trap. */ + +#define test_LxAT(type,mnem,opc) \ + { \ + static const type vals[] = { \ + 0x12345678, -0x12345678, 0x80000000, 0 \ + }; \ + int i; \ + printf("%-6s", mnem); fflush(stdout); \ + for (i = 0; i < sizeof(vals) / sizeof(vals[0]); i++) { \ + unsigned long result; \ + asm volatile("lghi %[out], -1\n" \ + ".insn rxy, 0x" opc ",%[out],%[in]\n" \ + : [out] "=&d" (result) : [in] "R" (vals[i])); \ + printf(" %016lx", result); \ + } \ + putchar('\n'); \ + } + +/* Compare and trap, register/register. */ + +#define insn_CxRT(type,fmt,opc,mask,a_val,b_val) { \ + type a = a_val; \ + type b = b_val; \ + printf(" " fmt " %s " fmt, a, msk_op[mask / 2], b); \ + fflush(stdout); \ + asm volatile(".insn rrf, 0x" opc "0000,%[a],%[b]," str(mask) ",0\n" \ + : : [a] "d" (a), [b] "d" (b)); \ + putchar('\n'); \ + } + +#define test_CxRT(type,fmt,mnem,opc) { \ + printf("%s:\n", mnem); \ + insn_CxRT(type, fmt, opc, MSK_ALWAYS, 0, 0); \ + insn_CxRT(type, fmt, opc, MSK_LT, 1, -1); \ + insn_CxRT(type, fmt, opc, MSK_GT, 0x7fffffff, -0x80000000); \ + } + +/* Compare and trap, register/immediate. */ + +#define insn_CxIT(sign,type,fmt,opc1,opc2,mask,val,imm) { \ + sign type a = val; \ + printf(" " fmt " %s " fmt, a, msk_op[mask / 2], \ + (sign type)(sign short) imm); \ + fflush(stdout); \ + asm volatile(".insn ri, 0x" opc1 "000000,%[a]," str(imm) "\n" \ + ".byte " str(mask) "*16, 0x" opc2 "\n" \ + : : [a] "d" (a)); \ + putchar('\n'); \ + } + +#define test_CxIT(sign,type,fmt,mnem,opc1,opc2) { \ + printf("%s:\n", mnem); \ + insn_CxIT(sign, type, fmt, opc1, opc2, MSK_NEVER, 0, 0); \ + insn_CxIT(sign, type, fmt, opc1, opc2, MSK_NE, -1, -1); \ + insn_CxIT(sign, type, fmt, opc1, opc2, MSK_LE, -0x80000000, 41); \ + } + +/* Compare and trap, register/memory. */ + +#define insn_CLxT(type,fmt,opc1,opc2,mask,a_val,b_val) { \ + type a = a_val; \ + type b = b_val; \ + printf(" " fmt " %s " fmt, a, msk_op[mask / 2], b); \ + fflush(stdout); \ + asm volatile(".insn rsy, 0x" opc1 "00000000" opc2 ",%[a]," \ + str(mask) ",%[b]\n" : : [a] "d" (a), [b] "R" (b)); \ + putchar('\n'); \ + } + +#define test_CLxT(type,fmt,mnem,opc1,opc2) { \ + printf("%s:\n", mnem); \ + insn_CLxT(type, fmt, opc1, opc2, MSK_GE, 1, -1); \ + insn_CLxT(type, fmt, opc1, opc2, MSK_EQ, 0xffffffff, -1); \ + } + +int main(void) +{ + struct sigaction sa; + + sa.sa_sigaction = handle_sigfpe; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sigaction(SIGFPE, &sa, NULL); + + test_LxAT(unsigned, "lat", "e3000000009f"); + test_LxAT(unsigned long, "lgat", "e30000000085"); + test_LxAT(unsigned, "lfhat", "e300000000c8"); + test_LxAT(unsigned, "llgfat", "e3000000009d"); + test_LxAT(unsigned, "llgtat", "e3000000009c"); + + putchar('\n'); + test_CxRT(int, "%d", "crt", "b972"); + test_CxRT(unsigned int, "%u", "clrt", "b973"); + test_CxRT(long int, "%ld", "cgrt", "b960"); + test_CxRT(unsigned long, "%lu", "clgrt", "b961"); + + putchar('\n'); + test_CxIT(signed, int, "%d", "cit", "ec", "72"); + test_CxIT(unsigned, int, "%u", "clfit", "ec", "73"); + test_CxIT(signed, long, "%ld", "cgit", "ec", "70"); + test_CxIT(unsigned, long, "%lu", "clgit", "ec", "71"); + + putchar('\n'); + test_CLxT(unsigned int, "%u", "clt", "eb", "23"); + test_CLxT(unsigned long, "%lu", "clgt", "eb", "2b"); + return 0; +} diff --git a/none/tests/s390x/traps.stderr.exp b/none/tests/s390x/traps.stderr.exp new file mode 100644 index 0000000000..139597f9cb --- /dev/null +++ b/none/tests/s390x/traps.stderr.exp @@ -0,0 +1,2 @@ + + diff --git a/none/tests/s390x/traps.stdout.exp b/none/tests/s390x/traps.stdout.exp new file mode 100644 index 0000000000..59a55b32ed --- /dev/null +++ b/none/tests/s390x/traps.stdout.exp @@ -0,0 +1,46 @@ +lat ffffffff12345678 ffffffffedcba988 ffffffff80000000 [FPE 0] ffffffff00000000 +lgat 0000000012345678 ffffffffedcba988 0000000080000000 [FPE 0] 0000000000000000 +lfhat 12345678ffffffff edcba988ffffffff 80000000ffffffff [FPE 0] 00000000ffffffff +llgfat 0000000012345678 00000000edcba988 0000000080000000 [FPE 0] 0000000000000000 +llgtat 0000000012345678 000000006dcba988 [FPE 0] 0000000000000000 [FPE 0] 0000000000000000 + +crt: + 0 Y 0 [FPE 0] + 1 < -1 + 2147483647 > -2147483648 [FPE 0] +clrt: + 0 Y 0 [FPE 0] + 1 < 4294967295 [FPE 0] + 2147483647 > 2147483648 +cgrt: + 0 Y 0 [FPE 0] + 1 < -1 + 2147483647 > 2147483648 +clgrt: + 0 Y 0 [FPE 0] + 1 < 18446744073709551615 [FPE 0] + 2147483647 > 2147483648 + +cit: + 0 N 0 + -1 != -1 + -2147483648 <= 41 [FPE 0] +clfit: + 0 N 0 + 4294967295 != 65535 [FPE 0] + 2147483648 <= 41 +cgit: + 0 N 0 + -1 != -1 + 2147483648 <= 41 +clgit: + 0 N 0 + 18446744073709551615 != 65535 [FPE 0] + 2147483648 <= 41 + +clt: + 1 >= 4294967295 + 4294967295 == 4294967295 [FPE 0] +clgt: + 1 >= 18446744073709551615 + 4294967295 == 18446744073709551615 diff --git a/none/tests/s390x/traps.vgtest b/none/tests/s390x/traps.vgtest new file mode 100644 index 0000000000..e46fb15aad --- /dev/null +++ b/none/tests/s390x/traps.vgtest @@ -0,0 +1 @@ +prog: traps -- 2.47.2