ppc-7.0 queue :

* Clang fixes
 * Vector/VSX instruction batch fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmIjHL4ACgkQUaNDx8/7
 7KH+sg/+JZW/X+U7uZRT9vK6vS4jqFG7gn55ouZKSvAQtPUMtUFdkEL/jeA3IuHh
 kRvmjGwWjtjgM9TIiJsVBo8yJeMqUO8f6AKUtaQU/3vT4CPO2Jbd8X0A58OOoe4I
 M3fzWf/18bAYPPEZAxmlJ8f8LEPsBOLM0tQ2py7JkVpUQU3WcP7/YgXbYRH1l+9k
 m1lMyXGZ/dQDxkFel9TGcfuHXVecBngyx4O1pJ1JkHduo+bLAi6h5HJgdj1wEVfr
 5vyqn7OULm6bPXWRb1j+CnCj0QO0VAky4hC4HDGajMlcnG8l/X8Dzs2bD+ua/VbE
 1aNkVpuNtuu0ljKfarqMED2no8lPJg4MpKOZvi8O128/bU+IkmJUYI2g73Gr6URL
 V6/Awh0syy9mi04gsXMD5kCwFLuBNQ5jC3z1aAZNy7Be/l37vzAoN0i53eYAGK3D
 rBTuMictAKRXKyXQ63VLiYqSdUB6zVoOIM6w3HJxQTQ8YkJ/Hx5cfOGv+lnTIdsK
 cX4e7s1p8YPSnDOEfEKTk+gnVcTn57FAhNJhelRuC1s2/OI8Gz4n+3eUGmcl04Bq
 +gcD1UEGMEsQpjMz+ikPuGMZvmF5gPr+9S3DPyMfUOoQJFUI8GOxq9SmUVKC9fki
 6oHTHpOvZg8MSJz8gzETq18hwHRKoRb95KzVHWGj1EG0ekjHG2U=
 =C+wh
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/legoater/tags/pull-ppc-20220305' into staging

ppc-7.0 queue :

* Clang fixes
* Vector/VSX instruction batch fixes

# gpg: Signature made Sat 05 Mar 2022 08:18:06 GMT
# gpg:                using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B  0B60 51A3 43C7 CFFB ECA1

* remotes/legoater/tags/pull-ppc-20220305:
  target/ppc: Add missing helper_reset_fpstatus to helper_XVCVSPBF16
  target/ppc: Add missing helper_reset_fpstatus to VSX_MAX_MINC
  target/ppc: split XXGENPCV macros for readability
  target/ppc: use andc in vrlqmi
  target/ppc: use extract/extract2 to create vrlqnm mask
  target/ppc: use ext32u and deposit in do_vx_vmulhw_i64
  target/ppc: Fix vmul[eo]* instructions marked 2.07
  tests/tcg/ppc64le: Use Altivec register names in clobber list
  tests/tcg/ppc64le: emit bcdsub with .long when needed
  tests/tcg/ppc64le: drop __int128 usage in bcdsub
  target/ppc: change xs[n]madd[am]sp to use float64r32_muladd
  tests/tcg/ppc64le: use inline asm instead of __builtin_mtfsf
  Use long endian options for ppc64

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2022-03-05 18:03:15 +00:00
commit 9d662a6b22
9 changed files with 187 additions and 193 deletions

4
configure vendored
View File

@ -630,10 +630,10 @@ case "$cpu" in
ppc)
CPU_CFLAGS="-m32" ;;
ppc64)
CPU_CFLAGS="-m64 -mbig" ;;
CPU_CFLAGS="-m64 -mbig-endian" ;;
ppc64le)
cpu="ppc64"
CPU_CFLAGS="-m64 -mlittle" ;;
CPU_CFLAGS="-m64 -mlittle-endian" ;;
s390)
CPU_CFLAGS="-m31" ;;

View File

