]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390x: Implement conditional trap instructions
authorAndreas Arnez <arnez@linux.vnet.ibm.com>
Wed, 25 Jul 2018 12:23:02 +0000 (14:23 +0200)
committerAndreas Arnez <arnez@linux.ibm.com>
Mon, 24 Sep 2018 14:06:19 +0000 (16:06 +0200)
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.

14 files changed:
.gitignore
VEX/priv/guest_s390_toIR.c
VEX/priv/host_s390_defs.c
VEX/priv/host_s390_isel.c
VEX/pub/libvex_ir.h
VEX/pub/libvex_trc_values.h
coregrind/m_scheduler/scheduler.c
coregrind/m_signals.c
docs/internals/s390-opcodes.csv
none/tests/s390x/Makefile.am
none/tests/s390x/traps.c [new file with mode: 0644]
none/tests/s390x/traps.stderr.exp [new file with mode: 0644]
none/tests/s390x/traps.stdout.exp [new file with mode: 0644]
none/tests/s390x/traps.vgtest [new file with mode: 0644]

index fc22c9442558507f142a14783f6f8d3ad0287780..7b93983116bf9124dca9f9c4d009d41cbb8b6849 100644 (file)
 /none/tests/s390x/vector
 /none/tests/s390x/lsc2
 /none/tests/s390x/ppno
+/none/tests/s390x/traps
 
 # /none/tests/scripts/
 /none/tests/scripts/*.dSYM
index 1697e9744bfc7487b87a207db1b06128394bf6ff..8f3fb6d3d47930aad93c130da99b7b1acbf86682 100644 (file)
@@ -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,
index d41093eb0133d758acfcbc47ea993b07116218c1..6c35c6724628827d409e83307772de21196ee8f3 100644 (file)
@@ -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. */
index ab71afeb2d305756ad8c6d69b1349547a71c6137..dec1259f6ed2cf10a30e7dbd1d7a413b12cf09b4 100644 (file)
@@ -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;
index 2b07afd5124f3570ef4d670d4da39637fe51e502..4beaabd38772f91f21112e379439a3f637b73dca 100644 (file)
@@ -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
index e46e0fba73a7b8a6a4536fb6f7b8d905c067ddbf..fb879b1e02e6bbc97f3a68e67613d343cc9aa7dc 100644 (file)
@@ -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 */
index 87cb4d6646ae2cdb1a95e55210b2ef9104ee2bcf..68e9590a01d33766291e5cad3a1ca08540da76ea 100644 (file)
@@ -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;
index e158fe3cb82d64bf6c158247d8653a3f67e7367e..e572f17cc3a002d711af4469b55f568e5ac863c1 100644 (file)
@@ -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;
index 36becfd073c1e8bab5277a61bca97ccb9dad695e..fe84a7c1364a45a60d5f92ab5c06a01305bd86c5 100644 (file)
@@ -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,
index 29cd6a342fdfe11028e2d67f811053219f3bcba6..ff9c29112655400fb6ef3c9668b36f05d76cea1e 100644 (file)
@@ -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 (file)
index 0000000..86874c3
--- /dev/null
@@ -0,0 +1,139 @@
+#include <features.h>
+#include <fpu_control.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+#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 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/s390x/traps.stdout.exp b/none/tests/s390x/traps.stdout.exp
new file mode 100644 (file)
index 0000000..59a55b3
--- /dev/null
@@ -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 (file)
index 0000000..e46fb15
--- /dev/null
@@ -0,0 +1 @@
+prog: traps