remove section of pseudocode that does nothing
[libreriscv.git] / openpower / sv / int_fp_mv.mdwn
1 [[!tag standards]]
2
3 Note on considered alternative naming schemes: we decided to switch to using the reduced mnemonic naming scheme (over some people's objections) since it would be 5 instructions instead of dozens, though we did consider trying to match PowerISA's existing naming scheme for the instructions rather than only for the instruction aliases. <https://bugs.libre-soc.org/show_bug.cgi?id=1015#c7>
4
5 # FPR-to-GPR and GPR-to-FPR
6
7 TODO special constants instruction (e, tau/N, ln 2, sqrt 2, etc.) -- exclude any constants available through fmvis
8
9 **Draft Status** under development, for submission as an RFC
10
11 Links:
12
13 * <https://bugs.libre-soc.org/show_bug.cgi?id=650>
14 * <https://bugs.libre-soc.org/show_bug.cgi?id=230#c71>
15 * <https://bugs.libre-soc.org/show_bug.cgi?id=230#c74>
16 * <https://bugs.libre-soc.org/show_bug.cgi?id=230#c76>
17 * <https://bugs.libre-soc.org/show_bug.cgi?id=887> fmvis
18 * <https://bugs.libre-soc.org/show_bug.cgi?id=1015> int-fp RFC
19 * [[int_fp_mv/appendix]]
20 * [[sv/rfc/ls002]] - `fmvis` and `fishmv` External RFC Formal Submission
21 * [[sv/rfc/ls006]] - int-fp-mv External RFC Formal Submission
22
23 Trademarks:
24
25 * Rust is a Trademark of the Rust Foundation
26 * Java and Javascript are Trademarks of Oracle
27 * LLVM is a Trademark of the LLVM Foundation
28 * SPIR-V is a Trademark of the Khronos Group
29 * OpenCL is a Trademark of Apple, Inc.
30
31 Referring to these Trademarks within this document
32 is by necessity, in order to put the semantics of each language
33 into context, and is considered "fair use" under Trademark
34 Law.
35
36 Introduction:
37
38 High-performance CPU/GPU software needs to often convert between integers
39 and floating-point, therefore fast conversion/data-movement instructions
40 are needed. Also given that initialisation of floats tends to take up
41 considerable space (even to just load 0.0) the inclusion of two compact
42 format float immediate instructions is up for consideration using 16-bit
43 immediates. BF16 is one of the formats: a second instruction allows a full
44 accuracy FP32 to be constructed.
45
46 Libre-SOC will be compliant with the
47 **Scalar Floating-Point Subset** (SFFS) i.e. is not implementing VMX/VSX,
48 and with its focus on modern 3D GPU hybrid workloads represents an
49 important new potential use-case for OpenPOWER.
50
51 Prior to the formation of the Compliancy Levels first introduced
52 in v3.0C and v3.1
53 the progressive historic development of the Scalar parts of the Power ISA assumed
54 that VSX would always be there to complement it. However With VMX/VSX
55 **not available** in the newly-introduced SFFS Compliancy Level, the
56 existing non-VSX conversion/data-movement instructions require
57 a Vector of load/store
58 instructions (slow and expensive) to transfer data between the FPRs and
59 the GPRs. For a modern 3D GPU this kills any possibility of a
60 competitive edge.
61 Also, because SimpleV needs efficient scalar instructions in
62 order to generate efficient vector instructions, adding new instructions
63 for data-transfer/conversion between FPRs and GPRs multiplies the savings.
64
65 In addition, the vast majority of GPR <-> FPR data-transfers are as part
66 of a FP <-> Integer conversion sequence, therefore reducing the number
67 of instructions required is a priority.
68
69 Therefore, we are proposing adding:
70
71 * FPR load-immediate instructions, one equivalent to `BF16`, the
72 other increasing accuracy to `FP32`
73 * FPR <-> GPR data-transfer instructions that just copy bits without conversion
74 * FPR <-> GPR combined data-transfer/conversion instructions that do
75 Integer <-> FP conversions
76
77 If adding new Integer <-> FP conversion instructions,
78 the opportunity may be taken to modernise the instructions and make them
79 well-suited for common/important conversion sequences:
80
81 * Int -> Float
82 * **standard IEEE754** - used by most languages and CPUs
83 * Float -> Int
84 * **standard OpenPOWER** - saturation with NaN
85 converted to minimum valid integer
86 * **Java/Saturating** - saturation with NaN converted to 0
87 * **JavaScript** - modulo wrapping with Inf/NaN converted to 0
88
89 The assembly listings in the [[int_fp_mv/appendix]] show how costly
90 some of these language-specific conversions are: Javascript, the
91 worst case, is 32 scalar instructions including seven branch instructions.
92
93 # Proposed New Scalar Instructions
94
95 All of the following instructions use the standard OpenPower conversion to/from 64-bit float format when reading/writing a 32-bit float from/to a FPR. All integers however are sourced/stored in the *GPR*.
96
97 Integer operands and results being in the GPR is the key differentiator between the proposed instructions
98 (the entire rationale) compared to existing Scalar Power ISA.
99 In all existing Power ISA Scalar conversion instructions, all
100 operands are FPRs, even if the format of the source or destination
101 data is actually a scalar integer.
102
103 *(The existing Scalar instructions being FP-FP only is based on an assumption
104 that VSX will be implemented, and VSX is not part of the SFFS Compliancy
105 Level. An earlier version of the Power ISA used to have similar
106 FPR<->GPR instructions to these:
107 they were deprecated due to this incorrect assumption that VSX would
108 always be present).*
109
110 Note that source and destination widths can be overridden by SimpleV
111 SVP64, and that SVP64 also has Saturation Modes *in addition*
112 to those independently described here. SVP64 Overrides and Saturation
113 work on *both* Fixed *and* Floating Point operands and results.
114 The interactions with SVP64
115 are explained in the [[int_fp_mv/appendix]]
116
117 # Float load immediate <a name="fmvis"></a>
118
119 These are like a variant of `fmvfg` and `oris`, combined.
120 Power ISA currently requires a large
121 number of instructions to get Floating Point constants into registers.
122 `fmvis` on its own is equivalent to BF16 to FP32/64 conversion,
123 but if followed up by `fishmv` an additional 16 bits of accuracy in the
124 mantissa may be achieved.
125
126 These instructions **always** save
127 resources compared to FP-load for exactly the same reason
128 that `li` saves resources: an L1-Data-Cache and memory read
129 is avoided.
130
131 *IBM may consider it worthwhile to extend these two instructions to
132 v3.1 Prefixed (`pfmvis` and `pfishmv`: 8RR, imm0 extended).
133 If so it is recommended that
134 `pfmvis` load a full FP32 immediate and `pfishmv` supplies the three high
135 missing exponent bits (numbered 8 to 10) and the lower additional
136 29 mantissa bits (23 to 51) needed to construct a full FP64 immediate.
137 Strictly speaking the sequence `fmvis fishmv pfishmv` achieves the
138 same effect in the same number of bytes as `pfmvis pfishmv`,
139 making `pfmvis` redundant.*
140
141 Just as Floating-point Load does not set FP Flags neither does fmvis or fishmv.
142 As fishmv is specifically intended to work in conjunction with fmvis
143 to provide additional accuracy, all bits other than those which
144 would have been set by a prior fmvis instruction are deliberately ignored.
145 (If these instructions involved reading from registers rather than immediates
146 it would be a different story).
147
148 ## Load BF16 Immediate
149
150 `fmvis FRS, D`
151
152 Reinterprets `D << 16` as a 32-bit float, which is then converted to a
153 64-bit float and written to `FRS`. This is equivalent to reinterpreting
154 `D` as a `BF16` and converting to 64-bit float.
155 There is no need for an Rc=1 variant because this is an immediate loading
156 instruction.
157
158 Example:
159
160 ```
161 # clearing a FPR
162 fmvis f4, 0 # writes +0.0 to f4
163 # loading handy constants
164 fmvis f4, 0x8000 # writes -0.0 to f4
165 fmvis f4, 0x3F80 # writes +1.0 to f4
166 fmvis f4, 0xBF80 # writes -1.0 to f4
167 fmvis f4, 0xBFC0 # writes -1.5 to f4
168 fmvis f4, 0x7FC0 # writes +qNaN to f4
169 fmvis f4, 0x7F80 # writes +Infinity to f4
170 fmvis f4, 0xFF80 # writes -Infinity to f4
171 fmvis f4, 0x3FFF # writes +1.9921875 to f4
172
173 # clearing 128 FPRs with 2 SVP64 instructions
174 # by issuing 32 vec4 (subvector length 4) ops
175 setvli VL=MVL=32
176 sv.fmvis/vec4 f0, 0 # writes +0.0 to f0-f127
177 ```
178 Important: If the float load immediate instruction(s) are left out,
179 change all [GPR to FPR conversion instructions](#GPR-to-FPR-conversions)
180 to instead write `+0.0` if `RA` is register `0`, at least
181 allowing clearing FPRs.
182
183 `fmvis` fits with DX-Form:
184
185 | 0-5 | 6-10 | 11-15 | 16-25 | 26-30 | 31 | Form |
186 |--------|------|-------|-------|-------|-----|---------|
187 | Major | FRS | d1 | d0 | XO | d2 | DX-Form |
188
189 Pseudocode:
190
191 bf16 = d0 || d1 || d2 # create BF16 immediate
192 fp32 = bf16 || [0]*16 # convert BF16 to FP32
193 FRS = DOUBLE(fp32) # convert FP32 to FP64
194
195 Special registers altered:
196
197 None
198
199 ## Float Immediate Second-Half MV <a name="fishmv"></a>
200
201 `fishmv FRS, D`
202
203 DX-Form:
204
205 | 0-5 | 6-10 | 11-15 | 16-25 | 26-30 | 31 | Form |
206 |--------|------|-------|-------|-------|-----|---------|
207 | Major | FRS | d1 | d0 | XO | d2 | DX-Form |
208
209 Strategically similar to how `oris` is used to construct
210 32-bit Integers, an additional 16-bits of immediate is
211 inserted into `FRS` to extend its accuracy to
212 a full FP32 (stored as usual in FP64 Format within the FPR).
213 If a prior `fmvis` instruction had been used to
214 set the upper 16-bits of an FP32 value, `fishmv` contains the
215 lower 16-bits.
216
217 The key difference between using `li` and `oris` to construct 32-bit
218 GPR Immediates and `fishmv` is that the `fmvis` will have converted
219 the `BF16` immediate to FP64 (Double) format.
220 This is taken into consideration
221 as can be seen in the pseudocode below.
222
223 Pseudocode:
224
225 fp32 <- SINGLE((FRS)) # convert to FP32
226 fp32[16:31] <- d0 || d1 || d2 # replace LSB half
227 FRS <- DOUBLE(fp32) # convert back to FP64
228
229 Special registers altered:
230
231 None
232
233 **This instruction performs a Read-Modify-Write.** *FRS is read, the additional
234 16 bit immediate inserted, and the result also written to FRS*
235
236 Example:
237
238 ```
239 # these two combined instructions write 0x3f808000
240 # into f4 as an FP32 to be converted to an FP64.
241 # actual contents in f4 after conversion: 0x3ff0_1000_0000_0000
242 # first the upper bits, happens to be +1.0
243 fmvis f4, 0x3F80 # writes +1.0 to f4
244 # now write the lower 16 bits of an FP32
245 fishmv f4, 0x8000 # writes +1.00390625 to f4
246 ```
247
248 # Immediate Tables
249
250 Tables that are used by `fmvtg`/`fmvfg`/`fcvttg`/`fcvtfg`:
251
252 ## `RCS` -- `Rc` and `s`
253
254 | `RCS` | `Rc` | FP Single Mode | Assembly Alias Mnemonic |
255 |-------|------|----------------|-------------------------|
256 | 0 | 0 | Double | `<op>` |
257 | 1 | 1 | Double | `<op>.` |
258 | 2 | 0 | Single | `<op>s` |
259 | 3 | 1 | Single | `<op>s.` |
260
261 ## `IT` -- Integer Type
262
263 | `IT` | Integer Type | Assembly Alias Mnemonic |
264 |------|-----------------|-------------------------|
265 | 0 | Signed 32-bit | `<op>w` |
266 | 1 | Unsigned 32-bit | `<op>uw` |
267 | 2 | Signed 64-bit | `<op>d` |
268 | 3 | Unsigned 64-bit | `<op>ud` |
269
270 ## `CVM` -- Float to Integer Conversion Mode
271
272 | `CVM` | `rounding_mode` | Semantics |
273 |-------|-----------------|----------------------------------|
274 | 000 | from `FPSCR` | [OpenPower semantics] |
275 | 001 | Truncate | [OpenPower semantics] |
276 | 010 | from `FPSCR` | [Java/Saturating semantics] |
277 | 011 | Truncate | [Java/Saturating semantics] |
278 | 100 | from `FPSCR` | [JavaScript semantics] |
279 | 101 | Truncate | [JavaScript semantics] |
280 | rest | -- | illegal instruction trap for now |
281
282 [OpenPower semantics]: #fp-to-int-openpower-conversion-semantics
283 [Java/Saturating semantics]: #fp-to-int-java-saturating-conversion-semantics
284 [JavaScript semantics]: #fp-to-int-javascript-conversion-semantics
285
286 # Moves
287
288 These instructions perform a straight unaltered bit-level copy from one Register
289 File to another.
290
291 ## FPR to GPR move
292
293 `fmvtg RT, FRB, RCS`
294
295 | 0-5 | 6-10 | 11-15 | 16-20 | 21-29 | 30-31 | Form |
296 |-----|------|-------|-------|-------|-------|--------|
297 | PO | RT | 0 | FRB | XO | RCS | X-Form |
298
299 ```
300 if RCS[0] = 1 then # if Single mode
301 RT <- [0] * 32 || SINGLE((FRB)) # SINGLE since that's what stfs uses
302 else
303 RT <- (FRB)
304 ```
305
306 move a 32/64-bit float from a FPR to a GPR, just copying bits of the IEEE 754 representation directly. This is equivalent to `stfs` followed by `lwz` or equivalent to `stfd` followed by `ld`.
307 As `fmvtg` is just copying bits, `FPSCR` is not affected in any way.
308
309 Rc=1 tests RT and sets CR0, exactly like all other Scalar Fixed-Point
310 operations.
311
312 ### Assembly Aliases
313
314 | Assembly Alias | Full Instruction |
315 |-------------------|--------------------|
316 | `fmvtg RT, FRB` | `fmvtg RT, FRB, 0` |
317 | `fmvtg. RT, FRB` | `fmvtg RT, FRB, 1` |
318 | `fmvtgs RT, FRB` | `fmvtg RT, FRB, 2` |
319 | `fmvtgs. RT, FRB` | `fmvtg RT, FRB, 3` |
320
321 ## GPR to FPR move
322
323 `fmvfg FRT, RB, RCS`
324
325 | 0-5 | 6-10 | 11-15 | 16-20 | 21-29 | 30-31 | Form |
326 |-----|------|-------|-------|-------|-------|--------|
327 | PO | FRT | 0 | RB | XO | RCS | X-Form |
328
329 ```
330 if RCS[0] = 1 then # if Single mode
331 FRT <- DOUBLE((RB)[32:63]) # DOUBLE since that's what lfs uses
332 else
333 FRT <- (RB)
334 ```
335
336 move a 32/64-bit float from a GPR to a FPR, just copying bits of the IEEE 754 representation directly. This is equivalent to `stw` followed by `lfs` or equivalent to `std` followed by `lfd`. As `fmvfg` is just copying bits, `FPSCR` is not affected in any way.
337
338 Rc=1 tests FRT and sets CR1, exactly like all other Scalar Floating-Point
339 operations.
340
341 ### Assembly Aliases
342
343 | Assembly Alias | Full Instruction |
344 |-------------------|--------------------|
345 | `fmvfg FRT, RB` | `fmvfg FRT, RB, 0` |
346 | `fmvfg. FRT, RB` | `fmvfg FRT, RB, 1` |
347 | `fmvfgs FRT, RB` | `fmvfg FRT, RB, 2` |
348 | `fmvfgs. FRT, RB` | `fmvfg FRT, RB, 3` |
349
350 # Conversions
351
352 Unlike the move instructions
353 these instructions perform conversions between Integer and
354 Floating Point. Truncation can therefore occur, as well
355 as exceptions.
356
357 ## Floating-point Convert From GPR
358
359 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21-29 | 30-31 | Form |
360 |-----|------|-------|-------|-------|-------|-------|--------|
361 | PO | FRT | IT | 0 | RB | XO | RCS | X-Form |
362
363 `fcvtfg FRT, RB, IT, RCS`
364
365 ```
366 if IT[0] = 0 and RCS[0] = 0 then # 32-bit int -> 64-bit float
367 # rounding never necessary, so don't touch FPSCR
368 # based off xvcvsxwdp
369 if IT = 0 then # Signed 32-bit
370 src <- bfp_CONVERT_FROM_SI32((RB)[32:63])
371 else # IT = 1 -- Unsigned 32-bit
372 src <- bfp_CONVERT_FROM_UI32((RB)[32:63])
373 FRT <- bfp64_CONVERT_FROM_BFP(src)
374 else
375 # rounding may be necessary
376 # based off xscvuxdsp
377 reset_xflags()
378 switch(IT)
379 case(0): # Signed 32-bit
380 src <- bfp_CONVERT_FROM_SI32((RB)[32:63])
381 case(1): # Unsigned 32-bit
382 src <- bfp_CONVERT_FROM_UI32((RB)[32:63])
383 case(2): # Signed 64-bit
384 src <- bfp_CONVERT_FROM_SI64((RB))
385 default: # Unsigned 64-bit
386 src <- bfp_CONVERT_FROM_UI64((RB))
387 if RCS[0] = 1 then # Single
388 rnd <- bfp_ROUND_TO_BFP32(FPSCR.RN, src)
389 result32 <- bfp32_CONVERT_FROM_BFP(rnd)
390 cls <- fprf_CLASS_BFP32(result32)
391 result <- DOUBLE(result32)
392 else
393 rnd <- bfp_ROUND_TO_BFP64(FPSCR.RN, src)
394 result <- bfp64_CONVERT_FROM_BFP(rnd)
395 cls <- fprf_CLASS_BFP64(result)
396
397 if xx_flag = 1 then SetFX(FPSCR.XX)
398
399 FRT <- result
400 FPSCR.FPRF <- cls
401 FPSCR.FR <- inc_flag
402 FPSCR.FI <- xx_flag
403 ```
404
405 Convert from a unsigned/signed 32/64-bit integer in RB to a 32/64-bit float in FRT, following the usual 32-bit float in 64-bit float format.
406
407 If converting from a unsigned/signed 32-bit integer to a 64-bit float, rounding is never necessary, so `FPSCR` is unmodified and exceptions are never raised. Otherwise, `FPSCR` is modified and exceptions are raised as usual.
408
409 Rc=1 tests FRT and sets CR1, exactly like all other Scalar Floating-Point
410 operations.
411
412 ### Assembly Aliases
413
414 | Assembly Alias | Full Instruction |
415 |----------------------|------------------------|
416 | `fcvtfgw FRT, RB` | `fcvtfg FRT, RB, 0, 0` |
417 | `fcvtfgw. FRT, RB` | `fcvtfg FRT, RB, 0, 1` |
418 | `fcvtfgws FRT, RB` | `fcvtfg FRT, RB, 0, 2` |
419 | `fcvtfgws. FRT, RB` | `fcvtfg FRT, RB, 0, 3` |
420 | `fcvtfguw FRT, RB` | `fcvtfg FRT, RB, 1, 0` |
421 | `fcvtfguw. FRT, RB` | `fcvtfg FRT, RB, 1, 1` |
422 | `fcvtfguws FRT, RB` | `fcvtfg FRT, RB, 1, 2` |
423 | `fcvtfguws. FRT, RB` | `fcvtfg FRT, RB, 1, 3` |
424 | `fcvtfgd FRT, RB` | `fcvtfg FRT, RB, 2, 0` |
425 | `fcvtfgd. FRT, RB` | `fcvtfg FRT, RB, 2, 1` |
426 | `fcvtfgds FRT, RB` | `fcvtfg FRT, RB, 2, 2` |
427 | `fcvtfgds. FRT, RB` | `fcvtfg FRT, RB, 2, 3` |
428 | `fcvtfgud FRT, RB` | `fcvtfg FRT, RB, 3, 0` |
429 | `fcvtfgud. FRT, RB` | `fcvtfg FRT, RB, 3, 1` |
430 | `fcvtfguds FRT, RB` | `fcvtfg FRT, RB, 3, 2` |
431 | `fcvtfguds. FRT, RB` | `fcvtfg FRT, RB, 3, 3` |
432
433 ## Floating-point to Integer Conversion Overview
434
435 <div id="fpr-to-gpr-conversion-mode"></div>
436
437 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
438 of the different variants, listing the languages and hardware that
439 implements each variant.
440
441 For convenience, we will give those different conversion semantics names based on which common ISA or programming language uses them, since there may not be an established name for them:
442
443 **Standard OpenPower conversion**
444
445 This conversion performs "saturation with NaN converted to minimum valid integer". This
446 is also exactly the same as the x86 ISA conversion semantics.
447 OpenPOWER however has instructions for both:
448
449 * rounding mode read from FPSCR
450 * rounding mode always set to truncate
451
452 **Java/Saturating conversion**
453
454 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
455 [Java/Saturating conversion semantics](#fp-to-int-java-saturating-conversion-semantics).
456
457 Those same semantics are used in some way by all of the following languages (not necessarily for the default conversion method):
458
459 * Java's
460 [FP -> Integer conversion](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3) (only for long/int results)
461 * Rust's FP -> Integer conversion using the
462 [`as` operator](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics)
463 * LLVM's
464 [`llvm.fptosi.sat`](https://llvm.org/docs/LangRef.html#llvm-fptosi-sat-intrinsic) and
465 [`llvm.fptoui.sat`](https://llvm.org/docs/LangRef.html#llvm-fptoui-sat-intrinsic) intrinsics
466 * SPIR-V's OpenCL dialect's
467 [`OpConvertFToU`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToU) and
468 [`OpConvertFToS`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToS)
469 instructions when decorated with
470 [the `SaturatedConversion` decorator](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_decoration_a_decoration).
471 * WebAssembly has also introduced
472 [trunc_sat_u](ttps://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-u) and
473 [trunc_sat_s](https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-s)
474
475 **JavaScript conversion**
476
477 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).
478
479 This instruction is present in ARM assembler as FJCVTZS
480 <https://developer.arm.com/documentation/dui0801/g/hko1477562192868>
481
482 **Rc=1 and OE=1**
483
484 All of these instructions have an Rc=1 mode which sets CR0
485 in the normal way for any instructions producing a GPR result.
486 Additionally, when OE=1, if the numerical value of the FP number
487 is not 100% accurately preserved (due to truncation or saturation
488 and including when the FP number was NaN) then this is considered
489 to be an integer Overflow condition, and CR0.SO, XER.SO and XER.OV
490 are all set as normal for any GPR instructions that overflow.
491
492 ### FP to Integer Conversion Simplified Pseudo-code
493
494 Key for pseudo-code:
495
496 | term | result type | definition |
497 |---------------------------|-------------|----------------------------------------------------------------------------------------------------|
498 | `fp` | -- | `f32` or `f64` (or other types from SimpleV) |
499 | `int` | -- | `u32`/`u64`/`i32`/`i64` (or other types from SimpleV) |
500 | `uint` | -- | the unsigned integer of the same bit-width as `int` |
501 | `int::BITS` | `int` | the bit-width of `int` |
502 | `uint::MIN_VALUE` | `uint` | the minimum value `uint` can store: `0` |
503 | `uint::MAX_VALUE` | `uint` | the maximum value `uint` can store: `2^int::BITS - 1` |
504 | `int::MIN_VALUE` | `int` | the minimum value `int` can store : `-2^(int::BITS-1)` |
505 | `int::MAX_VALUE` | `int` | the maximum value `int` can store : `2^(int::BITS-1) - 1` |
506 | `int::VALUE_COUNT` | Integer | the number of different values `int` can store (`2^int::BITS`). too big to fit in `int`. |
507 | `rint(fp, rounding_mode)` | `fp` | rounds the floating-point value `fp` to an integer according to rounding mode `rounding_mode` |
508
509 <div id="fp-to-int-openpower-conversion-semantics"></div>
510 OpenPower conversion semantics (section A.2 page 1009 (page 1035) of Power ISA v3.1B):
511
512 ```
513 def fp_to_int_open_power<fp, int>(v: fp) -> int:
514 if v is NaN:
515 return int::MIN_VALUE
516 if v >= int::MAX_VALUE:
517 return int::MAX_VALUE
518 if v <= int::MIN_VALUE:
519 return int::MIN_VALUE
520 return (int)rint(v, rounding_mode)
521 ```
522
523 <div id="fp-to-int-java-saturating-conversion-semantics"></div>
524 [Java/Saturating conversion semantics](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3)
525 (only for long/int results)/
526 [Rust semantics](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics)
527 (with adjustment to add non-truncate rounding modes):
528
529 ```
530 def fp_to_int_java_saturating<fp, int>(v: fp) -> int:
531 if v is NaN:
532 return 0
533 if v >= int::MAX_VALUE:
534 return int::MAX_VALUE
535 if v <= int::MIN_VALUE:
536 return int::MIN_VALUE
537 return (int)rint(v, rounding_mode)
538 ```
539
540 <div id="fp-to-int-javascript-conversion-semantics"></div>
541 Section 7.1 of the ECMAScript / JavaScript
542 [conversion semantics](https://262.ecma-international.org/11.0/#sec-toint32) (with adjustment to add non-truncate rounding modes):
543
544 ```
545 def fp_to_int_java_script<fp, int>(v: fp) -> int:
546 if v is NaN or infinite:
547 return 0
548 v = rint(v, rounding_mode) # assume no loss of precision in result
549 v = v mod int::VALUE_COUNT # 2^32 for i32, 2^64 for i64, result is non-negative
550 bits = (uint)v
551 return (int)bits
552 ```
553
554 ## Floating-point Convert To GPR
555
556 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21-28 | 29 | 30 | 31 | Form |
557 |-----|------|-------|-------|-------|-------|--------|----|--------|---------|
558 | PO | RT | IT | CVM | FRB | XO | RCS[0] | OE | RCS[1] | XO-Form |
559
560 `fcvttg RT, FRB, CVM, IT, RCS`
561 `fcvttgo RT, FRB, CVM, IT, RCS`
562
563 ```
564 # based on xscvdpuxws
565 reset_xflags()
566
567 if RCS[0] = 1 then # if Single mode
568 src <- bfp_CONVERT_FROM_BFP32(SINGLE((FRB)))
569 else
570 src <- bfp_CONVERT_FROM_BFP64((FRB))
571
572 switch(IT)
573 case(0): # Signed 32-bit
574 range_min <- bfp_CONVERT_FROM_SI32(0x8000_0000)
575 range_max <- bfp_CONVERT_FROM_SI32(0x7FFF_FFFF)
576 js_mask <- 0xFFFF_FFFF
577 case(1): # Unsigned 32-bit
578 range_min <- bfp_CONVERT_FROM_UI32(0)
579 range_max <- bfp_CONVERT_FROM_UI32(0xFFFF_FFFF)
580 js_mask <- 0xFFFF_FFFF
581 case(2): # Signed 64-bit
582 range_min <- bfp_CONVERT_FROM_SI64(-0x8000_0000_0000_0000)
583 range_max <- bfp_CONVERT_FROM_SI64(0x7FFF_FFFF_FFFF_FFFF)
584 js_mask <- 0xFFFF_FFFF_FFFF_FFFF
585 default: # Unsigned 64-bit
586 range_min <- bfp_CONVERT_FROM_UI64(0)
587 range_max <- bfp_CONVERT_FROM_UI64(0xFFFF_FFFF_FFFF_FFFF)
588 js_mask <- 0xFFFF_FFFF_FFFF_FFFF
589
590 if CVM[2] = 1 or FPSCR.RN = 0b01 then
591 rnd <- bfp_ROUND_TO_INTEGER_TRUNC(src)
592 else if FPSCR.RN = 0b00 then
593 rnd <- bfp_ROUND_TO_INTEGER_NEAR_EVEN(src)
594 else if FPSCR.RN = 0b10 then
595 rnd <- bfp_ROUND_TO_INTEGER_CEIL(src)
596 else if FPSCR.RN = 0b11 then
597 rnd <- bfp_ROUND_TO_INTEGER_FLOOR(src)
598
599 switch(CVM)
600 case(0, 1): # OpenPower semantics
601 if IsNaN(rnd) then
602 result <- si64_CONVERT_FROM_BFP(range_min)
603 else if bfp_COMPARE_GT(rnd, range_max) then
604 result <- ui64_CONVERT_FROM_BFP(range_max)
605 else if bfp_COMPARE_LT(rnd, range_min) then
606 result <- si64_CONVERT_FROM_BFP(range_min)
607 else if IT[1] = 1 then # Unsigned 32/64-bit
608 result <- ui64_CONVERT_FROM_BFP(range_max)
609 else # Signed 32/64-bit
610 result <- si64_CONVERT_FROM_BFP(range_max)
611 case(2, 3): # Java/Saturating semantics
612 if IsNaN(rnd) then
613 result <- [0] * 64
614 else if bfp_COMPARE_GT(rnd, range_max) then
615 result <- ui64_CONVERT_FROM_BFP(range_max)
616 else if bfp_COMPARE_LT(rnd, range_min) then
617 result <- si64_CONVERT_FROM_BFP(range_min)
618 else if IT[1] = 1 then # Unsigned 32/64-bit
619 result <- ui64_CONVERT_FROM_BFP(range_max)
620 else # Signed 32/64-bit
621 result <- si64_CONVERT_FROM_BFP(range_max)
622 default: # JavaScript semantics
623 # CVM = 6, 7 are illegal instructions
624
625 # this works because the largest type we try to
626 # convert from has 53 significand bits, and the
627 # largest type we try to convert to has 64 bits,
628 # and the sum of those is strictly less than the
629 # 128 bits of the intermediate result.
630 limit <- bfp_CONVERT_FROM_UI128([1] * 128)
631 if IsInf(rnd) or IsNaN(rnd) then
632 result <- [0] * 64
633 else if bfp_COMPARE_GT(bfp_ABSOLUTE(rnd), limit) then
634 result <- [0] * 64
635 else
636 result128 <- si128_CONVERT_FROM_BFP(rnd)
637 result <- result128[64:127] & js_mask
638
639 switch(IT)
640 case(0): # Signed 32-bit
641 result <- EXTS64(result[32:63])
642 result_bfp <- bfp_CONVERT_FROM_SI32(result[32:63])
643 case(1): # Unsigned 32-bit
644 result <- EXTZ64(result[32:63])
645 result_bfp <- bfp_CONVERT_FROM_UI32(result[32:63])
646 case(2): # Signed 64-bit
647 result_bfp <- bfp_CONVERT_FROM_SI64(result)
648 default: # Unsigned 64-bit
649 result_bfp <- bfp_CONVERT_FROM_UI64(result)
650
651 if vxsnan_flag = 1 then SetFX(FPSCR.VXSNAN)
652 if vxcvi_flag = 1 then SetFX(FPSCR.VXCVI)
653 if xx_flag = 1 then SetFX(FPSCR.XX)
654
655 vx_flag <- vxsnan_flag | vxcvi_flag
656 vex_flag <- FPSCR.VE & vx_flag
657
658 if vex_flag = 0 then
659 RT <- result
660 FPSCR.FPRF <- undefined
661 FPSCR.FR <- inc_flag
662 FPSCR.FI <- xx_flag
663 if IsNaN(src) or not bfp_COMPARE_EQ(src, result_bfp) then
664 overflow <- 1 # signals SO only when OE = 1
665 else
666 FPSCR.FR <- 0
667 FPSCR.FI <- 0
668 ```
669
670 Convert from 32/64-bit float in FRB to a unsigned/signed 32/64-bit integer in RT, with the conversion overflow/rounding semantics following the chosen `CVM` value, following the usual 32-bit float in 64-bit float format.
671
672 `FPSCR` is modified and exceptions are raised as usual.
673
674 Both of these instructions have an Rc=1 mode which sets CR0
675 in the normal way for any instructions producing a GPR result.
676 Additionally, when OE=1, if the numerical value of the FP number
677 is not 100% accurately preserved (due to truncation or saturation
678 and including when the FP number was NaN) then this is considered
679 to be an integer Overflow condition, and CR0.SO, XER.SO and XER.OV
680 are all set as normal for any GPR instructions that overflow.
681
682 ### Assembly Aliases
683
684 For brevity, `[o]` is used to mean `o` is optional there.
685
686 | Assembly Alias | Full Instruction |
687 |------------------------------|--------------------------------|
688 | `fcvttgw[o] RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 0, 0` |
689 | `fcvttgw[o]. RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 0, 1` |
690 | `fcvtstgw[o] RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 0, 2` |
691 | `fcvtstgw[o]. RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 0, 3` |
692 | `fcvttguw[o] RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 1, 0` |
693 | `fcvttguw[o]. RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 1, 1` |
694 | `fcvtstguw[o] RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 1, 2` |
695 | `fcvtstguw[o]. RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 1, 3` |
696 | `fcvttgd[o] RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 2, 0` |
697 | `fcvttgd[o]. RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 2, 1` |
698 | `fcvtstgd[o] RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 2, 2` |
699 | `fcvtstgd[o]. RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 2, 3` |
700 | `fcvttgud[o] RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 3, 0` |
701 | `fcvttgud[o]. RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 3, 1` |
702 | `fcvtstgud[o] RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 3, 2` |
703 | `fcvtstgud[o]. RT, FRB, CVM` | `fcvttg[o] RT, FRB, CVM, 3, 3` |