[nasm:nasm-2.15.xx] fp: support bfloat16 constants

nasm-bot for H. Peter Anvin hpa at zytor.com
Thu Jul 16 23:15:04 PDT 2020


Commit-ID:  d081f0db5d491ee473fdb97b109dd9810b68d9b7
Gitweb:     http://repo.or.cz/w/nasm.git?a=commitdiff;h=d081f0db5d491ee473fdb97b109dd9810b68d9b7
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Thu, 16 Jul 2020 23:11:03 -0700
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Thu, 16 Jul 2020 23:11:03 -0700

fp: support bfloat16 constants

Support generating bfloat16 constants. This is a bit awkward, as "DW"
already generates IEEE half precision constants; therefore there is no
longer a single floating-point format for each size. This requires
some replumbing.

Fortunately bfloat16 fits in 64 bits, so support generating them with
a macro that uses __?bfloat16?__() to convert to integers first before
passing them to DW.

Signed-off-by: H. Peter Anvin <hpa at zytor.com>


---
 asm/eval.c      | 25 ++++++++-----------
 asm/floats.c    | 74 +++++++++++++++++++++++++++++++--------------------------
 asm/floats.h    | 17 +++++++++++--
 asm/parser.c    |  7 +++---
 asm/tokens.dat  |  3 +++
 doc/changes.src |  3 +++
 doc/nasmdoc.src | 20 +++++++++++++---
 include/nasm.h  |  5 +++-
 macros/fp.mac   | 10 +++++++-
 test/float.asm  | 36 +++++++++++++++++++++++++++-
 10 files changed, 140 insertions(+), 60 deletions(-)

