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