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
* <h> @HALF@ %|0|% %|1|%
* <r> @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
static const struct tvec_test round_test =
{ "round", round_regs, 0, test_round };
-/*----- IEEE format conversion --------------------------------------------*/
+/*----- IEEE format conversions -------------------------------------------*/
#define IEEE_FORMATS(_) \
_(mini, 1) \
#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) \
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"))
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);
}
}
-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[] = { \
#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
};