diff --git a/asm/eval.c b/asm/eval.c
index cd3c526d..5d6ee1e7 100644
--- a/asm/eval.c
+++ b/asm/eval.c
@@ -694,21 +694,13 @@ static expr *expr5(void)
 static expr *eval_floatize(enum floatize type)
 {
     uint8_t result[16], *p;     /* Up to 128 bits */
-    static const struct {
-        int bytes, start, len;
-    } formats[] = {
-        {  1, 0, 1 },           /* FLOAT_8 */
-        {  2, 0, 2 },           /* FLOAT_16 */
-        {  4, 0, 4 },           /* FLOAT_32 */
-        {  8, 0, 8 },           /* FLOAT_64 */
-        { 10, 0, 8 },           /* FLOAT_80M */
-        { 10, 8, 2 },           /* FLOAT_80E */
-        { 16, 0, 8 },           /* FLOAT_128L */
-        { 16, 8, 8 },           /* FLOAT_128H */
-    };
     int sign = 1;
     int64_t val;
+    size_t len;
     int i;
+    const struct ieee_format *fmt;
+
+    fmt = &fp_formats[type];
 
     scan();
     if (tt != '(') {
@@ -724,7 +716,7 @@ static expr *eval_floatize(enum floatize type)
         nasm_nonfatal("expecting floating-point number");
         return NULL;
     }
-    if (!float_const(tokval->t_charptr, sign, result, formats[type].bytes))
+    if (!float_const(tokval->t_charptr, sign, result, type))
         return NULL;
     scan();
     if (tt != ')') {
@@ -732,9 +724,12 @@ static expr *eval_floatize(enum floatize type)
         return NULL;
     }
 
-    p = result+formats[type].start+formats[type].len;
+    len = fmt->bytes - fmt->offset;
+    if (len > 8)
+        len = 8;                /* Max 64 bits */
+    p = result + len;
     val = 0;
-    for (i = formats[type].len; i; i--) {
+    for (i = len; i; i--) {
         p--;
         val = (val << 8) + *p;
     }
diff --git a/asm/floats.c b/asm/floats.c
index adc6afbf..27180bdc 100644
--- a/asm/floats.c
+++ b/asm/floats.c
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
  *
- *   Copyright 1996-2018 The NASM Authors - All Rights Reserved
+ *   Copyright 1996-2020 The NASM Authors - All Rights Reserved
  *   See the file AUTHORS included with the NASM distribution for
  *   the specific copyright holders.
  *
@@ -629,13 +629,6 @@ static void ieee_shr(fp_limb *mant, int i)
    - the sign bit plus exponent fit in 16 bits.
    - the exponent bias is 2^(n-1)-1 for an n-bit exponent */
 
-struct ieee_format {
-    int bytes;
-    int mantissa;               /* Fractional bits in the mantissa */
-    int explicit;               /* Explicit integer */
-    int exponent;               /* Bits in the exponent */
-};
-
 /*
  * The 16- and 128-bit formats are expected to be in IEEE 754r.
  * AMD SSE5 uses the 16-bit format.
@@ -646,13 +639,31 @@ struct ieee_format {
  *
  * The 8-bit format appears to be the consensus 8-bit floating-point
  * format.  It is apparently used in graphics applications.
+ *
+ * The b16 format is a 16-bit format with smaller mantissa and larger
+ * exponent field.  It is effectively a truncated version of the standard
+ * IEEE 32-bit (single) format, but is explicitly supported here in
+ * order to support proper rounding.
+ *
+ * This array must correspond to enum floatize in include/nasm.h.
+ * Note that there are some formats which have more than one enum;
+ * both need to be listed here with the appropriate offset into the
+ * floating-point byte array (use for the floatize operators.)
+ *
+ * FLOAT_ERR is a value that both represents "invalid format" and the
+ * size of this array.
  */
-static const struct ieee_format ieee_8   = {  1,   3, 0,  4 };
-static const struct ieee_format ieee_16  = {  2,  10, 0,  5 };
-static const struct ieee_format ieee_32  = {  4,  23, 0,  8 };
-static const struct ieee_format ieee_64  = {  8,  52, 0, 11 };
-static const struct ieee_format ieee_80  = { 10,  63, 1, 15 };
-static const struct ieee_format ieee_128 = { 16, 112, 0, 15 };
+const struct ieee_format fp_formats[FLOAT_ERR] = {
+    {  1,   3, 0,  4, 0 },         /* FLOAT_8 */
+    {  2,  10, 0,  5, 0 },         /* FLOAT_16 */
+    {  2,   7, 0,  8, 0 },         /* FLOAT_B16 */
+    {  4,  23, 0,  8, 0 },         /* FLOAT_32 */
+    {  8,  52, 0, 11, 0 },         /* FLOAT_64 */
+    { 10,  63, 1, 15, 0 },         /* FLOAT_80M */
+    { 10,  63, 1, 15, 8 },         /* FLOAT_80E */
+    { 16, 112, 0, 15, 0 },         /* FLOAT_128L */
+    { 16, 112, 0, 15, 8 }          /* FLOAT_128H */
+};
 
 /* Types of values we can generate */
 enum floats {
@@ -672,7 +683,7 @@ static int to_packed_bcd(const char *str, const char *p,
     char c;
     int tv = -1;
 
-    if (fmt != &ieee_80) {
+    if (fmt->bytes != 10) {
         nasm_nonfatal("packed BCD requires an 80-bit format");
         return 0;
     }
@@ -711,9 +722,9 @@ static int to_packed_bcd(const char *str, const char *p,
     return 1;                   /* success */
 }
 
-static int to_float(const char *str, int s, uint8_t *result,
-                    const struct ieee_format *fmt)
+int float_const(const char *str, int s, uint8_t *result, enum floatize ffmt)
 {
+    const struct ieee_format *fmt = &fp_formats[ffmt];
     fp_limb mant[MANT_LIMBS];
     int32_t exponent = 0;
     const int32_t expmax = 1 << (fmt->exponent - 1);
@@ -902,25 +913,20 @@ static int to_float(const char *str, int s, uint8_t *result,
     return 1;                   /* success */
 }
 
-int float_const(const char *number, int sign, uint8_t *result, int bytes)
+/*
+ * Get the default floating point format for this specific field size.
+ * Used for the Dx pseudoops.
+ */
+enum floatize float_deffmt(int bytes)
 {
-    switch (bytes) {
-    case 1:
-        return to_float(number, sign, result, &ieee_8);
-    case 2:
-        return to_float(number, sign, result, &ieee_16);
-    case 4:
-        return to_float(number, sign, result, &ieee_32);
-    case 8:
-        return to_float(number, sign, result, &ieee_64);
-    case 10:
-        return to_float(number, sign, result, &ieee_80);
-    case 16:
-        return to_float(number, sign, result, &ieee_128);
-    default:
-        nasm_panic("strange value %d passed to float_const", bytes);
-        return 0;
+    enum floatize type;
+
+    for (type = 0; type < FLOAT_ERR; type++) {
+        if (fp_formats[type].bytes == bytes)
+            break;
     }
+
+    return type;                /* FLOAT_ERR if invalid */
 }
 
 /* Set floating-point options */
diff --git a/asm/floats.h b/asm/floats.h
index 4f80acac..c4635136 100644
--- a/asm/floats.h
+++ b/asm/floats.h
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
  *   
- *   Copyright 1996-2009 The NASM Authors - All Rights Reserved
+ *   Copyright 1996-2020 The NASM Authors - All Rights Reserved
  *   See the file AUTHORS included with the NASM distribution for
  *   the specific copyright holders.
  *
@@ -48,7 +48,20 @@ enum float_round {
     FLOAT_RC_UP
 };
 
-int float_const(const char *string, int sign, uint8_t *result, int bytes);
+/* Note: enum floatize and FLOAT_ERR are defined in nasm.h */
+
+/* Floating-point format description */
+struct ieee_format {
+    int bytes;                  /* Total bytes */
+    int mantissa;               /* Fractional bits in the mantissa */
+    int explicit;               /* Explicit integer */
+    int exponent;               /* Bits in the exponent */
+    int offset;                 /* Offset into byte array for floatize op */
+};
+extern const struct ieee_format fp_formats[FLOAT_ERR];
+
+int float_const(const char *str, int s, uint8_t *result, enum floatize ffmt);
+enum floatize float_deffmt(int bytes);
 int float_option(const char *option);
 
 #endif /* NASM_FLOATS_H */
diff --git a/asm/parser.c b/asm/parser.c
index 47b46ecd..dbd2240c 100644
--- a/asm/parser.c
+++ b/asm/parser.c
@@ -531,10 +531,12 @@ static int parse_eops(extop **result, bool critical, int elem)
                 goto is_float;
             }
         } else if (i == TOKEN_FLOAT) {
+            enum floatize fmt;
         is_float:
             eop->type = EOT_DB_FLOAT;
 
-            if (eop->elem > 16) {
+            fmt = float_deffmt(eop->elem);
+            if (fmt == FLOAT_ERR) {
                 nasm_nonfatal("no %d-bit floating-point format supported",
                               eop->elem << 3);
                 eop->val.string.len = 0;
@@ -552,8 +554,7 @@ static int parse_eops(extop **result, bool critical, int elem)
                 eop = nasm_realloc(eop, sizeof(extop) + eop->val.string.len);
                 eop->val.string.data = (char *)eop + sizeof(extop);
                 if (!float_const(tokval.t_charptr, sign,
-                                 (uint8_t *)eop->val.string.data,
-                                 eop->val.string.len))
+                                 (uint8_t *)eop->val.string.data, fmt))
                     eop->val.string.len = 0;
             }
             if (!eop->val.string.len)
diff --git a/asm/tokens.dat b/asm/tokens.dat
index ab37dcc1..356b39a2 100644
--- a/asm/tokens.dat
+++ b/asm/tokens.dat
@@ -113,6 +113,9 @@ __?float80e?__
 __?float128l?__
 __?float128h?__
 
+% TOKEN_FLOATIZE, 0, 0, FLOAT_B{__?bfloat*?__}
+__?bfloat16?__
+
 % TOKEN_STRFUNC, 0, 0, STRFUNC_{__?*?__}
 __?utf16?__
 __?utf16le?__
diff --git a/doc/changes.src b/doc/changes.src
index cf95224a..c1459231 100644
--- a/doc/changes.src
+++ b/doc/changes.src
@@ -12,6 +12,9 @@ since 2007.
 \b Add instructions from the Intel Instruction Set Extensions and
 Future Features Programming Reference, June 2020.
 
+\b Support for \c{bfloat16} floating-point constants. See \k{fltconst}
+and \k{pkg_fp}.
+
 \b Properly display warnings in preprocess-only mode.
 
 \b Fix copy-and-paste of examples from the PDF documentation.
diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src
index cfa92fd1..e3d503c5 100644
--- a/doc/nasmdoc.src
+++ b/doc/nasmdoc.src
@@ -1692,9 +1692,9 @@ context.
 \i{Floating-point} constants are acceptable only as arguments to
 \i\c{DB}, \i\c{DW}, \i\c{DD}, \i\c{DQ}, \i\c{DT}, and \i\c{DO}, or as
 arguments to the special operators \i\c{__?float8?__},
-\i\c{__?float16?__}, \i\c{__?float32?__}, \i\c{__?float64?__},
-\i\c{__?float80m?__}, \i\c{__?float80e?__}, \i\c{__?float128l?__}, and
-\i\c{__?float128h?__}.
+\i\c{__?float16?__}, \i\c{__?bfloat16?__}, \i\c{__?float32?__},
+\i\c{__?float64?__}, \i\c{__?float80m?__}, \i\c{__?float80e?__},
+\i\c{__?float128l?__}, and \i\c{__?float128h?__}. See also \k{pkg_fp}.
 
 Floating-point constants are expressed in the traditional form:
 digits, then a period, then optionally more digits, then optionally an
@@ -1733,6 +1733,13 @@ appears to be the most frequently used 8-bit floating-point format,
 although it is not covered by any formal standard.  This is sometimes
 called a "\i{minifloat}."
 
+The \i\c{bfloat16} format is effectively a compressed version of the
+32-bit single precision format, with a reduced mantissa. It is
+effectively the same as truncating the 32-bit format to the upper 16
+bits, except for rounding. There is no \c{D}\e{x} directive that
+corresponds to \c{bfloat16} as it obviously has the same size as the
+IEEE standard 16-bit half precision format, see however \k{pkg_fp}.
+
 The special operators are used to produce floating-point numbers in
 other contexts.  They produce the binary representation of a specific
 floating-point number as an integer, and can use anywhere integer
@@ -4633,6 +4640,7 @@ This packages contains the following floating-point convenience macros:
 \c
 \c %define float8(x)       __?float8?__(x)
 \c %define float16(x)      __?float16?__(x)
+\c %define bfloat16(x)     __?bfloat16?__(x)
 \c %define float32(x)      __?float32?__(x)
 \c %define float64(x)      __?float64?__(x)
 \c %define float80m(x)     __?float80m?__(x)
@@ -4640,6 +4648,12 @@ This packages contains the following floating-point convenience macros:
 \c %define float128l(x)    __?float128l?__(x)
 \c %define float128h(x)    __?float128h?__(x)
 
+It also defines the a multi-line macro \i\c{bf16} that can be used
+in a similar way to the \c{D}\e{x} directives for the other
+floating-point numbers:
+
+\c      bf16 -3.1415, NaN, 2000.0, +Inf
+
 
 \H{pkg_ifunc} \i\c{ifunc}: \i{Integer functions}
 
diff --git a/include/nasm.h b/include/nasm.h
index 6cffaf5d..950ac45b 100644
--- a/include/nasm.h
+++ b/include/nasm.h
@@ -196,15 +196,18 @@ enum token_type { /* token types, other than chars */
     TOKEN_OPMASK        /* translated token for opmask registers */
 };
 
+/* Must match the fp_formats[] array in asm/floats.c */
 enum floatize {
     FLOAT_8,
     FLOAT_16,
+    FLOAT_B16,
     FLOAT_32,
     FLOAT_64,
     FLOAT_80M,
     FLOAT_80E,
     FLOAT_128L,
-    FLOAT_128H
+    FLOAT_128H,
+    FLOAT_ERR                   /* Invalid format, MUST BE LAST */
 };
 
 /* Must match the list in string_transform(), in strfunc.c */
diff --git a/macros/fp.mac b/macros/fp.mac
index eb297014..3a094a5c 100644
--- a/macros/fp.mac
+++ b/macros/fp.mac
@@ -1,6 +1,6 @@
 ;; --------------------------------------------------------------------------
 ;;   
-;;   Copyright 2010 The NASM Authors - All Rights Reserved
+;;   Copyright 2010-2020 The NASM Authors - All Rights Reserved
 ;;   See the file AUTHORS included with the NASM distribution for
 ;;   the specific copyright holders.
 ;;
@@ -46,9 +46,17 @@ USE: fp
 
 %define float8(x)	__?float8?__(x)
 %define float16(x)	__?float16?__(x)
+%define bfloat16(x)     __?bfloat16?__(x)
 %define float32(x)	__?float32?__(x)
 %define float64(x)	__?float64?__(x)
 %define float80m(x)	__?float80m?__(x)
 %define float80e(x)	__?float80e?__(x)
 %define float128l(x)	__?float128l?__(x)
 %define float128h(x)	__?float128h?__(x)
+
+%imacro bf16 1-*.nolist
+  %rep %0
+    dw __?bfloat16?__(%1)
+    %rotate 1
+  %endrep
+%endmacro
diff --git a/test/float.asm b/test/float.asm
index 88519b2e..1dd92a96 100644
--- a/test/float.asm
+++ b/test/float.asm
@@ -5,6 +5,8 @@
 ; Test of floating-point formats
 ;
 
+%use fp
+
 ; 8-bit
 	db 1.0
 	db +1.0
@@ -65,6 +67,37 @@
 	dw __SNaN__
 	dw 3.1415926535_8979323846_2643383279_5028841971_6939937510_5
 
+; 16-bit bfloat
+	bf16 1.0
+	bf16 +1.0
+	bf16 -1.0
+	bf16 1.5
+	bf16 +1.5
+	bf16 -1.5
+	bf16 0.0
+	bf16 +0.0
+	bf16 -0.0
+	bf16 1.83203125
+	bf16 +1.83203125
+	bf16 -1.83203125
+	bf16 1.83203125e15
+	bf16 +1.83203125e15
+	bf16 -1.83203125e15
+	bf16 1.83203125e-15
+	bf16 +1.83203125e-15
+	bf16 -1.83203125e-15
+	bf16 1.83203125e-40		; Denormal!
+	bf16 +1.83203125e-40		; Denormal!
+	bf16 -1.83203125e-40		; Denormal!
+	bf16 __Infinity__
+	bf16 +__Infinity__
+	bf16 -__Infinity__
+	bf16 __NaN__
+	bf16 __QNaN__
+	bf16 __SNaN__
+	bf16 3.1415926535_8979323846_2643383279_5028841971_6939937510_5
+	bf16 -3.1415, NaN, 2000.0, +Inf
+
 ; 32-bit
 	dd 1.0
 	dd +1.0
@@ -94,6 +127,7 @@
 	dd __QNaN__
 	dd __SNaN__
 	dd 3.1415926535_8979323846_2643383279_5028841971_6939937510_5
+	dd -3.1415, NaN, 2000.0, +Inf
 
 ; 64-bit
 	dq 1.0
@@ -124,7 +158,7 @@
 	dq __QNaN__
 	dq __SNaN__
 	dq 3.1415926535_8979323846_2643383279_5028841971_6939937510_5
-	
+
 ; 80-bit
 	dt 1.0
 	dt +1.0


More information about the Nasm-commits mailing list