/none/tests/s390x/vector
/none/tests/s390x/lsc2
/none/tests/s390x/ppno
+/none/tests/s390x/traps
# /none/tests/scripts/
/none/tests/scripts/*.dSYM
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)
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),
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)
{
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,
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,
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,
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,
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,
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,
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,
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";
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. */
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));
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;
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
#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 */
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;
// 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;
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,
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,
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,
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 \
--- /dev/null
+#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;
+}
--- /dev/null
+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
--- /dev/null
+prog: traps