From e0c9a43aae5c1d6b08bf2fec41d55745105721a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciro=20Santilli=20=E5=85=AD=E5=9B=9B=E4=BA=8B=E4=BB=B6=20?= =?UTF-8?q?=E6=B3=95=E8=BD=AE=E5=8A=9F?= Date: Sat, 29 Jun 2019 00:00:02 +0000 Subject: [PATCH] ieee 754: start section --- README.adoc | 27 +++++++++++++++- lkmc/float.h | 20 ++++++++++++ userland/arch/x86_64/ieee754.S | 59 ++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 lkmc/float.h create mode 100644 userland/arch/x86_64/ieee754.S diff --git a/README.adoc b/README.adoc index de7d7db..f969c49 100644 --- a/README.adoc +++ b/README.adoc @@ -12063,7 +12063,7 @@ Particularly important numerical analysis instruction, that is used in particula * Dot product * Matrix multiplication -FMA is so important that IEEE 754 specifies it with single precision drop compared to a separate add and multiply! +FMA is so important that <> specifies it with single precision drop compared to a separate add and multiply! Micro-op fun: http://stackoverflow.com/questions/28630864/how-is-fma-implemented @@ -12990,6 +12990,19 @@ Old floating point unit that you should likely not use anymore, prefer instead t ** link:userland/arch/x86_64/fsqrt.S[] FSQRT: square root ** link:userland/arch/x86_64/fxch.S[] FXCH: swap ST0 and another register +The ST0-ST7 x87 FPU registers are actually 80-bits wide, this can be seen from GDB with: + +.... +i r st0 st1 +.... + +By counting the number of hex digits, we have 20 digits instead of 16! + +Instructions such as FLDL convert standard <> 64-bit values from memory into this custom 80-bit format. + +* https://stackoverflow.com/questions/3206101/extended-80-bit-double-floating-point-in-x87-not-sse2-we-dont-miss-it +* https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format + ==== x86 x87 FPU vs SIMD http://stackoverflow.com/questions/1844669/benefits-of-x87-over-sse @@ -14177,6 +14190,18 @@ http://infocenter.arm.com/help/topic/com.arm.doc.ddi0438i/DDI0438I_cortex_a15_r4 2013. +== IEEE 754 + +https://en.wikipedia.org/wiki/IEEE_754 + +Examples: + +* link:userland/arch/x86_64/ieee754.S[] +* link:lkmc/float.h[] +* https://stackoverflow.com/questions/8341395/what-is-a-subnormal-floating-point-number/53203428#53203428 +* https://stackoverflow.com/questions/18118408/what-is-difference-between-quiet-nan-and-signaling-nan/55648118#55648118 +* https://stackoverflow.com/questions/2618059/in-java-what-does-nan-mean/55673220#55673220 + == Baremetal Getting started at: <> diff --git a/lkmc/float.h b/lkmc/float.h new file mode 100644 index 0000000..4259b6e --- /dev/null +++ b/lkmc/float.h @@ -0,0 +1,20 @@ +#ifndef LKMC_FLOAT_H +#define LKMC_FLOAT_H + +/* https://github.com/cirosantilli/linux-kernel-module-cheat#ieee-754 */ + +#define LKMC_FLOAT_64_SIGN_BITS 1 +#define LKMC_FLOAT_64_EXP_BITS 11 +#define LKMC_FLOAT_64_MANTISSA_BITS 52 +#define LKMC_FLOAT_64_EXP_BIAS ((1 << (LKMC_FLOAT_64_EXP_BITS - 1)) - 1) +#define LKMC_FLOAT_64_EXP_INFINITY_BIASED ((1 << LKMC_FLOAT_64_EXP_BITS) - 1) +#define LKMC_FLOAT_64_EXP_INFINITY (LKMC_FLOAT_64_EXP_INFINITY_BIASED - LKMC_FLOAT_64_EXP_BIAS) +#define LKMC_FLOAT_64(sign, exp, mantissa) ((((sign << LKMC_FLOAT_64_EXP_BITS) | exp + LKMC_FLOAT_64_EXP_BIAS) << LKMC_FLOAT_64_MANTISSA_BITS) | mantissa) +#define LKMC_FLOAT_64_PLUS_INFINITY LKMC_FLOAT_64(0x0, LKMC_FLOAT_64_EXP_INFINITY, 0x0) +#define LKMC_FLOAT_64_MINUS_INFINITY LKMC_FLOAT_64(0x1, LKMC_FLOAT_64_EXP_INFINITY, 0x0) +#define LKMC_FLOAT_64_QNAN(x) LKMC_FLOAT_64(0x0, LKMC_FLOAT_64_EXP_INFINITY, (x) | (1 << (LKMC_FLOAT_64_MANTISSA_BITS - 1))) +#define LKMC_FLOAT_64_QNAN_DEFAULT LKMC_FLOAT_64_QNAN(1 << (LKMC_FLOAT_64_MANTISSA_BITS - 2)) +#define LKMC_FLOAT_64_SNAN(x) LKMC_FLOAT_64(0x0, LKMC_FLOAT_64_EXP_INFINITY, x) +#define LKMC_FLOAT_64_SNAN_DEFAULT LKMC_FLOAT_64_SNAN(1 << (LKMC_FLOAT_64_MANTISSA_BITS - 2)) + +#endif diff --git a/userland/arch/x86_64/ieee754.S b/userland/arch/x86_64/ieee754.S new file mode 100644 index 0000000..8b8bbd0 --- /dev/null +++ b/userland/arch/x86_64/ieee754.S @@ -0,0 +1,59 @@ +/* https://github.com/cirosantilli/linux-kernel-module-cheat#ieee-754 */ + +#include +#include + +.data + double_1_5: .quad LKMC_FLOAT_64(0x0, 0x0, 0x8000000000000) + double_2_5: .quad LKMC_FLOAT_64(0x0, 0x1, 0x4000000000000) + double_4_0: .quad LKMC_FLOAT_64(0x0, 0x2, 0x0000000000000) + double_minus_4_0: .quad LKMC_FLOAT_64(0x1, 0x2, 0x10000000000000) + double_plus_infinity: .quad LKMC_FLOAT_64_PLUS_INFINITY + double_nan: .quad LKMC_FLOAT_64_QNAN_DEFAULT + double_ref_1_5: .double 1.5 + double_ref_2_5: .double 2.5 + double_ref_4_0: .double 4.0 + double_ref_minus_4_0: .double -4.0 + double_ref_plus_infinity: .double inf + double_ref_nan: .double nan +LKMC_PROLOGUE + /* Check that our macros are correct. */ + LKMC_ASSERT_EQ(double_1_5, double_ref_1_5) + LKMC_ASSERT_EQ(double_2_5, double_ref_2_5) + LKMC_ASSERT_EQ(double_4_0, double_ref_4_0) + LKMC_ASSERT_EQ(double_minus_4_0, double_ref_minus_4_0) + LKMC_ASSERT_EQ(double_plus_infinity, double_ref_plus_infinity) + /* TODO: GAS nan is a different NaN: 0x7FFFFFFF */ + /*LKMC_ASSERT_EQ(double_nan, double_ref_nan)*/ + + /* x87 80-bit FPU: https://github.com/cirosantilli/linux-kernel-module-cheat#x86-x87-fpu-instructions */ + + /* 1.5 + 2.5 == 4.0. */ + fldl double_1_5 + fldl double_2_5 + faddp %st, %st(1) + fldl double_4_0 + fcomip %st(1) + LKMC_ASSERT(je) + + /* 4.0 + -4.0 == 0.0. */ + fldl double_minus_4_0 + faddp %st, %st(1) + fldz + fcomip %st(1) + LKMC_ASSERT(je) + + /* 0.0 + inf == inf */ + fldl double_plus_infinity + faddp %st, %st(1) + fldl double_plus_infinity + fcomip %st(1) + LKMC_ASSERT(je) + + /* inf + nan == nan */ + fldl double_nan + faddp %st, %st(1) + fldl double_nan + fcomip %st(1) + LKMC_ASSERT(je) +LKMC_EPILOGUE