mirror of
https://https.git.savannah.gnu.org/git/coreutils.git
synced 2026-01-26 15:29:07 +00:00
od: support half precision floating point
Rely on compiler support for _Float16 and __bf16 to support -fH and -fB formats respectively. I.e. IEEE 16 bit, and brain 16 bit floats respectively. Modern GCC and LLVM compilers support both types. clang-sect=half-precision-floating-point https://gcc.gnu.org/onlinedocs/gcc/Half-Precision.html https://clang.llvm.org/docs/LanguageExtensions.html#$clang-sect https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0192r4.html https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1467r9.html This was tested on: gcc 13, clang 17 x86 (Both types supported) gcc 7 aarch64 (Only -fH supported) gcc 13 ppc(be) (Neither supported. Both will be with GCC 14) * src/od.c: Support -tf2 or -tfH to print IEEE 16 bit floating point, or -tfB to print Brain 16 bit floating point. * configure.ac: Check for _Float16 and __bf16 types. * doc/coreutils.texi (od invocation): Mention the new -f types. * tests/od/od-float.sh: Add test cases. * NEWS: Mention the new feature. Addresses https://bugs.gnu.org/68871
This commit is contained in:
parent
6ec1fb46ab
commit
76604db7d2
3
NEWS
3
NEWS
@ -57,6 +57,9 @@ GNU coreutils NEWS -*- outline -*-
|
||||
chgrp now accepts the --from=OWNER:GROUP option to restrict changes to files
|
||||
with matching current OWNER and/or GROUP, as already supported by chown(1).
|
||||
|
||||
od now supports printing IEEE half precision floating point with -t fH,
|
||||
or brain 16 bit floating point with -t fB, where supported by the compiler.
|
||||
|
||||
tail now supports following multiple processes, with repeated --pid options.
|
||||
|
||||
** Improvements
|
||||
|
||||
@ -522,6 +522,9 @@ CFLAGS=$ac_save_CFLAGS
|
||||
LDFLAGS=$ac_save_LDFLAGS
|
||||
ac_c_werror_flag=$cu_save_c_werror_flag
|
||||
|
||||
# Test compiler support for half precision floating point types (for od)
|
||||
AC_CHECK_TYPES([_Float16, __bf16])
|
||||
|
||||
ac_save_CFLAGS=$CFLAGS
|
||||
CFLAGS="-mavx -mpclmul $CFLAGS"
|
||||
AC_MSG_CHECKING([if pclmul intrinsic exists])
|
||||
|
||||
@ -2127,6 +2127,12 @@ long
|
||||
For floating point (@code{f}):
|
||||
|
||||
@table @asis
|
||||
@item B
|
||||
@uref{https://en.wikipedia.org/wiki/Bfloat16_floating-point_format,
|
||||
brain 16 bit float}
|
||||
@item H
|
||||
@uref{https://en.wikipedia.org/wiki/Half-precision_floating-point_format,
|
||||
half precision float}
|
||||
@item F
|
||||
float
|
||||
@item D
|
||||
|
||||
73
src/od.c
73
src/od.c
@ -19,6 +19,7 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
@ -49,6 +50,26 @@ typedef unsigned long long int unsigned_long_long_int;
|
||||
typedef unsigned long int unsigned_long_long_int;
|
||||
#endif
|
||||
|
||||
#if HAVE__FLOAT16
|
||||
/* Available since clang 6 (2018), and gcc 7 (2017). */
|
||||
typedef _Float16 float16;
|
||||
#else
|
||||
# define HAVE__FLOAT16 0
|
||||
/* This is just a place-holder to avoid a few '#if' directives.
|
||||
In this case, the type isn't actually used. */
|
||||
typedef float float16;
|
||||
#endif
|
||||
|
||||
#if HAVE___BF16
|
||||
/* Available since clang 11 (2020), and gcc 13 (2023). */
|
||||
typedef __bf16 bfloat16;
|
||||
#else
|
||||
# define HAVE___BF16 0
|
||||
/* This is just a place-holder to avoid a few '#if' directives.
|
||||
In this case, the type isn't actually used. */
|
||||
typedef float bfloat16;
|
||||
#endif
|
||||
|
||||
enum size_spec
|
||||
{
|
||||
NO_SIZE,
|
||||
@ -58,6 +79,7 @@ enum size_spec
|
||||
LONG,
|
||||
LONG_LONG,
|
||||
/* FIXME: add INTMAX support, too */
|
||||
FLOAT_HALF,
|
||||
FLOAT_SINGLE,
|
||||
FLOAT_DOUBLE,
|
||||
FLOAT_LONG_DOUBLE,
|
||||
@ -71,6 +93,8 @@ enum output_format
|
||||
OCTAL,
|
||||
HEXADECIMAL,
|
||||
FLOATING_POINT,
|
||||
HFLOATING_POINT,
|
||||
BFLOATING_POINT,
|
||||
NAMED_CHARACTER,
|
||||
CHARACTER
|
||||
};
|
||||
@ -156,6 +180,11 @@ static const int width_bytes[] =
|
||||
sizeof (int),
|
||||
sizeof (long int),
|
||||
sizeof (unsigned_long_long_int),
|
||||
#if HAVE___BF16
|
||||
sizeof (bfloat16),
|
||||
#else
|
||||
sizeof (float16),
|
||||
#endif
|
||||
sizeof (float),
|
||||
sizeof (double),
|
||||
sizeof (long double)
|
||||
@ -400,8 +429,9 @@ TYPE is made up of one or more of these specifications:\n\
|
||||
\n\
|
||||
SIZE is a number. For TYPE in [doux], SIZE may also be C for\n\
|
||||
sizeof(char), S for sizeof(short), I for sizeof(int) or L for\n\
|
||||
sizeof(long). If TYPE is f, SIZE may also be F for sizeof(float), D\n\
|
||||
for sizeof(double) or L for sizeof(long double).\n\
|
||||
sizeof(long). If TYPE is f, SIZE may also be B for Brain 16 bit,\n\
|
||||
H for Half precision float, F for sizeof(float), D for sizeof(double),\n\
|
||||
or L for sizeof(long double).\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
\n\
|
||||
@ -477,6 +507,8 @@ PRINT_TYPE (print_int, unsigned int)
|
||||
PRINT_TYPE (print_long, unsigned long int)
|
||||
PRINT_TYPE (print_long_long, unsigned_long_long_int)
|
||||
|
||||
PRINT_FLOATTYPE (print_bfloat, bfloat16, ftoastr, FLT_BUFSIZE_BOUND)
|
||||
PRINT_FLOATTYPE (print_halffloat, float16, ftoastr, FLT_BUFSIZE_BOUND)
|
||||
PRINT_FLOATTYPE (print_float, float, ftoastr, FLT_BUFSIZE_BOUND)
|
||||
PRINT_FLOATTYPE (print_double, double, dtoastr, DBL_BUFSIZE_BOUND)
|
||||
PRINT_FLOATTYPE (print_long_double, long double, ldtoastr, LDBL_BUFSIZE_BOUND)
|
||||
@ -773,6 +805,18 @@ decode_one_format (char const *s_orig, char const *s, char const **next,
|
||||
++s;
|
||||
switch (*s)
|
||||
{
|
||||
case 'B':
|
||||
++s;
|
||||
fmt = BFLOATING_POINT;
|
||||
size = sizeof (bfloat16);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
++s;
|
||||
fmt = HFLOATING_POINT;
|
||||
size = sizeof (float16);
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
++s;
|
||||
size = sizeof (float);
|
||||
@ -802,7 +846,10 @@ decode_one_format (char const *s_orig, char const *s, char const **next,
|
||||
else
|
||||
{
|
||||
if (size > MAX_FP_TYPE_SIZE
|
||||
|| fp_type_size[size] == NO_SIZE)
|
||||
|| fp_type_size[size] == NO_SIZE
|
||||
|| (! HAVE__FLOAT16 && HAVE___BF16
|
||||
&& size == sizeof (bfloat16))
|
||||
)
|
||||
{
|
||||
error (0, 0,
|
||||
_("invalid type string %s;\n"
|
||||
@ -817,6 +864,15 @@ decode_one_format (char const *s_orig, char const *s, char const **next,
|
||||
}
|
||||
size_spec = fp_type_size[size];
|
||||
|
||||
if ((! HAVE__FLOAT16 && fmt == HFLOATING_POINT)
|
||||
|| (! HAVE___BF16 && fmt == BFLOATING_POINT))
|
||||
{
|
||||
error (0, 0,
|
||||
_("this system doesn't provide a %s floating point type"),
|
||||
quote (s_orig));
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
struct lconv const *locale = localeconv ();
|
||||
size_t decimal_point_len =
|
||||
@ -824,6 +880,12 @@ decode_one_format (char const *s_orig, char const *s, char const **next,
|
||||
|
||||
switch (size_spec)
|
||||
{
|
||||
case FLOAT_HALF:
|
||||
print_function = fmt == BFLOATING_POINT
|
||||
? print_bfloat : print_halffloat;
|
||||
field_width = FLT_STRLEN_BOUND_L (decimal_point_len);
|
||||
break;
|
||||
|
||||
case FLOAT_SINGLE:
|
||||
print_function = print_float;
|
||||
field_width = FLT_STRLEN_BOUND_L (decimal_point_len);
|
||||
@ -1598,6 +1660,11 @@ main (int argc, char **argv)
|
||||
for (i = 0; i <= MAX_FP_TYPE_SIZE; i++)
|
||||
fp_type_size[i] = NO_SIZE;
|
||||
|
||||
#if HAVE__FLOAT16
|
||||
fp_type_size[sizeof (float16)] = FLOAT_HALF;
|
||||
#elif HAVE___BF16
|
||||
fp_type_size[sizeof (bfloat16)] = FLOAT_HALF;
|
||||
#endif
|
||||
fp_type_size[sizeof (float)] = FLOAT_SINGLE;
|
||||
/* The array entry for 'double' is filled in after that for 'long double'
|
||||
so that if they are the same size, we avoid any overhead of
|
||||
|
||||
@ -69,4 +69,25 @@ set x $(printf 00000000ff000000 | tr 0f '\000\377' | od -t fL) || fail=1
|
||||
#*) fail=1;;
|
||||
#esac
|
||||
|
||||
# Check Half precision IEEE 16 bit float
|
||||
if grep '^#define HAVE__FLOAT16 1' "$CONFIG_HEADER" >/dev/null; then
|
||||
for fmt in '-tfH' '-tf2'; do
|
||||
od_out=$(printf '\x3C\x00\x3C\x00' | od --endian=big -An $fmt | tr -d ' ')
|
||||
test "$od_out" = '11' || fail=1
|
||||
done
|
||||
else
|
||||
echo "od: this system doesn't provide a 'fH' floating point type" > exp_err
|
||||
returns_ 1 od -tfH /dev/null 2>err || fail=1
|
||||
compare exp_err err || fail=1
|
||||
fi
|
||||
# Check Half precision Brain 16 bit float
|
||||
if grep '^#define HAVE___BF16 1' "$CONFIG_HEADER" >/dev/null; then
|
||||
od_out=$(printf '\x3F\x80\x3F\x80' | od --endian=big -An -tfB | tr -d ' ')
|
||||
test "$od_out" = '11' || fail=1
|
||||
else
|
||||
echo "od: this system doesn't provide a 'fB' floating point type" > exp_err
|
||||
returns_ 1 od -tfB /dev/null 2>err || fail=1
|
||||
compare exp_err err || fail=1
|
||||
fi
|
||||
|
||||
Exit $fail
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user