@ -2156,9 +2156,8 @@ VSX_TSQRT(xvtsqrtsp, 4, float32, VsrW(i), -126, 23)
* maddflgs - flags for the float*muladd routine that control the
* various forms (madd, msub, nmadd, nmsub)
* sfprf - set FPRF
* r2sp - round intermediate double precision result to single precision
*/
#define VSX_MADD(op, nels, tp, fld, maddflgs, sfprf, r2sp) \
#define VSX_MADD(op, nels, tp, fld, maddflgs, sfprf) \
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
ppc_vsr_t *s1, ppc_vsr_t *s2, ppc_vsr_t *s3) \
{ \
@ -2170,20 +2169,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
for (i = 0; i < nels; i++) { \
float_status tstat = env->fp_status; \
set_float_exception_flags(0, &tstat); \
if (r2sp && (tstat.float_rounding_mode == float_round_nearest_even)) {\
/* \
* Avoid double rounding errors by rounding the intermediate \
* result to odd. \
*/ \
set_float_rounding_mode(float_round_to_zero, &tstat); \
t.fld = tp##_muladd(s1->fld, s3->fld, s2->fld, \
maddflgs, &tstat); \
t.fld |= (get_float_exception_flags(&tstat) & \
float_flag_inexact) != 0; \
} else { \
t.fld = tp##_muladd(s1->fld, s3->fld, s2->fld, \
maddflgs, &tstat); \
} \
t.fld = tp##_muladd(s1->fld, s3->fld, s2->fld, maddflgs, &tstat); \
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
\
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
@ -2191,10 +2177,6 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
sfprf, GETPC()); \
} \
\
if (r2sp) { \
t.fld = do_frsp(env, t.fld, GETPC()); \
} \
\
if (sfprf) { \
helper_compute_fprf_float64(env, t.fld); \
} \
@ -2203,24 +2185,24 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
do_float_check_status(env, GETPC()); \
}
VSX_MADD(XSMADDDP, 1, float64, VsrD(0), MADD_FLGS, 1, 0)
VSX_MADD(XSMSUBDP, 1, float64, VsrD(0), MSUB_FLGS, 1, 0)
VSX_MADD(XSNMADDDP, 1, float64, VsrD(0), NMADD_FLGS, 1, 0)
VSX_MADD(XSNMSUBDP, 1, float64, VsrD(0), NMSUB_FLGS, 1, 0)
VSX_MADD(XSMADDSP, 1, float64, VsrD(0), MADD_FLGS, 1, 1)
VSX_MADD(XSMSUBSP, 1, float64, VsrD(0), MSUB_FLGS, 1, 1)
VSX_MADD(XSNMADDSP, 1, float64, VsrD(0), NMADD_FLGS, 1, 1)
VSX_MADD(XSNMSUBSP, 1, float64, VsrD(0), NMSUB_FLGS, 1, 1)
VSX_MADD(XSMADDDP, 1, float64, VsrD(0), MADD_FLGS, 1)
VSX_MADD(XSMSUBDP, 1, float64, VsrD(0), MSUB_FLGS, 1)
VSX_MADD(XSNMADDDP, 1, float64, VsrD(0), NMADD_FLGS, 1)
VSX_MADD(XSNMSUBDP, 1, float64, VsrD(0), NMSUB_FLGS, 1)
VSX_MADD(XSMADDSP, 1, float64r32, VsrD(0), MADD_FLGS, 1)
VSX_MADD(XSMSUBSP, 1, float64r32, VsrD(0), MSUB_FLGS, 1)
VSX_MADD(XSNMADDSP, 1, float64r32, VsrD(0), NMADD_FLGS, 1)
VSX_MADD(XSNMSUBSP, 1, float64r32, VsrD(0), NMSUB_FLGS, 1)
VSX_MADD(xvmadddp, 2, float64, VsrD(i), MADD_FLGS, 0, 0)
VSX_MADD(xvmsubdp, 2, float64, VsrD(i), MSUB_FLGS, 0, 0)
VSX_MADD(xvnmadddp, 2, float64, VsrD(i), NMADD_FLGS, 0, 0)
VSX_MADD(xvnmsubdp, 2, float64, VsrD(i), NMSUB_FLGS, 0, 0)
VSX_MADD(xvmadddp, 2, float64, VsrD(i), MADD_FLGS, 0)
VSX_MADD(xvmsubdp, 2, float64, VsrD(i), MSUB_FLGS, 0)
VSX_MADD(xvnmadddp, 2, float64, VsrD(i), NMADD_FLGS, 0)
VSX_MADD(xvnmsubdp, 2, float64, VsrD(i), NMSUB_FLGS, 0)
VSX_MADD(xvmaddsp, 4, float32, VsrW(i), MADD_FLGS, 0, 0)
VSX_MADD(xvmsubsp, 4, float32, VsrW(i), MSUB_FLGS, 0, 0)
VSX_MADD(xvnmaddsp, 4, float32, VsrW(i), NMADD_FLGS, 0, 0)
VSX_MADD(xvnmsubsp, 4, float32, VsrW(i), NMSUB_FLGS, 0, 0)
VSX_MADD(xvmaddsp, 4, float32, VsrW(i), MADD_FLGS, 0)
VSX_MADD(xvmsubsp, 4, float32, VsrW(i), MSUB_FLGS, 0)
VSX_MADD(xvnmaddsp, 4, float32, VsrW(i), NMADD_FLGS, 0)
VSX_MADD(xvnmsubsp, 4, float32, VsrW(i), NMSUB_FLGS, 0)
/*
* VSX_MADDQ - VSX floating point quad-precision muliply/add
@ -2540,6 +2522,8 @@ void helper_##name(CPUPPCState *env, \
ppc_vsr_t t = { }; \
bool first; \
\
helper_reset_fpstatus(env); \
\
if (max) { \
first = tp##_le_quiet(xb->fld, xa->fld, &env->fp_status); \
} else { \
@ -2790,6 +2774,8 @@ void helper_XVCVSPBF16(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)
ppc_vsr_t t = { };
int i, status;
helper_reset_fpstatus(env);
for (i = 0; i < 4; i++) {
t.VsrH(2 * i + 1) = float32_to_bfloat16(xb->VsrW(i), &env->fp_status);
}

View File

@ -1072,7 +1072,7 @@ void helper_VPERMR(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
*r = result;
}
#define XXGENPCV(NAME, SZ) \
#define XXGENPCV_BE_EXP(NAME, SZ) \
void glue(helper_, glue(NAME, _be_exp))(ppc_vsr_t *t, ppc_vsr_t *b) \
{ \
ppc_vsr_t tmp; \
@ -1093,8 +1093,9 @@ void glue(helper_, glue(NAME, _be_exp))(ppc_vsr_t *t, ppc_vsr_t *b) \
} \
\
*t = tmp; \
} \
\
}
#define XXGENPCV_BE_COMP(NAME, SZ) \
void glue(helper_, glue(NAME, _be_comp))(ppc_vsr_t *t, ppc_vsr_t *b)\
{ \
ppc_vsr_t tmp = { .u64 = { 0, 0 } }; \
@ -1111,8 +1112,9 @@ void glue(helper_, glue(NAME, _be_comp))(ppc_vsr_t *t, ppc_vsr_t *b)\
} \
\
*t = tmp; \
} \
\
}
#define XXGENPCV_LE_EXP(NAME, SZ) \
void glue(helper_, glue(NAME, _le_exp))(ppc_vsr_t *t, ppc_vsr_t *b) \
{ \
ppc_vsr_t tmp; \
@ -1135,8 +1137,9 @@ void glue(helper_, glue(NAME, _le_exp))(ppc_vsr_t *t, ppc_vsr_t *b) \
} \
\
*t = tmp; \
} \
\
}
#define XXGENPCV_LE_COMP(NAME, SZ) \
void glue(helper_, glue(NAME, _le_comp))(ppc_vsr_t *t, ppc_vsr_t *b)\
{ \
ppc_vsr_t tmp = { .u64 = { 0, 0 } }; \
@ -1157,10 +1160,21 @@ void glue(helper_, glue(NAME, _le_comp))(ppc_vsr_t *t, ppc_vsr_t *b)\
*t = tmp; \
}
#define XXGENPCV(NAME, SZ) \
XXGENPCV_BE_EXP(NAME, SZ) \
XXGENPCV_BE_COMP(NAME, SZ) \
XXGENPCV_LE_EXP(NAME, SZ) \
XXGENPCV_LE_COMP(NAME, SZ) \
XXGENPCV(XXGENPCVBM, 1)
XXGENPCV(XXGENPCVHM, 2)
XXGENPCV(XXGENPCVWM, 4)
XXGENPCV(XXGENPCVDM, 8)
#undef XXGENPCV_BE_EXP
#undef XXGENPCV_BE_COMP
#undef XXGENPCV_LE_EXP
#undef XXGENPCV_LE_COMP
#undef XXGENPCV
#if defined(HOST_WORDS_BIGENDIAN)

View File

@ -1088,10 +1088,8 @@ static void do_vrlq_mask(TCGv_i64 mh, TCGv_i64 ml, TCGv_i64 b, TCGv_i64 e)
tcg_gen_or_i64(tl, t1, tl);
/* t = t >> 1 */
tcg_gen_shli_i64(t0, th, 63);
tcg_gen_shri_i64(tl, tl, 1);
tcg_gen_extract2_i64(tl, tl, th, 1);
tcg_gen_shri_i64(th, th, 1);
tcg_gen_or_i64(tl, t0, tl);
/* m = m ^ t */
tcg_gen_xor_i64(mh, mh, th);
@ -1148,10 +1146,8 @@ static bool do_vector_rotl_quad(DisasContext *ctx, arg_VX *a, bool mask,
tcg_gen_or_i64(t1, ah, t1);
if (mask || insert) {
tcg_gen_shri_i64(n, vrb, 8);
tcg_gen_shri_i64(vrb, vrb, 16);
tcg_gen_andi_i64(n, n, 0x7f);
tcg_gen_andi_i64(vrb, vrb, 0x7f);
tcg_gen_extract_i64(n, vrb, 8, 7);
tcg_gen_extract_i64(vrb, vrb, 16, 7);
do_vrlq_mask(ah, al, vrb, n);
@ -1161,10 +1157,8 @@ static bool do_vector_rotl_quad(DisasContext *ctx, arg_VX *a, bool mask,
if (insert) {
get_avr64(n, a->vrt, true);
get_avr64(vrb, a->vrt, false);
tcg_gen_not_i64(ah, ah);
tcg_gen_not_i64(al, al);
tcg_gen_and_i64(n, n, ah);
tcg_gen_and_i64(vrb, vrb, al);
tcg_gen_andc_i64(n, n, ah);
tcg_gen_andc_i64(vrb, vrb, al);
tcg_gen_or_i64(t0, t0, n);
tcg_gen_or_i64(t1, t1, vrb);
}
@ -3141,14 +3135,14 @@ static bool trans_VMULLD(DisasContext *ctx, arg_VX *a)
return true;
}
TRANS_FLAGS2(ALTIVEC_207, VMULESB, do_vx_helper, gen_helper_VMULESB)
TRANS_FLAGS2(ALTIVEC_207, VMULOSB, do_vx_helper, gen_helper_VMULOSB)
TRANS_FLAGS2(ALTIVEC_207, VMULEUB, do_vx_helper, gen_helper_VMULEUB)
TRANS_FLAGS2(ALTIVEC_207, VMULOUB, do_vx_helper, gen_helper_VMULOUB)
TRANS_FLAGS2(ALTIVEC_207, VMULESH, do_vx_helper, gen_helper_VMULESH)
TRANS_FLAGS2(ALTIVEC_207, VMULOSH, do_vx_helper, gen_helper_VMULOSH)
TRANS_FLAGS2(ALTIVEC_207, VMULEUH, do_vx_helper, gen_helper_VMULEUH)
TRANS_FLAGS2(ALTIVEC_207, VMULOUH, do_vx_helper, gen_helper_VMULOUH)
TRANS_FLAGS(ALTIVEC, VMULESB, do_vx_helper, gen_helper_VMULESB)
TRANS_FLAGS(ALTIVEC, VMULOSB, do_vx_helper, gen_helper_VMULOSB)
TRANS_FLAGS(ALTIVEC, VMULEUB, do_vx_helper, gen_helper_VMULEUB)
TRANS_FLAGS(ALTIVEC, VMULOUB, do_vx_helper, gen_helper_VMULOUB)
TRANS_FLAGS(ALTIVEC, VMULESH, do_vx_helper, gen_helper_VMULESH)
TRANS_FLAGS(ALTIVEC, VMULOSH, do_vx_helper, gen_helper_VMULOSH)
TRANS_FLAGS(ALTIVEC, VMULEUH, do_vx_helper, gen_helper_VMULEUH)
TRANS_FLAGS(ALTIVEC, VMULOUH, do_vx_helper, gen_helper_VMULOUH)
TRANS_FLAGS2(ALTIVEC_207, VMULESW, do_vx_helper, gen_helper_VMULESW)
TRANS_FLAGS2(ALTIVEC_207, VMULOSW, do_vx_helper, gen_helper_VMULOSW)
TRANS_FLAGS2(ALTIVEC_207, VMULEUW, do_vx_helper, gen_helper_VMULEUW)
@ -3162,19 +3156,16 @@ static void do_vx_vmulhw_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b, bool sign)
{
TCGv_i64 hh, lh, temp;
uint64_t c;
hh = tcg_temp_new_i64();
lh = tcg_temp_new_i64();
temp = tcg_temp_new_i64();
c = 0xFFFFFFFF;
if (sign) {
tcg_gen_ext32s_i64(lh, a);
tcg_gen_ext32s_i64(temp, b);
} else {
tcg_gen_andi_i64(lh, a, c);
tcg_gen_andi_i64(temp, b, c);
tcg_gen_ext32u_i64(lh, a);
tcg_gen_ext32u_i64(temp, b);
}
tcg_gen_mul_i64(lh, lh, temp);
@ -3188,8 +3179,7 @@ static void do_vx_vmulhw_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b, bool sign)
tcg_gen_mul_i64(hh, hh, temp);
tcg_gen_shri_i64(lh, lh, 32);
tcg_gen_andi_i64(hh, hh, c << 32);
tcg_gen_or_i64(t, hh, lh);
tcg_gen_deposit_i64(t, hh, lh, 0, 32);
tcg_temp_free_i64(hh);
tcg_temp_free_i64(lh);

View File

@ -1204,41 +1204,42 @@ static bool trans_XXPERMX(DisasContext *ctx, arg_8RR_XX4_uim3 *a)
return true;
}
typedef void (*xxgenpcv_genfn)(TCGv_ptr, TCGv_ptr);
static bool do_xxgenpcv(DisasContext *ctx, arg_X_imm5 *a,
const xxgenpcv_genfn fn[4])
{
TCGv_ptr xt, vrb;
REQUIRE_INSNS_FLAGS2(ctx, ISA310);
REQUIRE_VSX(ctx);
if (a->imm & ~0x3) {
gen_invalid(ctx);
return true;
}
xt = gen_vsr_ptr(a->xt);
vrb = gen_avr_ptr(a->vrb);
fn[a->imm](xt, vrb);
tcg_temp_free_ptr(xt);
tcg_temp_free_ptr(vrb);
return true;
}
#define XXGENPCV(NAME) \
static bool trans_##NAME(DisasContext *ctx, arg_X_imm5 *a) \
{ \
TCGv_ptr xt, vrb; \
\
REQUIRE_INSNS_FLAGS2(ctx, ISA310); \
REQUIRE_VSX(ctx); \
\
if (a->imm & ~0x3) { \
gen_invalid(ctx); \
return true; \
} \
\
xt = gen_vsr_ptr(a->xt); \
vrb = gen_avr_ptr(a->vrb); \
\
switch (a->imm) { \
case 0b00000: /* Big-Endian expansion */ \
glue(gen_helper_, glue(NAME, _be_exp))(xt, vrb); \
break; \
case 0b00001: /* Big-Endian compression */ \
glue(gen_helper_, glue(NAME, _be_comp))(xt, vrb); \
break; \
case 0b00010: /* Little-Endian expansion */ \
glue(gen_helper_, glue(NAME, _le_exp))(xt, vrb); \
break; \
case 0b00011: /* Little-Endian compression */ \
glue(gen_helper_, glue(NAME, _le_comp))(xt, vrb); \
break; \
} \
\
tcg_temp_free_ptr(xt); \
tcg_temp_free_ptr(vrb); \
\
return true; \
static const xxgenpcv_genfn fn[4] = { \
gen_helper_##NAME##_be_exp, \
gen_helper_##NAME##_be_comp, \
gen_helper_##NAME##_le_exp, \
gen_helper_##NAME##_le_comp, \
}; \
return do_xxgenpcv(ctx, a, fn); \
}
XXGENPCV(XXGENPCVBM)

