X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/289651a7df7bc48724137cd0faaf8535fb54e73b..d04c0e00da3a27693bbf9cc4f2d5c88e56d80f20:/utils/t/fltfmt-test.c diff --git a/utils/t/fltfmt-test.c b/utils/t/fltfmt-test.c index 5b60607..9ed7c68 100644 --- a/utils/t/fltfmt-test.c +++ b/utils/t/fltfmt-test.c @@ -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 };