@@@ fltfmt mess
[mLib] / utils / fltfmt-convert.c
diff --git a/utils/fltfmt-convert.c b/utils/fltfmt-convert.c
new file mode 100644 (file)
index 0000000..6db742b
--- /dev/null
@@ -0,0 +1,210 @@
+/* -*-c-*-
+ *
+ * Floating-point format conversions
+ *
+ * (c) 2024 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the mLib utilities library.
+ *
+ * mLib is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * mLib is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with mLib.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include "bits.h"
+#include "fltfmt.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* Macro machinery. */
+
+#define CONVERSIONS(_)                                                 \
+  _(float, flt, f32)                                                   \
+  _(double, dbl, f64)
+
+#define CONV_DECLS_flt_f32 uint32 t
+#if (FLT_FORMAT&(FLTFMT_ORGMASK | FLTFMT_TYPEMASK)) == FLTFMT_IEEE_F32
+#  if (FLT_FORMAT&FLTFMT_ENDMASK) == FLTFMT_BE
+#    define CONV_LOAD_flt_f32 do { t = LOAD32_B(&x); } while (0)
+#    define CONV_STORE_flt_f32 do { STORE32_B(z_out, t); } while (0)
+#  elif (FLT_FORMAT&FLTFMT_ENDMASK) == FLTFMT_LE
+#    define CONV_LOAD_flt_f32 do { t = LOAD32_L(&x); } while (0)
+#    define CONV_STORE_flt_f32 do { STORE32_L(z_out, t); } while (0)
+#  else
+#    error "unimplemented byte order"
+#  endif
+#  ifdef FLTFMT__MUST_FROB_NANS
+#    define CONV_FROB_flt_f32 do { FLTFMT__FROB_NAN_F32(&t, rc); } while (0)
+#  else
+#    define CONV_FROB_flt_f32 do ; while (0)
+#  endif
+#else
+#  define CONV_LOAD_flt_f32 do {                                       \
+     struct floatbits u = FLOATBITS_INIT;                              \
+     rc |= fltfmt_decflt(&u, x, r);                                    \
+     rc |= fltfmt_encieee(&fltfmt_f32, &t, &u, r, FLTERR_ALLERRS);     \
+     fltfmt_freebits(&u);                                              \
+   } while (0)
+#  define CONV_STORE_flt_f32 do {                                      \
+     struct floatbits u = FLOATBITS_INIT;                              \
+     rc |= fltfmt_decieee(&fltfmt_f32, &u, &t);                                \
+     rc |= fltfmt_encflt(z_out, &u, r);                                        \
+     fltfmt_freebits(&u);                                              \
+   } while (0)
+#  define CONV_FROB_flt_f32 do ; while (0)
+#endif
+#define CONV_LOADB_flt_f32 do { t = LOAD32_B(p); } while (0)
+#define CONV_LOADL_flt_f32 do { t = LOAD32_L(p); } while (0)
+#define CONV_STOREB_flt_f32 do { STORE32_B(p, t); } while (0)
+#define CONV_STOREL_flt_f32 do { STORE32_L(p, t); } while (0)
+
+#define CONV_DECLS_dbl_f64 kludge64 t
+#if (DBL_FORMAT&(FLTFMT_ORGMASK | FLTFMT_TYPEMASK)) == FLTFMT_IEEE_F64
+#  if (DBL_FORMAT&FLTFMT_ENDMASK) == FLTFMT_BE
+#    define CONV_LOAD_dbl_f64 do { LOAD64_B_(t, &x); } while (0)
+#    define CONV_STORE_dbl_f64 do { STORE64_B_(z_out, t); } while (0)
+#  elif (DBL_FORMAT&FLTFMT_ENDMASK) == FLTFMT_LE
+#    define CONV_LOAD_dbl_f64 do { LOAD64_L_(t, &x); } while (0)
+#    define CONV_STORE_dbl_f64 do { STORE64_L_(z_out, t); } while (0)
+#  else
+#    error "unimplemented byte order"
+#  endif
+#  ifdef FLTFMT__MUST_FROB_NANS
+#    define CONV_FROB_dbl_f64 do {                                     \
+       uint32 u[2];                                                    \
+       u[0] = HI64(t); u[1] = LO64(t);                                 \
+       FLTFMT__FROB_NAN_F64(&u, rc);                                   \
+       SET64(t, u[0], u[1]);                                           \
+     } while (0)
+#  else
+#    define CONV_FROB_dbl_f64 do ; while (0)
+#  endif
+#else
+#  define CONV_LOAD_dbl_f64 do {                                       \
+     struct floatbits u = FLOATBITS_INIT; uint32 v[2];                 \
+     rc |= fltfmt_decdbl(&u, x, r);                                    \
+     rc |= fltfmt_encieee(&fltfmt_f64, v, &u, r, FLTERR_ALLERRS);      \
+     SET64(t, v[0], v[1]); fltfmt_freebits(&u);                                \
+   } while (0)
+#  define CONV_STORE_dbl_f64 do {                                      \
+     struct floatbits u = FLOATBITS_INIT; uint32 v[2];                 \
+     v[0] = HI64(t); v[1] = LO64(t);                                   \
+     rc |= fltfmt_decieee(&fltfmt_f64, &u, v);                         \
+     rc |= fltfmt_encdbl(z_out, &u, r);                                        \
+     fltfmt_freebits(&u);                                              \
+   } while (0)
+#  define CONV_FROB_dbl_f64 do ; while (0)
+#endif
+#define CONV_LOADB_dbl_f64 do { LOAD64_B_(t, p); } while (0)
+#define CONV_LOADL_dbl_f64 do { LOAD64_L_(t, p); } while (0)
+#define CONV_STOREB_dbl_f64 do { STORE64_B_(p, t); } while (0)
+#define CONV_STOREL_dbl_f64 do { STORE64_L_(p, t); } while (0)
+
+/* --- @fltfmt_CTYtoFTYE@ --- *
+ *
+ * Arguments:  @octet *p@ = output pointer
+ *             @float x@, @double x@ = value to convert
+ *             @unsigned r@ = rounding mode
+ *
+ * Returns:    Error flags (@FLTERR_...@).
+ *
+ * Use:                Encode a native C floating-point value in an external format.
+ *
+ *             The @CTY@ is an abbreviation for a C type: @flt@ for @float@,
+ *             or @dbl@ for @double@; @fty@ is an abbreviation for the
+ *             external format, @f32@ for IEEE Binary32, or @f64@ for IEEE
+ *             Binary64; and @E@ is @l@ for little-endian or @b@ for
+ *             big-endian byte order.  Not all combinations are currently
+ *             supported.
+ *
+ *             On platforms where the external format is used natively,
+ *             these functions are simple data copies.
+ */
+
+#define DEF_CONV(ctype, cty, fty)                                      \
+  unsigned fltfmt_##cty##to##fty##l(octet *p, ctype x, unsigned r)     \
+  {                                                                    \
+    unsigned rc = 0; CONV_DECLS_##cty##_##fty;                         \
+                                                                       \
+    CONV_LOAD_##cty##_##fty;                                           \
+    CONV_FROB_##cty##_##fty;                                           \
+    CONV_STOREL_##cty##_##fty;                                         \
+    return (rc);                                                       \
+  }                                                                    \
+                                                                       \
+  unsigned fltfmt_##cty##to##fty##b(octet *p, ctype x, unsigned r)     \
+  {                                                                    \
+    unsigned rc = 0; CONV_DECLS_##cty##_##fty;                         \
+                                                                       \
+    CONV_LOAD_##cty##_##fty;                                           \
+    CONV_FROB_##cty##_##fty;                                           \
+    CONV_STOREB_##cty##_##fty;                                         \
+    return (rc);                                                       \
+  }
+
+CONVERSIONS(DEF_CONV)
+
+#undef DEF_CONV
+
+/* --- @fltfmt_FTYEtoCTY@ --- *
+ *
+ * Arguments:  @float *z_out@, @double *z_out@ = storage for output
+ *             @const octet *p@ = input pointer
+ *             @unsigned r@ = rounding mode
+ *
+ * Returns:    Error flags (@FLTERR_...@).
+ *
+ * Use:                Decodes a floating point value in an external format into a
+ *             native value.
+ *
+ *             The naming conventions are the same as for @fltfmt_dbltof64b@
+ *             above.
+ *
+ *             On platforms where the external format is used natively,
+ *             these functions are simple data copies.
+ */
+
+#define DEF_CONV(ctype, cty, fty)                                      \
+  unsigned fltfmt_##fty##lto##cty(ctype *z_out, const octet *p, unsigned r) \
+  {                                                                    \
+    unsigned rc = 0; CONV_DECLS_##cty##_##fty;                         \
+                                                                       \
+    CONV_LOADL_##cty##_##fty;                                          \
+    CONV_FROB_##cty##_##fty;                                           \
+    CONV_STORE_##cty##_##fty;                                          \
+    return (rc);                                                       \
+  }                                                                    \
+                                                                       \
+  unsigned fltfmt_##fty##bto##cty(ctype *z_out, const octet *p, unsigned r) \
+  {                                                                    \
+    unsigned rc = 0; CONV_DECLS_##cty##_##fty;                         \
+                                                                       \
+    CONV_LOADB_##cty##_##fty;                                          \
+    CONV_FROB_##cty##_##fty;                                           \
+    CONV_STORE_##cty##_##fty;                                          \
+    return (rc);                                                       \
+  }
+
+CONVERSIONS(DEF_CONV)
+
+#undef DEF_CONV
+
+/*----- That's all, folks -------------------------------------------------*/