1 <!-- main body for int_fp_mv.mdwn (without fmvis/fishmv) and ls006.mdwn -->
4 Tables that are used by
5 `mffpr[s][.]`/`mtfpr[s]`/`cffpr[o][.]`/`ctfpr[s][.]`:
7 ## `IT` -- Integer Type
9 | `IT` | Integer Type | Assembly Alias Mnemonic |
10 |------|-----------------|-------------------------|
11 | 0 | Signed 32-bit | `<op>w` |
12 | 1 | Unsigned 32-bit | `<op>uw` |
13 | 2 | Signed 64-bit | `<op>d` |
14 | 3 | Unsigned 64-bit | `<op>ud` |
16 ## `CVM` -- Float to Integer Conversion Mode
18 | `CVM` | `rounding_mode` | Semantics |
19 |-------|-----------------|----------------------------------|
20 | 000 | from `FPSCR` | [OpenPower semantics] |
21 | 001 | Truncate | [OpenPower semantics] |
22 | 010 | from `FPSCR` | [Java/Saturating semantics] |
23 | 011 | Truncate | [Java/Saturating semantics] |
24 | 100 | from `FPSCR` | [JavaScript semantics] |
25 | 101 | Truncate | [JavaScript semantics] |
26 | rest | -- | illegal instruction trap for now |
28 [OpenPower semantics]: #fp-to-int-openpower-conversion-semantics
29 [Java/Saturating semantics]: #fp-to-int-java-saturating-conversion-semantics
30 [JavaScript semantics]: #fp-to-int-javascript-conversion-semantics
36 These instructions perform a straight unaltered bit-level copy from one Register
39 ## Floating Move To GPR
46 | 0-5 | 6-10 | 11-15 | 16-20 | 21-30 | 31 | Form |
47 |-----|------|-------|-------|-------|----|--------|
48 | PO | RT | // | FRB | XO | Rc | X-Form |
54 Move a 64-bit float from a FPR to a GPR, just copying bits of the IEEE 754
55 representation directly. This is equivalent to `stfd` followed by `ld`.
56 As `mffpr` is just copying bits, `FPSCR` is not affected in any way. `mffpr` is
57 similar to `mfvsrd`, except doesn't require VSX, which is useful for SFFS
60 Rc=1 tests RT and sets CR0, exactly like all other Scalar Fixed-Point
63 Special Registers altered:
71 ## Floating Move To GPR Single
78 | 0-5 | 6-10 | 11-15 | 16-20 | 21-30 | 31 | Form |
79 |-----|------|-------|-------|-------|----|--------|
80 | PO | RT | // | FRB | XO | Rc | X-Form |
83 RT <- [0] * 32 || SINGLE((FRB)) # SINGLE since that's what stfs uses
86 Move a BFP32 from a FPR to a GPR, by using `SINGLE` to extract the standard
87 `BFP32` form from FRB and zero-extending the result to 64-bits and storing to
88 RT. This is equivalent to `stfs` followed by `lwz`.
89 As `mffprs` is just copying the BFP32 form, `FPSCR` is not affected in any way.
91 Rc=1 tests RT and sets CR0, exactly like all other Scalar Fixed-Point
94 Special Registers altered:
104 ## Double-Precision Floating Move From GPR
110 | 0-5 | 6-10 | 11-15 | 16-20 | 21-30 | 31 | Form |
111 |-----|------|-------|-------|-------|----|--------|
112 | PO | FRT | // | RB | XO | // | X-Form |
118 move a 64-bit float from a GPR to a FPR, just copying bits of the IEEE 754
119 representation directly. This is equivalent to `std` followed by `lfd`.
120 As `mtfpr` is just copying bits, `FPSCR` is not affected in any way. `mtfpr` is
121 similar to `mtvsrd`, except doesn't require VSX, which is useful for SFFS
124 Special Registers altered:
132 ## Floating Move From GPR Single
138 | 0-5 | 6-10 | 11-15 | 16-20 | 21-30 | 31 | Form |
139 |-----|------|-------|-------|-------|----|--------|
140 | PO | FRT | // | RB | XO | // | X-Form |
143 FRT <- DOUBLE((RB)[32:63]) # DOUBLE since that's what lfs uses
146 Move a BFP32 from a GPR to a FPR, by using `DOUBLE` on the least significant
147 32-bits of RB to do the standard BFP32 in BFP64 trick and store the result in
148 FRT. This is equivalent to `stw` followed by `lfs`.
149 As `mtfprs` is just copying the BFP32 form, `FPSCR` is not affected in any way.
151 Special Registers altered:
163 Unlike the move instructions
164 these instructions perform conversions between Integer and
165 Floating Point. Truncation can therefore occur, as well
168 ## Double-Precision Floating Convert From Integer In GPR
175 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21-30 | 31 | Form |
176 |-----|------|-------|-------|-------|-------|----|--------|
177 | PO | FRT | IT | // | RB | XO | Rc | X-Form |
180 if IT[0] = 0 then # 32-bit int -> 64-bit float
181 # rounding never necessary, so don't touch FPSCR
182 # based off xvcvsxwdp
183 if IT = 0 then # Signed 32-bit
184 src <- bfp_CONVERT_FROM_SI32((RB)[32:63])
185 else # IT = 1 -- Unsigned 32-bit
186 src <- bfp_CONVERT_FROM_UI32((RB)[32:63])
187 FRT <- bfp64_CONVERT_FROM_BFP(src)
189 # rounding may be necessary. based off xscvuxdsp
192 case(0): # Signed 32-bit
193 src <- bfp_CONVERT_FROM_SI32((RB)[32:63])
194 case(1): # Unsigned 32-bit
195 src <- bfp_CONVERT_FROM_UI32((RB)[32:63])
196 case(2): # Signed 64-bit
197 src <- bfp_CONVERT_FROM_SI64((RB))
198 default: # Unsigned 64-bit
199 src <- bfp_CONVERT_FROM_UI64((RB))
200 rnd <- bfp_ROUND_TO_BFP64(0b0, FPSCR.RN, src)
201 result <- bfp64_CONVERT_FROM_BFP(rnd)
202 cls <- fprf_CLASS_BFP64(result)
204 if xx_flag = 1 then SetFX(FPSCR.XX)
211 <!-- note the PowerISA spec. explicitly has empty lines before/after SetFX,
212 don't remove them -->
214 Convert from a unsigned/signed 32/64-bit integer in RB to a 64-bit
217 If converting from a unsigned/signed 32-bit integer to a 64-bit float,
218 rounding is never necessary, so `FPSCR` is unmodified and exceptions are
219 never raised. Otherwise, `FPSCR` is modified and exceptions are raised
222 Rc=1 tests FRT and sets CR1, exactly like all other Scalar Floating-Point
225 Special Registers altered:
229 FPRF FR FI FX XX (if IT[0]=1)
234 | Assembly Alias | Full Instruction |
235 |----------------------|----------------------|
236 | `ctfprw FRT, RB` | `ctfpr FRT, RB, 0` |
237 | `ctfprw. FRT, RB` | `ctfpr. FRT, RB, 0` |
238 | `ctfpruw FRT, RB` | `ctfpr FRT, RB, 1` |
239 | `ctfpruw. FRT, RB` | `ctfpr. FRT, RB, 1` |
240 | `ctfprd FRT, RB` | `ctfpr FRT, RB, 2` |
241 | `ctfprd. FRT, RB` | `ctfpr. FRT, RB, 2` |
242 | `ctfprud FRT, RB` | `ctfpr FRT, RB, 3` |
243 | `ctfprud. FRT, RB` | `ctfpr. FRT, RB, 3` |
249 ## Floating Convert From Integer In GPR Single
256 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21-30 | 31 | Form |
257 |-----|------|-------|-------|-------|-------|----|--------|
258 | PO | FRT | IT | // | RB | XO | Rc | X-Form |
261 # rounding may be necessary. based off xscvuxdsp
264 case(0): # Signed 32-bit
265 src <- bfp_CONVERT_FROM_SI32((RB)[32:63])
266 case(1): # Unsigned 32-bit
267 src <- bfp_CONVERT_FROM_UI32((RB)[32:63])
268 case(2): # Signed 64-bit
269 src <- bfp_CONVERT_FROM_SI64((RB))
270 default: # Unsigned 64-bit
271 src <- bfp_CONVERT_FROM_UI64((RB))
272 rnd <- bfp_ROUND_TO_BFP32(FPSCR.RN, src)
273 result32 <- bfp32_CONVERT_FROM_BFP(rnd)
274 cls <- fprf_CLASS_BFP32(result32)
275 result <- DOUBLE(result32)
277 if xx_flag = 1 then SetFX(FPSCR.XX)
284 <!-- note the PowerISA spec. explicitly has empty lines before/after SetFX,
285 don't remove them -->
287 Convert from a unsigned/signed 32/64-bit integer in RB to a 32-bit
288 float in FRT, following the usual 32-bit float in 64-bit float format.
289 `FPSCR` is modified and exceptions are raised as usual.
291 Rc=1 tests FRT and sets CR1, exactly like all other Scalar Floating-Point
294 Special Registers altered:
303 | Assembly Alias | Full Instruction |
304 |----------------------|----------------------|
305 | `ctfprws FRT, RB` | `ctfpr FRT, RB, 0` |
306 | `ctfprws. FRT, RB` | `ctfpr. FRT, RB, 0` |
307 | `ctfpruws FRT, RB` | `ctfpr FRT, RB, 1` |
308 | `ctfpruws. FRT, RB` | `ctfpr. FRT, RB, 1` |
309 | `ctfprds FRT, RB` | `ctfpr FRT, RB, 2` |
310 | `ctfprds. FRT, RB` | `ctfpr. FRT, RB, 2` |
311 | `ctfpruds FRT, RB` | `ctfpr FRT, RB, 3` |
312 | `ctfpruds. FRT, RB` | `ctfpr. FRT, RB, 3` |
318 ## Floating-point to Integer Conversion Overview
320 <div id="fpr-to-gpr-conversion-mode"></div>
322 IEEE 754 doesn't specify what results are obtained when converting a NaN
323 or out-of-range floating-point value to integer, so different programming
324 languages and ISAs have made different choices. Below is an overview
325 of the different variants, listing the languages and hardware that
326 implements each variant.
328 For convenience, those different conversion semantics will be given names
329 based on which common ISA or programming language uses them, since there
330 may not be an established name for them:
332 **Standard OpenPower conversion**
334 This conversion performs "saturation with NaN converted to minimum
335 valid integer". This is also exactly the same as the x86 ISA conversion
336 semantics. OpenPOWER however has instructions for both:
338 * rounding mode read from FPSCR
339 * rounding mode always set to truncate
341 **Java/Saturating conversion**
343 For the sake of simplicity, the FP -> Integer conversion semantics
344 generalized from those used by Java's semantics (and Rust's `as`
345 operator) will be referred to as [Java/Saturating conversion
346 semantics](#fp-to-int-java-saturating-conversion-semantics).
348 Those same semantics are used in some way by all of the following
349 languages (not necessarily for the default conversion method):
352 [FP -> Integer conversion](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3)
353 (only for long/int results)
354 * Rust's FP -> Integer conversion using the
355 [`as` operator](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics)
357 [`llvm.fptosi.sat`](https://llvm.org/docs/LangRef.html#llvm-fptosi-sat-intrinsic) and
358 [`llvm.fptoui.sat`](https://llvm.org/docs/LangRef.html#llvm-fptoui-sat-intrinsic) intrinsics
359 * SPIR-V's OpenCL dialect's
360 [`OpConvertFToU`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToU) and
361 [`OpConvertFToS`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToS)
362 instructions when decorated with
363 [the `SaturatedConversion` decorator](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_decoration_a_decoration).
364 * WebAssembly has also introduced
365 [trunc_sat_u](ttps://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-u) and
366 [trunc_sat_s](https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-s)
368 **JavaScript conversion**
370 For the sake of simplicity, the FP -> Integer conversion
371 semantics generalized from those used by JavaScripts's `ToInt32`
372 abstract operation will be referred to as [JavaScript conversion
373 semantics](#fp-to-int-javascript-conversion-semantics).
375 This instruction is present in ARM assembler as FJCVTZS
376 <https://developer.arm.com/documentation/dui0801/g/hko1477562192868>
380 All of these instructions have an Rc=1 mode which sets CR0
381 in the normal way for any instructions producing a GPR result.
382 Additionally, when OE=1, if the numerical value of the FP number
383 is not 100% accurately preserved (due to truncation or saturation
384 and including when the FP number was NaN) then this is considered
385 to be an integer Overflow condition, and CR0.SO, XER.SO and XER.OV
386 are all set as normal for any GPR instructions that overflow.
390 ### FP to Integer Conversion Simplified Pseudo-code
394 | term | result type | definition |
395 |---------------------------|-------------|----------------------------------------------------------------------------------------------------|
396 | `fp` | -- | `f32` or `f64` (or other types from SimpleV) |
397 | `int` | -- | `u32`/`u64`/`i32`/`i64` (or other types from SimpleV) |
398 | `uint` | -- | the unsigned integer of the same bit-width as `int` |
399 | `int::BITS` | `int` | the bit-width of `int` |
400 | `uint::MIN_VALUE` | `uint` | the minimum value `uint` can store: `0` |
401 | `uint::MAX_VALUE` | `uint` | the maximum value `uint` can store: `2^int::BITS - 1` |
402 | `int::MIN_VALUE` | `int` | the minimum value `int` can store : `-2^(int::BITS-1)` |
403 | `int::MAX_VALUE` | `int` | the maximum value `int` can store : `2^(int::BITS-1) - 1` |
404 | `int::VALUE_COUNT` | Integer | the number of different values `int` can store (`2^int::BITS`). too big to fit in `int`. |
405 | `rint(fp, rounding_mode)` | `fp` | rounds the floating-point value `fp` to an integer according to rounding mode `rounding_mode` |
407 <div id="fp-to-int-openpower-conversion-semantics"></div>
408 OpenPower conversion semantics (section A.2 page 1009 (page 1035) of
412 def fp_to_int_open_power<fp, int>(v: fp) -> int:
414 return int::MIN_VALUE
415 if v >= int::MAX_VALUE:
416 return int::MAX_VALUE
417 if v <= int::MIN_VALUE:
418 return int::MIN_VALUE
419 return (int)rint(v, rounding_mode)
422 <div id="fp-to-int-java-saturating-conversion-semantics"></div>
423 [Java/Saturating conversion semantics](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3)
424 (only for long/int results)
425 (with adjustment to add non-truncate rounding modes):
428 def fp_to_int_java_saturating<fp, int>(v: fp) -> int:
431 if v >= int::MAX_VALUE:
432 return int::MAX_VALUE
433 if v <= int::MIN_VALUE:
434 return int::MIN_VALUE
435 return (int)rint(v, rounding_mode)
438 <div id="fp-to-int-javascript-conversion-semantics"></div>
439 Section 7.1 of the ECMAScript / JavaScript
440 [conversion semantics](https://262.ecma-international.org/11.0/#sec-toint32)
441 (with adjustment to add non-truncate rounding modes):
444 def fp_to_int_java_script<fp, int>(v: fp) -> int:
445 if v is NaN or infinite:
447 v = rint(v, rounding_mode) # assume no loss of precision in result
448 v = v mod int::VALUE_COUNT # 2^32 for i32, 2^64 for i64, result is non-negative
457 ## Double-Precision Floating Convert To Integer In GPR
460 cffpr RT, FRB, CVM, IT
461 cffpr. RT, FRB, CVM, IT
462 cffpro RT, FRB, CVM, IT
463 cffpro. RT, FRB, CVM, IT
466 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21 | 22-30 | 31 | Form |
467 |-----|------|-------|-------|-------|----|-------|----|---------|
468 | PO | RT | IT | CVM | FRB | OE | XO | Rc | XO-Form |
471 # based on xscvdpuxws
473 src <- bfp_CONVERT_FROM_BFP64((FRB))
476 case(0): # Signed 32-bit
477 range_min <- bfp_CONVERT_FROM_SI32(0x8000_0000)
478 range_max <- bfp_CONVERT_FROM_SI32(0x7FFF_FFFF)
479 js_mask <- 0x0000_0000_FFFF_FFFF
480 case(1): # Unsigned 32-bit
481 range_min <- bfp_CONVERT_FROM_UI32(0)
482 range_max <- bfp_CONVERT_FROM_UI32(0xFFFF_FFFF)
483 js_mask <- 0x0000_0000_FFFF_FFFF
484 case(2): # Signed 64-bit
485 range_min <- bfp_CONVERT_FROM_SI64(-0x8000_0000_0000_0000)
486 range_max <- bfp_CONVERT_FROM_SI64(0x7FFF_FFFF_FFFF_FFFF)
487 js_mask <- 0xFFFF_FFFF_FFFF_FFFF
488 default: # Unsigned 64-bit
489 range_min <- bfp_CONVERT_FROM_UI64(0)
490 range_max <- bfp_CONVERT_FROM_UI64(0xFFFF_FFFF_FFFF_FFFF)
491 js_mask <- 0xFFFF_FFFF_FFFF_FFFF
493 if (CVM[2] = 1) | (FPSCR.RN = 0b01) then
494 rnd <- bfp_ROUND_TO_INTEGER_TRUNC(src)
495 else if FPSCR.RN = 0b00 then
496 rnd <- bfp_ROUND_TO_INTEGER_NEAR_EVEN(src)
497 else if FPSCR.RN = 0b10 then
498 rnd <- bfp_ROUND_TO_INTEGER_CEIL(src)
499 else if FPSCR.RN = 0b11 then
500 rnd <- bfp_ROUND_TO_INTEGER_FLOOR(src)
503 case(0, 1): # OpenPower semantics
505 result <- si64_CONVERT_FROM_BFP(range_min)
506 else if bfp_COMPARE_GT(rnd, range_max) then
507 result <- ui64_CONVERT_FROM_BFP(range_max)
508 else if bfp_COMPARE_LT(rnd, range_min) then
509 result <- si64_CONVERT_FROM_BFP(range_min)
510 else if IT[1] = 1 then # Unsigned 32/64-bit
511 result <- ui64_CONVERT_FROM_BFP(rnd)
512 else # Signed 32/64-bit
513 result <- si64_CONVERT_FROM_BFP(rnd)
514 case(2, 3): # Java/Saturating semantics
517 else if bfp_COMPARE_GT(rnd, range_max) then
518 result <- ui64_CONVERT_FROM_BFP(range_max)
519 else if bfp_COMPARE_LT(rnd, range_min) then
520 result <- si64_CONVERT_FROM_BFP(range_min)
521 else if IT[1] = 1 then # Unsigned 32/64-bit
522 result <- ui64_CONVERT_FROM_BFP(rnd)
523 else # Signed 32/64-bit
524 result <- si64_CONVERT_FROM_BFP(rnd)
525 default: # JavaScript semantics
526 # CVM = 6, 7 are illegal instructions
527 # using a 128-bit intermediate works here because the largest type
528 # this instruction can convert from has 53 significand bits, and
529 # the largest type this instruction can convert to has 64 bits,
530 # and the sum of those is strictly less than the 128 bits of the
531 # intermediate result.
532 limit <- bfp_CONVERT_FROM_UI128([1] * 128)
533 if IsInf(rnd) | IsNaN(rnd) then
535 else if bfp_COMPARE_GT(bfp_ABSOLUTE(rnd), limit) then
538 result128 <- si128_CONVERT_FROM_BFP(rnd)
539 result <- result128[64:127] & js_mask
542 case(0): # Signed 32-bit
543 result <- EXTS64(result[32:63])
544 result_bfp <- bfp_CONVERT_FROM_SI32(result[32:63])
545 case(1): # Unsigned 32-bit
546 result <- EXTZ64(result[32:63])
547 result_bfp <- bfp_CONVERT_FROM_UI32(result[32:63])
548 case(2): # Signed 64-bit
549 result_bfp <- bfp_CONVERT_FROM_SI64(result)
550 default: # Unsigned 64-bit
551 result_bfp <- bfp_CONVERT_FROM_UI64(result)
553 overflow <- 0 # signals SO only when OE = 1
554 if IsNaN(src) | ¬bfp_COMPARE_EQ(rnd, result_bfp) then
555 overflow <- 1 # signals SO only when OE = 1
560 xx_flag <- ¬bfp_COMPARE_EQ(src, result_bfp)
561 inc_flag <- bfp_COMPARE_GT(bfp_ABSOLUTE(result_bfp), bfp_ABSOLUTE(src))
563 if vxsnan_flag = 1 then SetFX(FPSCR.VXSNAN)
564 if vxcvi_flag = 1 then SetFX(FPSCR.VXCVI)
565 if xx_flag = 1 then SetFX(FPSCR.XX)
567 vx_flag <- vxsnan_flag | vxcvi_flag
568 vex_flag <- FPSCR.VE & vx_flag
571 FPSCR.FPRF <- undefined
579 Convert from 64-bit float in FRB to a unsigned/signed 32/64-bit integer
580 in RT, with the conversion overflow/rounding semantics following the
581 chosen `CVM` value. `FPSCR` is modified and exceptions are raised as usual.
583 These instructions have an Rc=1 mode which sets CR0 in the normal
584 way for any instructions producing a GPR result. Additionally, when OE=1,
585 if the numerical value of the FP number is not 100% accurately preserved
586 (due to truncation or saturation and including when the FP number was
587 NaN) then this is considered to be an Integer Overflow condition, and
588 CR0.SO, XER.SO and XER.OV are all set as normal for any GPR instructions
589 that overflow. When `RT` is not written (`vex_flag = 1`), all CR0 bits
590 except SO are undefined.
592 Special Registers altered:
596 XER SO, OV, OV32 (if OE=1)
597 FPRF=0bUUUUU FR FI FX XX VXSNAN VXCV
602 | Assembly Alias | Full Instruction |
603 |---------------------------|----------------------------|
604 | `cffprw RT, FRB, CVM` | `cffpr RT, FRB, CVM, 0` |
605 | `cffprw. RT, FRB, CVM` | `cffpr. RT, FRB, CVM, 0` |
606 | `cffprwo RT, FRB, CVM` | `cffpro RT, FRB, CVM, 0` |
607 | `cffprwo. RT, FRB, CVM` | `cffpro. RT, FRB, CVM, 0` |
608 | `cffpruw RT, FRB, CVM` | `cffpr RT, FRB, CVM, 1` |
609 | `cffpruw. RT, FRB, CVM` | `cffpr. RT, FRB, CVM, 1` |
610 | `cffpruwo RT, FRB, CVM` | `cffpro RT, FRB, CVM, 1` |
611 | `cffpruwo. RT, FRB, CVM` | `cffpro. RT, FRB, CVM, 1` |
612 | `cffprd RT, FRB, CVM` | `cffpr RT, FRB, CVM, 2` |
613 | `cffprd. RT, FRB, CVM` | `cffpr. RT, FRB, CVM, 2` |
614 | `cffprdo RT, FRB, CVM` | `cffpro RT, FRB, CVM, 2` |
615 | `cffprdo. RT, FRB, CVM` | `cffpro. RT, FRB, CVM, 2` |
616 | `cffprud RT, FRB, CVM` | `cffpr RT, FRB, CVM, 3` |
617 | `cffprud. RT, FRB, CVM` | `cffpr. RT, FRB, CVM, 3` |
618 | `cffprudo RT, FRB, CVM` | `cffpro RT, FRB, CVM, 3` |
619 | `cffprudo. RT, FRB, CVM` | `cffpro. RT, FRB, CVM, 3` |