View File

@ -64,9 +64,9 @@ fi
: ${cross_cc_ppc="powerpc-linux-gnu-gcc"}
: ${cross_cc_cflags_ppc="-m32"}
: ${cross_cc_ppc64="powerpc64-linux-gnu-gcc"}
: ${cross_cc_cflags_ppc64="-m64 -mbig"}
: ${cross_cc_cflags_ppc64="-m64 -mbig-endian"}
: ${cross_cc_ppc64le="$cross_cc_ppc64"}
: ${cross_cc_cflags_ppc64le="-m64 -mlittle"}
: ${cross_cc_cflags_ppc64le="-m64 -mlittle-endian"}
: ${cross_cc_riscv64="riscv64-linux-gnu-gcc"}
: ${cross_cc_s390x="s390x-linux-gnu-gcc"}
: ${cross_cc_sh4="sh4-linux-gnu-gcc"}

View File

@ -1,6 +1,7 @@
#include <assert.h>
#include <unistd.h>
#include <signal.h>
#include <stdint.h>
#define CRF_LT (1 << 3)
#define CRF_GT (1 << 2)
@ -8,24 +9,50 @@
#define CRF_SO (1 << 0)
#define UNDEF 0
#define BCDSUB(vra, vrb, ps) \
asm ("bcdsub. %1,%2,%3,%4;" \
"mfocrf %0,0b10;" \
: "=r" (cr), "=v" (vrt) \
: "v" (vra), "v" (vrb), "i" (ps) \
: );
#ifdef __has_builtin
#if !__has_builtin(__builtin_bcdsub)
#define NO_BUILTIN_BCDSUB
#endif
#endif
#define TEST(vra, vrb, ps, exp_res, exp_cr6) \
#ifdef NO_BUILTIN_BCDSUB
#define BCDSUB(T, A, B, PS) \
".long 4 << 26 | (" #T ") << 21 | (" #A ") << 16 | (" #B ") << 11" \
" | 1 << 10 | (" #PS ") << 9 | 65\n\t"
#else
#define BCDSUB(T, A, B, PS) "bcdsub. " #T ", " #A ", " #B ", " #PS "\n\t"
#endif
#define TEST(AH, AL, BH, BL, PS, TH, TL, CR6) \
do { \
__int128 vrt = 0; \
int cr = 0; \
BCDSUB(vra, vrb, ps); \
if (exp_res) \
assert(vrt == exp_res); \
assert((cr >> 4) == exp_cr6); \
uint64_t th, tl; \
/* \
* Use GPR pairs to load the VSR values and place the resulting VSR and\
* CR6 in th, tl, and cr. Note that we avoid newer instructions (e.g., \
* mtvsrdd/mfvsrld) so we can run this test on POWER8 machines. \
*/ \
asm ("mtvsrd 32, %3\n\t" \
"mtvsrd 33, %4\n\t" \
"xxmrghd 32, 32, 33\n\t" \
"mtvsrd 33, %5\n\t" \
"mtvsrd 34, %6\n\t" \
"xxmrghd 33, 33, 34\n\t" \
BCDSUB(0, 0, 1, PS) \
"mfocrf %0, 0b10\n\t" \
"mfvsrd %1, 32\n\t" \
"xxswapd 32, 32\n\t" \
"mfvsrd %2, 32\n\t" \
: "=r" (cr), "=r" (th), "=r" (tl) \
: "r" (AH), "r" (AL), "r" (BH), "r" (BL) \
: "v0", "v1", "v2"); \
if (TH != UNDEF || TL != UNDEF) { \
assert(tl == TL); \
assert(th == TH); \
} \
assert((cr >> 4) == CR6); \
} while (0)
/*
* Unbounded result is equal to zero:
* sign = (PS) ? 0b1111 : 0b1100
@ -33,13 +60,13 @@
*/
void test_bcdsub_eq(void)
{
__int128 a, b;
/* maximum positive BCD value */
a = b = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999c);
TEST(a, b, 0, 0xc, CRF_EQ);
TEST(a, b, 1, 0xf, CRF_EQ);
TEST(0x9999999999999999, 0x999999999999999c,
0x9999999999999999, 0x999999999999999c,
0, 0x0, 0xc, CRF_EQ);
TEST(0x9999999999999999, 0x999999999999999c,
0x9999999999999999, 0x999999999999999c,
1, 0x0, 0xf, CRF_EQ);
}
/*
@ -49,21 +76,16 @@ void test_bcdsub_eq(void)
*/
void test_bcdsub_gt(void)
{
__int128 a, b, c;
/* maximum positive and negative one BCD values */
TEST(0x9999999999999999, 0x999999999999999c, 0x0, 0x1d, 0,
0x0, 0xc, (CRF_GT | CRF_SO));
TEST(0x9999999999999999, 0x999999999999999c, 0x0, 0x1d, 1,
0x0, 0xf, (CRF_GT | CRF_SO));
/* maximum positive BCD value */
a = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999c);
/* negative one BCD value */
b = (__int128) 0x1d;
TEST(a, b, 0, 0xc, (CRF_GT | CRF_SO));
TEST(a, b, 1, 0xf, (CRF_GT | CRF_SO));
c = (((__int128) 0x9999999999999999) << 64 | 0x999999999999998c);
TEST(c, b, 0, a, CRF_GT);
TEST(c, b, 1, (a | 0x3), CRF_GT);
TEST(0x9999999999999999, 0x999999999999998c, 0x0, 0x1d, 0,
0x9999999999999999, 0x999999999999999c, CRF_GT);
TEST(0x9999999999999999, 0x999999999999998c, 0x0, 0x1d, 1,
0x9999999999999999, 0x999999999999999f, CRF_GT);
}
/*
@ -73,45 +95,27 @@ void test_bcdsub_gt(void)
*/
void test_bcdsub_lt(void)
{
__int128 a, b;
/* positive zero and positive one BCD values */
TEST(0x0, 0xc, 0x0, 0x1c, 0, 0x0, 0x1d, CRF_LT);
TEST(0x0, 0xc, 0x0, 0x1c, 1, 0x0, 0x1d, CRF_LT);
/* positive zero BCD value */
a = (__int128) 0xc;
/* positive one BCD value */
b = (__int128) 0x1c;
TEST(a, b, 0, 0x1d, CRF_LT);
TEST(a, b, 1, 0x1d, CRF_LT);
/* maximum negative BCD value */
a = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999d);
/* positive one BCD value */
b = (__int128) 0x1c;
TEST(a, b, 0, 0xd, (CRF_LT | CRF_SO));
TEST(a, b, 1, 0xd, (CRF_LT | CRF_SO));
/* maximum negative and positive one BCD values */
TEST(0x9999999999999999, 0x999999999999999d, 0x0, 0x1c, 0,
0x0, 0xd, (CRF_LT | CRF_SO));
TEST(0x9999999999999999, 0x999999999999999d, 0x0, 0x1c, 1,
0x0, 0xd, (CRF_LT | CRF_SO));
}
void test_bcdsub_invalid(void)
{
__int128 a, b;
TEST(0x0, 0x1c, 0x0, 0xf00, 0, UNDEF, UNDEF, CRF_SO);
TEST(0x0, 0x1c, 0x0, 0xf00, 1, UNDEF, UNDEF, CRF_SO);
/* positive one BCD value */
a = (__int128) 0x1c;
b = 0xf00;
TEST(0x0, 0xf00, 0x0, 0x1c, 0, UNDEF, UNDEF, CRF_SO);
TEST(0x0, 0xf00, 0x0, 0x1c, 1, UNDEF, UNDEF, CRF_SO);
TEST(a, b, 0, UNDEF, CRF_SO);
TEST(a, b, 1, UNDEF, CRF_SO);
TEST(b, a, 0, UNDEF, CRF_SO);
TEST(b, a, 1, UNDEF, CRF_SO);
a = 0xbad;
TEST(a, b, 0, UNDEF, CRF_SO);
TEST(a, b, 1, UNDEF, CRF_SO);
TEST(0x0, 0xbad, 0x0, 0xf00, 0, UNDEF, UNDEF, CRF_SO);
TEST(0x0, 0xbad, 0x0, 0xf00, 1, UNDEF, UNDEF, CRF_SO);
}
int main(void)

