X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/b1a20beee623c83315c3ce21abc7bcce103c6efb..98ff9295493ed2b990f30768e11b18b6bc65eaa4:/utils/t/fltfmt-test.c diff --git a/utils/t/fltfmt-test.c b/utils/t/fltfmt-test.c index 76e1d41..9ed7c68 100644 --- a/utils/t/fltfmt-test.c +++ b/utils/t/fltfmt-test.c @@ -79,18 +79,18 @@ static const struct tvec_flaginfo flterrmask_flaginfo = static const struct tvec_flag fltrnd_flags[] = { /* Standard rounding modes. */ - { "zero", 0xffff, FLTRND_ZERO }, - { "projinf", 0xffff, FLTRND_PROJINF }, - { "posinf", 0xffff, FLTRND_POSINF }, - { "neginf", 0xffff, FLTRND_NEGINF }, - { "odd", 0xffff, FLTRND_ODD }, - { "even", 0xffff, FLTRND_EVEN }, - { "nearest-even", 0xffff, FLTRND_NEAREVEN }, - { "nearest-odd", 0xffff, FLTRND_NEARODD }, - { "nearest-zero", 0xffff, FLTRND_NEARZERO }, - { "nearest-projinf", 0xffff, FLTRND_NEARINF }, - { "nearest-neginf", 0xffff, FLTRND_NEARNEG }, - { "nearest-posinf", 0xffff, FLTRND_NEARPOS }, + { "zero", 0xffffu, FLTRND_ZERO }, + { "projinf", 0xffffu, FLTRND_PROJINF }, + { "posinf", 0xffffu, FLTRND_POSINF }, + { "neginf", 0xffffu, FLTRND_NEGINF }, + { "odd", 0xffffu, FLTRND_ODD }, + { "even", 0xffffu, FLTRND_EVEN }, + { "nearest-even", 0xffffu, FLTRND_NEAREVEN }, + { "nearest-odd", 0xffffu, FLTRND_NEARODD }, + { "nearest-zero", 0xffffu, FLTRND_NEARZERO }, + { "nearest-projinf", 0xffffu, FLTRND_NEARINF }, + { "nearest-neginf", 0xffffu, FLTRND_NEARNEG }, + { "nearest-posinf", 0xffffu, FLTRND_NEARPOS }, /* Rounding mode bits: rounds away from zero in the listed conditions. * The notation corresponds to rounding predicates as follows. The syntax @@ -102,22 +102,22 @@ static const struct tvec_flag fltrnd_flags[] = { * @HALF@ %|0|% %|1|% * @LOW@ %|0|% %|1|% */ - { "+0.00", 0x0001, 0x0001 }, - { "+0.01", 0x0002, 0x0002 }, - { "+0.10", 0x0004, 0x0004 }, - { "+0.11", 0x0008, 0x0008 }, - { "+1.00", 0x0010, 0x0010 }, - { "+1.01", 0x0020, 0x0020 }, - { "+1.10", 0x0040, 0x0040 }, - { "+1.11", 0x0080, 0x0080 }, - { "-0.00", 0x0100, 0x0100 }, - { "-0.01", 0x0200, 0x0200 }, - { "-0.10", 0x0400, 0x0400 }, - { "-0.11", 0x0800, 0x0800 }, - { "-1.00", 0x1000, 0x1000 }, - { "-1.01", 0x2000, 0x2000 }, - { "-1.10", 0x4000, 0x4000 }, - { "-1.11", 0x8000, 0x8000 }, + { "+0.00", 0x0001u, 0x0001u }, + { "+0.01", 0x0002u, 0x0002u }, + { "+0.10", 0x0004u, 0x0004u }, + { "+0.11", 0x0008u, 0x0008u }, + { "+1.00", 0x0010u, 0x0010u }, + { "+1.01", 0x0020u, 0x0020u }, + { "+1.10", 0x0040u, 0x0040u }, + { "+1.11", 0x0080u, 0x0080u }, + { "-0.00", 0x0100u, 0x0100u }, + { "-0.01", 0x0200u, 0x0200u }, + { "-0.10", 0x0400u, 0x0400u }, + { "-0.11", 0x0800u, 0x0800u }, + { "-1.00", 0x1000u, 0x1000u }, + { "-1.01", 0x2000u, 0x2000u }, + { "-1.10", 0x4000u, 0x4000u }, + { "-1.11", 0x8000u, 0x8000u }, /* Phew! */ TVEC_ENDFLAGS @@ -208,7 +208,7 @@ static void test_round(const struct tvec_reg *in, struct tvec_reg *out, static const struct tvec_test round_test = { "round", round_regs, 0, test_round }; -/*----- IEEE format conversion --------------------------------------------*/ +/*----- IEEE format conversions -------------------------------------------*/ #define IEEE_FORMATS(_) \ _(mini, 1) \ @@ -348,7 +348,7 @@ IEEE_FORMATS(DEF_TEST) #define DEF_IEEE_TEST(ty, sz) &enc##ty##_test, &dec##ty##_test, #define IEEE_TESTS IEEE_FORMATS(DEF_IEEE_TEST) -/*----- Native format conversion ------------------------------------------*/ +/*----- Native format conversions -----------------------------------------*/ #define NATIVE_FORMATS(_) \ _(flt, float, FLT) \ @@ -393,64 +393,64 @@ static const struct tvec_flag assume_flags[] = { static const struct tvec_flaginfo assume_flaginfo = { "assume", assume_flags, &tvrange_uint }; -struct nativeenv { struct tvec_env _env; unsigned ntv; }; -struct nativectx { unsigned af, want; }; +struct assumeenv { struct tvec_env _env; unsigned ntv; }; +struct assumectx { unsigned af, want; }; -static void setup_native(struct tvec_state *tv, const struct tvec_env *env, +static void setup_assume(struct tvec_state *tv, const struct tvec_env *env, void *pctx, void *ctx) { - const struct nativeenv *nenv = (const struct nativeenv *)env; - const struct ntvinfo *info = &ntvinfo[nenv->ntv]; - struct nativectx *nctx = ctx; + const struct assumeenv *aenv = (const struct assumeenv *)env; + const struct ntvinfo *info = &ntvinfo[aenv->ntv]; + struct assumectx *actx = ctx; double prec; switch (info->fmt&(FLTFMT_ORGMASK | FLTFMT_TYPEMASK)) { case FLTFMT_IEEE_F32: - nctx->af = AF_NEGZ | AF_INF | AF_IEEE | AF_PREC24; + actx->af = AF_NEGZ | AF_INF | AF_IEEE | AF_PREC24; break; case FLTFMT_IEEE_F64: - nctx->af = AF_NEGZ | AF_INF | AF_IEEE | AF_PREC24 | AF_PREC53; + actx->af = AF_NEGZ | AF_INF | AF_IEEE | AF_PREC24 | AF_PREC53; break; case FLTFMT_IEEE_F128: - nctx->af = AF_NEGZ | AF_INF | AF_IEEE | + actx->af = AF_NEGZ | AF_INF | AF_IEEE | AF_PREC24 | AF_PREC53 | AF_PREC64 | AF_PREC113; break; case FLTFMT_INTEL_F80: - nctx->af = AF_NEGZ | AF_INF | AF_IEEE | + actx->af = AF_NEGZ | AF_INF | AF_IEEE | AF_PREC24 | AF_PREC53 | AF_PREC64; break; default: - nctx->af = 0; - if (NEGP(-0.0)) nctx->af |= AF_NEGZ; + actx->af = 0; + if (NEGP(-0.0)) actx->af |= AF_NEGZ; #ifdef INF - nctx->af |= AF_INF; + actx->af |= AF_INF; #endif #ifdef NAN - nctx->af |= AF_STDCNAN; + actx->af |= AF_STDCNAN; #endif prec = log(FLT_RADIX)/log(2.0)*info->mant_dig; - if (prec >= 24) nctx->af |= AF_PREC24; - if (prec >= 53) nctx->af |= AF_PREC53; - if (prec >= 64) nctx->af |= AF_PREC64; - if (prec >= 113) nctx->af |= AF_PREC113; + if (prec >= 24) actx->af |= AF_PREC24; + if (prec >= 53) actx->af |= AF_PREC53; + if (prec >= 64) actx->af |= AF_PREC64; + if (prec >= 113) actx->af |= AF_PREC113; break; } - nctx->want = 0; + actx->want = 0; } -static int setvar_native(struct tvec_state *tv, const char *var, +static int setvar_assume(struct tvec_state *tv, const char *var, const union tvec_regval *rv, void *ctx) { - struct nativectx *nctx = ctx; + struct assumectx *actx = ctx; - if (STRCMP(var, ==, "@assume")) nctx->want = rv->u; + if (STRCMP(var, ==, "@assume")) actx->want = rv->u; else return (tvec_unkregerr(tv, var)); return (0); } static const struct tvec_vardef assume_vardef = - { sizeof(struct tvec_reg), setvar_native, + { sizeof(struct tvec_reg), setvar_assume, { "@assume", &tvty_flags, 0, 0, { &assume_flaginfo } }}; -static const struct tvec_vardef *findvar_native +static const struct tvec_vardef *findvar_assume (struct tvec_state *tv, const char *name, void **ctx_out, void *ctx) { if (STRCMP(name, ==, "@assume")) @@ -459,11 +459,11 @@ static const struct tvec_vardef *findvar_native return (0); } -static void before_native(struct tvec_state *tv, void *ctx) +static void before_assume(struct tvec_state *tv, void *ctx) { - struct nativectx *nctx = ctx; + struct assumectx *actx = ctx; - if (nctx->want&~nctx->af) + if ((tv->f&TVSF_ACTIVE) && (actx->want&~actx->af)) tvec_skip(tv, "unsatisfied assumption"); else { DEFAULT_REG(RROUND, rv->u = FLTRND_NEAREVEN); @@ -471,18 +471,18 @@ static void before_native(struct tvec_state *tv, void *ctx) } } -static void after_native(struct tvec_state *tv, void *ctx) +static void after_assume(struct tvec_state *tv, void *ctx) { - struct nativectx *nctx = ctx; + struct assumectx *actx = ctx; - nctx->want = 0; + actx->want = 0; } #define DEF_TEST(ty, cty, TY) \ \ - static struct nativeenv ty##_env = \ - { { sizeof(struct nativectx), \ - setup_native, findvar_native, before_native, 0, after_native, 0 }, \ + static struct assumeenv ty##_env = \ + { { sizeof(struct assumectx), \ + setup_assume, findvar_assume, before_assume, 0, after_assume, 0 }, \ NTV_##TY }; \ \ static const struct tvec_regdef enc##ty##_regs[] = { \ @@ -538,12 +538,93 @@ NATIVE_FORMATS(DEF_TEST) #define DEF_NATIVE_TEST(ty, cty, TY) &enc##ty##_test, &dec##ty##_test, #define NATIVE_TESTS NATIVE_FORMATS(DEF_NATIVE_TEST) +/*----- Direct conversions ------------------------------------------------*/ + +#define DIRECT_CONVERSIONS(_) \ + _(flt, float, f32) \ + _(dbl, double, f64) + +#define DEF_TEST1(ty, cty, fty, e) \ + static void test_##ty##to##fty##e(const struct tvec_reg *in, \ + struct tvec_reg *out, \ + void *ctx) \ + { \ + tvec_allocbytes(&out[RZ_OUT].v, OUTSZ_##fty); \ + out[RERR_OUT].v.u = fltfmt_##ty##to##fty##e(out[RZ_OUT].v.bytes.p, \ + in[RX].v.f, \ + in[RROUND].v.u); \ + } \ + \ + static const struct tvec_test ty##to##fty##e##_test = \ + { #ty "to" #fty #e, ty##to##fty##_regs, &ty##_env._env, \ + test_##ty##to##fty##e }; + +#define DEF_TEST(ty, cty, fty) \ + static const struct tvec_regdef ty##to##fty##_regs[] = { \ + { "round", &tvty_flags, RROUND, TVRF_OPT, { &fltrnd_flaginfo } }, \ + { "x", &tvty_float, RX, 0, { &tvflt_##cty } }, \ + { "z", &tvty_bytes, RZ_OUT, 0, { &fty##_range } }, \ + { "err", &tvty_flags, RERR_OUT, TVRF_OPT, { &flterr_flaginfo } }, \ + TVEC_ENDREGS \ + }; \ + \ + DEF_TEST1(ty, cty, fty, l) \ + DEF_TEST1(ty, cty, fty, b) + +DIRECT_CONVERSIONS(DEF_TEST) + +#undef DEF_TEST1 +#undef DEF_TEST + +#define DEF_TEST1(ty, cty, fty, e) \ + static void test_##fty##e##to##ty(const struct tvec_reg *in, \ + struct tvec_reg *out, \ + void *ctx) \ + { \ + cty z; \ + \ + out[RERR_OUT].v.u = fltfmt_##fty##e##to##ty(&z, in[RX].v.bytes.p, \ + in[RROUND].v.u); \ + out[RZ_OUT].v.f = z; \ + } \ + \ + static const struct tvec_test fty##e##to##ty##_test = \ + { #fty #e "to" #ty, fty##to##ty##_regs, &ty##_env._env, \ + test_##fty##e##to##ty }; + +#define DEF_TEST(ty, cty, fty) \ + static const struct tvec_regdef fty##to##ty##_regs[] = { \ + { "round", &tvty_flags, RROUND, TVRF_OPT, { &fltrnd_flaginfo } }, \ + { "x", &tvty_bytes, RX, 0, { &fty##_range } }, \ + { "z", &tvty_float, RZ_OUT, 0, { &tvflt_##cty } }, \ + { "err", &tvty_flags, RERR_OUT, TVRF_OPT, { &flterr_flaginfo } }, \ + TVEC_ENDREGS \ + }; \ + \ + DEF_TEST1(ty, cty, fty, l) \ + DEF_TEST1(ty, cty, fty, b) + +DIRECT_CONVERSIONS(DEF_TEST) + +#undef DEF_TEST1 +#undef DEF_TEST + +#define DEF_DIRECT_CTOF_TESTS(ty, cty, fty) \ + &ty##to##fty##l_test, &ty##to##fty##b_test, +#define DEF_DIRECT_FTOC_TESTS(ty, cty, fty) \ + &fty##l##to##ty##_test, &fty##b##to##ty##_test, +#define DEF_DIRECT_TESTS(ty, cty, fty) \ + DEF_DIRECT_CTOF_TESTS(ty, cty, fty) \ + DEF_DIRECT_FTOC_TESTS(ty, cty, fty) +#define DIRECT_TESTS DIRECT_CONVERSIONS(DEF_DIRECT_TESTS) + /*----- Main code ---------------------------------------------------------*/ static const struct tvec_test *const tests[] = { &round_test, NATIVE_TESTS IEEE_TESTS + DIRECT_TESTS 0 };