From: Jacob Lifshay Date: Tue, 4 Jul 2023 00:45:11 +0000 (-0700) Subject: extract fp->int conversion overview to separate page X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=985eed121053b544605af3adbe1de5651f61ae27;p=libreriscv.git extract fp->int conversion overview to separate page --- diff --git a/openpower/sv/int_fp_mv.mdwn b/openpower/sv/int_fp_mv.mdwn index 2e93df090..8bda5d823 100644 --- a/openpower/sv/int_fp_mv.mdwn +++ b/openpower/sv/int_fp_mv.mdwn @@ -245,4 +245,6 @@ fmvis f4, 0x3F80 # writes +1.0 to f4 fishmv f4, 0x8000 # writes +1.00390625 to f4 ``` +[[!inline pages="openpower/sv/int_fp_mv/cvt_fp_to_int_overview" raw=yes ]] + [[!inline pages="openpower/sv/int_fp_mv/moves_and_conversions" raw=yes ]] diff --git a/openpower/sv/int_fp_mv/cvt_fp_to_int_overview.mdwn b/openpower/sv/int_fp_mv/cvt_fp_to_int_overview.mdwn new file mode 100644 index 000000000..a3175ae3f --- /dev/null +++ b/openpower/sv/int_fp_mv/cvt_fp_to_int_overview.mdwn @@ -0,0 +1,134 @@ +## Floating-point to Integer Conversion Overview + +
+ +IEEE 754 doesn't specify what results are obtained when converting a NaN +or out-of-range floating-point value to integer, so different programming +languages and ISAs have made different choices. Below is an overview +of the different variants, listing the languages and hardware that +implements each variant. + +For convenience, those different conversion semantics will be given names +based on which common ISA or programming language uses them, since there +may not be an established name for them: + +**Standard OpenPower conversion** + +This conversion performs "saturation with NaN converted to minimum +valid integer". This is also exactly the same as the x86 ISA conversion +semantics. OpenPOWER however has instructions for both: + +* rounding mode read from FPSCR +* rounding mode always set to truncate + +**Java/Saturating conversion** + +For the sake of simplicity, the FP -> Integer conversion semantics +generalized from those used by Java's semantics (and Rust's `as` +operator) will be referred to as [Java/Saturating conversion +semantics](#fp-to-int-java-saturating-conversion-semantics). + +Those same semantics are used in some way by all of the following +languages (not necessarily for the default conversion method): + +* Java's + [FP -> Integer conversion](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3) + (only for long/int results) +* Rust's FP -> Integer conversion using the + [`as` operator](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics) +* LLVM's + [`llvm.fptosi.sat`](https://llvm.org/docs/LangRef.html#llvm-fptosi-sat-intrinsic) and + [`llvm.fptoui.sat`](https://llvm.org/docs/LangRef.html#llvm-fptoui-sat-intrinsic) intrinsics +* SPIR-V's OpenCL dialect's + [`OpConvertFToU`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToU) and + [`OpConvertFToS`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToS) + instructions when decorated with + [the `SaturatedConversion` decorator](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_decoration_a_decoration). +* WebAssembly has also introduced + [trunc_sat_u](ttps://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-u) and + [trunc_sat_s](https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-s) + +**JavaScript conversion** + +For the sake of simplicity, the FP -> Integer conversion +semantics generalized from those used by JavaScripts's `ToInt32` +abstract operation will be referred to as [JavaScript conversion +semantics](#fp-to-int-javascript-conversion-semantics). + +This instruction is present in ARM assembler as FJCVTZS + + +**Rc=1 and OE=1** + +All of these instructions have an Rc=1 mode which sets CR0 +in the normal way for any instructions producing a GPR result. +Additionally, when OE=1, if the numerical value of the FP number +is not 100% accurately preserved (due to truncation or saturation +and including when the FP number was NaN) then this is considered +to be an integer Overflow condition, and CR0.SO, XER.SO and XER.OV +are all set as normal for any GPR instructions that overflow. + +\newpage{} + +### FP to Integer Conversion Simplified Pseudo-code + +Key for pseudo-code: + +| term | result type | definition | +|---------------------------|-------------|-----------------------------------------------------------------------------------------------| +| `fp` | -- | `f32` or `f64` (or other types from SimpleV) | +| `int` | -- | `u32`/`u64`/`i32`/`i64` (or other types from SimpleV) | +| `uint` | -- | the unsigned integer of the same bit-width as `int` | +| `int::BITS` | `int` | the bit-width of `int` | +| `uint::MIN_VALUE` | `uint` | the minimum value `uint` can store: `0` | +| `uint::MAX_VALUE` | `uint` | the maximum value `uint` can store: `2^int::BITS - 1` | +| `int::MIN_VALUE` | `int` | the minimum value `int` can store : `-2^(int::BITS-1)` | +| `int::MAX_VALUE` | `int` | the maximum value `int` can store : `2^(int::BITS-1) - 1` | +| `int::VALUE_COUNT` | Integer | the number of different values `int` can store (`2^int::BITS`). too big to fit in `int`. | +| `rint(fp, rounding_mode)` | `fp` | rounds the floating-point value `fp` to an integer according to rounding mode `rounding_mode` | + +
+OpenPower conversion semantics (section A.2 page 1009 (page 1035) of +Power ISA v3.1B): + +``` + def fp_to_int_open_power(v: fp) -> int: + if v is NaN: + return int::MIN_VALUE + if v >= int::MAX_VALUE: + return int::MAX_VALUE + if v <= int::MIN_VALUE: + return int::MIN_VALUE + return (int)rint(v, rounding_mode) +``` + +
+[Java/Saturating conversion semantics](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3) +(only for long/int results) +(with adjustment to add non-truncate rounding modes): + +``` + def fp_to_int_java_saturating(v: fp) -> int: + if v is NaN: + return 0 + if v >= int::MAX_VALUE: + return int::MAX_VALUE + if v <= int::MIN_VALUE: + return int::MIN_VALUE + return (int)rint(v, rounding_mode) +``` + +
+Section 7.1 of the ECMAScript / JavaScript +[conversion semantics](https://262.ecma-international.org/11.0/#sec-toint32) +(with adjustment to add non-truncate rounding modes): + +``` + def fp_to_int_java_script(v: fp) -> int: + if v is NaN or infinite: + return 0 + v = rint(v, rounding_mode) # assume no loss of precision in result + v = v mod int::VALUE_COUNT # 2^32 for i32, 2^64 for i64, result is non-negative + bits = (uint)v + return (int)bits +``` diff --git a/openpower/sv/int_fp_mv/moves_and_conversions.mdwn b/openpower/sv/int_fp_mv/moves_and_conversions.mdwn index 874927446..fb0aeae36 100644 --- a/openpower/sv/int_fp_mv/moves_and_conversions.mdwn +++ b/openpower/sv/int_fp_mv/moves_and_conversions.mdwn @@ -322,145 +322,6 @@ Special Registers altered: \newpage{} -## Floating-point to Integer Conversion Overview - -
- -IEEE 754 doesn't specify what results are obtained when converting a NaN -or out-of-range floating-point value to integer, so different programming -languages and ISAs have made different choices. Below is an overview -of the different variants, listing the languages and hardware that -implements each variant. - -For convenience, those different conversion semantics will be given names -based on which common ISA or programming language uses them, since there -may not be an established name for them: - -**Standard OpenPower conversion** - -This conversion performs "saturation with NaN converted to minimum -valid integer". This is also exactly the same as the x86 ISA conversion -semantics. OpenPOWER however has instructions for both: - -* rounding mode read from FPSCR -* rounding mode always set to truncate - -**Java/Saturating conversion** - -For the sake of simplicity, the FP -> Integer conversion semantics -generalized from those used by Java's semantics (and Rust's `as` -operator) will be referred to as [Java/Saturating conversion -semantics](#fp-to-int-java-saturating-conversion-semantics). - -Those same semantics are used in some way by all of the following -languages (not necessarily for the default conversion method): - -* Java's - [FP -> Integer conversion](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3) - (only for long/int results) -* Rust's FP -> Integer conversion using the - [`as` operator](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics) -* LLVM's - [`llvm.fptosi.sat`](https://llvm.org/docs/LangRef.html#llvm-fptosi-sat-intrinsic) and - [`llvm.fptoui.sat`](https://llvm.org/docs/LangRef.html#llvm-fptoui-sat-intrinsic) intrinsics -* SPIR-V's OpenCL dialect's - [`OpConvertFToU`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToU) and - [`OpConvertFToS`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToS) - instructions when decorated with - [the `SaturatedConversion` decorator](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_decoration_a_decoration). -* WebAssembly has also introduced - [trunc_sat_u](ttps://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-u) and - [trunc_sat_s](https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-s) - -**JavaScript conversion** - -For the sake of simplicity, the FP -> Integer conversion -semantics generalized from those used by JavaScripts's `ToInt32` -abstract operation will be referred to as [JavaScript conversion -semantics](#fp-to-int-javascript-conversion-semantics). - -This instruction is present in ARM assembler as FJCVTZS - - -**Rc=1 and OE=1** - -All of these instructions have an Rc=1 mode which sets CR0 -in the normal way for any instructions producing a GPR result. -Additionally, when OE=1, if the numerical value of the FP number -is not 100% accurately preserved (due to truncation or saturation -and including when the FP number was NaN) then this is considered -to be an integer Overflow condition, and CR0.SO, XER.SO and XER.OV -are all set as normal for any GPR instructions that overflow. - -\newpage{} - -### FP to Integer Conversion Simplified Pseudo-code - -Key for pseudo-code: - -| term | result type | definition | -|---------------------------|-------------|-----------------------------------------------------------------------------------------------| -| `fp` | -- | `f32` or `f64` (or other types from SimpleV) | -| `int` | -- | `u32`/`u64`/`i32`/`i64` (or other types from SimpleV) | -| `uint` | -- | the unsigned integer of the same bit-width as `int` | -| `int::BITS` | `int` | the bit-width of `int` | -| `uint::MIN_VALUE` | `uint` | the minimum value `uint` can store: `0` | -| `uint::MAX_VALUE` | `uint` | the maximum value `uint` can store: `2^int::BITS - 1` | -| `int::MIN_VALUE` | `int` | the minimum value `int` can store : `-2^(int::BITS-1)` | -| `int::MAX_VALUE` | `int` | the maximum value `int` can store : `2^(int::BITS-1) - 1` | -| `int::VALUE_COUNT` | Integer | the number of different values `int` can store (`2^int::BITS`). too big to fit in `int`. | -| `rint(fp, rounding_mode)` | `fp` | rounds the floating-point value `fp` to an integer according to rounding mode `rounding_mode` | - -
-OpenPower conversion semantics (section A.2 page 1009 (page 1035) of -Power ISA v3.1B): - -``` - def fp_to_int_open_power(v: fp) -> int: - if v is NaN: - return int::MIN_VALUE - if v >= int::MAX_VALUE: - return int::MAX_VALUE - if v <= int::MIN_VALUE: - return int::MIN_VALUE - return (int)rint(v, rounding_mode) -``` - -
-[Java/Saturating conversion semantics](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3) -(only for long/int results) -(with adjustment to add non-truncate rounding modes): - -``` - def fp_to_int_java_saturating(v: fp) -> int: - if v is NaN: - return 0 - if v >= int::MAX_VALUE: - return int::MAX_VALUE - if v <= int::MIN_VALUE: - return int::MIN_VALUE - return (int)rint(v, rounding_mode) -``` - -
-Section 7.1 of the ECMAScript / JavaScript -[conversion semantics](https://262.ecma-international.org/11.0/#sec-toint32) -(with adjustment to add non-truncate rounding modes): - -``` - def fp_to_int_java_script(v: fp) -> int: - if v is NaN or infinite: - return 0 - v = rint(v, rounding_mode) # assume no loss of precision in result - v = v mod int::VALUE_COUNT # 2^32 for i32, 2^64 for i64, result is non-negative - bits = (uint)v - return (int)bits -``` - ----------- - -\newpage{} - ## Convert From Floating-Point Register ``` diff --git a/openpower/sv/rfc/ls006.fpintmv.mdwn b/openpower/sv/rfc/ls006.fpintmv.mdwn index fa762f601..186c1bd21 100644 --- a/openpower/sv/rfc/ls006.fpintmv.mdwn +++ b/openpower/sv/rfc/ls006.fpintmv.mdwn @@ -97,6 +97,12 @@ Add the following entries to: \newpage{} +[[!inline pages="openpower/sv/int_fp_mv/cvt_fp_to_int_overview" raw=yes ]] + +---------- + +\newpage{} + [[!inline pages="openpower/sv/int_fp_mv/moves_and_conversions" raw=yes ]] ----------