View File

@ -1,8 +1,12 @@
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <signal.h>
#include <sys/prctl.h>
#define MTFSF(FLM, FRB) asm volatile ("mtfsf %0, %1" :: "i" (FLM), "f" (FRB))
#define MFFS(FRT) asm("mffs %0" : "=f" (FRT))
#define FPSCR_VE 7 /* Floating-point invalid operation exception enable */
#define FPSCR_VXSOFT 10 /* Floating-point invalid operation exception (soft) */
#define FPSCR_FI 17 /* Floating-point fraction inexact */
@ -21,10 +25,7 @@ void sigfpe_handler(int sig, siginfo_t *si, void *ucontext)
int main(void)
{
union {
double d;
long long ll;
} fpscr;
uint64_t fpscr;
struct sigaction sa = {
.sa_sigaction = sigfpe_handler,
@ -40,10 +41,9 @@ int main(void)
prctl(PR_SET_FPEXC, PR_FP_EXC_PRECISE);
/* First test if the FI bit is being set correctly */
fpscr.ll = FP_FI;
__builtin_mtfsf(0b11111111, fpscr.d);
fpscr.d = __builtin_mffs();
assert((fpscr.ll & FP_FI) != 0);
MTFSF(0b11111111, FP_FI);
MFFS(fpscr);
assert((fpscr & FP_FI) != 0);
/* Then test if the deferred exception is being called correctly */
sigaction(SIGFPE, &sa, NULL);
@ -54,8 +54,7 @@ int main(void)
* But if a different exception is chosen si_code check should
* change accordingly.
*/
fpscr.ll = FP_VE | FP_VXSOFT;
__builtin_mtfsf(0b11111111, fpscr.d);
MTFSF(0b11111111, FP_VE | FP_VXSOFT);
return 1;
}

View File

@ -6,16 +6,16 @@
#define TEST(INSN, B_HI, B_LO, T_HI, T_LO) \
do { \
uint64_t th, tl, bh = B_HI, bl = B_LO; \
asm("mtvsrd 0, %2\n\t" \
"mtvsrd 1, %3\n\t" \
"xxmrghd 0, 0, 1\n\t" \
INSN " 0, 0\n\t" \
"mfvsrd %0, 0\n\t" \
"xxswapd 0, 0\n\t" \
"mfvsrd %1, 0\n\t" \
asm("mtvsrd 32, %2\n\t" \
"mtvsrd 33, %3\n\t" \
"xxmrghd 32, 32, 33\n\t" \
INSN " 32, 32\n\t" \
"mfvsrd %0, 32\n\t" \
"xxswapd 32, 32\n\t" \
"mfvsrd %1, 32\n\t" \
: "=r" (th), "=r" (tl) \
: "r" (bh), "r" (bl) \
: "vs0", "vs1"); \
: "v0", "v1"); \
printf(INSN "(0x%016" PRIx64 "%016" PRIx64 ") = 0x%016" PRIx64 \
"%016" PRIx64 "\n", bh, bl, th, tl); \
assert(th == T_HI && tl == T_LO); \