1 <!-- main body for int_fp_mv.mdwn (without fmvis/fishmv) and ls006.fpintmv.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
34 # Move To/From Floating-Point Register Instructions
36 These instructions perform a copy from one register file to another, as if by
37 using a GPR/FPR store, followed by a FPR/GPR load.
39 ## Move From Floating-Point Register
46 | 0-5 | 6-10 | 11-15 | 16-20 | 21-30 | 31 | Form |
47 |-----|------|-------|-------|-------|----|--------|
48 | PO | RT | // | FRB | XO | Rc | X-Form |
54 The contents of `FPR[FRB]` are placed into `GPR[RT]`.
56 Special Registers altered:
64 `mffpr` is equivalent to the combination of `stfd` followed by `ld`.
68 `mffpr` is a separate instruction from `mfvsrd` because `mfvsrd` requires
69 VSX which may not be available on simpler implementations.
70 Additionally, SVP64 may treat VSX instructions differently than SFFS
71 instructions in a future version of the architecture.
75 ## Move From Floating-Point Register Single
82 | 0-5 | 6-10 | 11-15 | 16-20 | 21-30 | 31 | Form |
83 |-----|------|-------|-------|-------|----|--------|
84 | PO | RT | // | FRB | XO | Rc | X-Form |
87 RT <- [0] * 32 || SINGLE((FRB))
90 The contents of `FPR[FRB]` are converted to BFP32 by using `SINGLE`, then
91 zero-extended to 64-bits, and the result stored in `GPR[RT]`.
93 Special Registers altered:
101 `mffprs` is equivalent to the combination of `stfs` followed by `lwz`.
107 ## Move To Floating-Point Register
113 | 0-5 | 6-10 | 11-15 | 16-20 | 21-30 | 31 | Form |
114 |-----|------|-------|-------|-------|----|--------|
115 | PO | FRT | // | RB | XO | // | X-Form |
121 The contents of `GPR[RB]` are placed into `FPR[FRT]`.
123 Special Registers altered:
131 `mtfpr` is equivalent to the combination of `std` followed by `lfd`.
135 `mtfpr` is a separate instruction from `mtvsrd` because `mtvsrd` requires
136 VSX which may not be available on simpler implementations.
137 Additionally, SVP64 may treat VSX instructions differently than SFFS
138 instructions in a future version of the architecture.
142 ## Move To Floating-Point Register Single
148 | 0-5 | 6-10 | 11-15 | 16-20 | 21-30 | 31 | Form |
149 |-----|------|-------|-------|-------|----|--------|
150 | PO | FRT | // | RB | XO | // | X-Form |
153 FRT <- DOUBLE((RB)[32:63])
156 The contents of bits 32:63 of `GPR[RB]` are converted to BFP64 by using
157 `DOUBLE`, then the result is stored in `GPR[RT]`.
159 Special Registers altered:
167 `mtfprs` is equivalent to the combination of `stw` followed by `lfs`.
173 # Conversion To/From Floating-Point Register Instructions
175 ## Convert To Floating-Point Register
182 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21-30 | 31 | Form |
183 |-----|------|-------|-------|-------|-------|----|--------|
184 | PO | FRT | IT | // | RB | XO | Rc | X-Form |
187 if IT[0] = 0 then # 32-bit int -> 64-bit float
188 # rounding never necessary, so don't touch FPSCR
189 # based off xvcvsxwdp
190 if IT = 0 then # Signed 32-bit
191 src <- bfp_CONVERT_FROM_SI32((RB)[32:63])
192 else # IT = 1 -- Unsigned 32-bit
193 src <- bfp_CONVERT_FROM_UI32((RB)[32:63])
194 FRT <- bfp64_CONVERT_FROM_BFP(src)
196 # rounding may be necessary. based off xscvuxdsp
199 case(0): # Signed 32-bit
200 src <- bfp_CONVERT_FROM_SI32((RB)[32:63])
201 case(1): # Unsigned 32-bit
202 src <- bfp_CONVERT_FROM_UI32((RB)[32:63])
203 case(2): # Signed 64-bit
204 src <- bfp_CONVERT_FROM_SI64((RB))
205 default: # Unsigned 64-bit
206 src <- bfp_CONVERT_FROM_UI64((RB))
207 rnd <- bfp_ROUND_TO_BFP64(0b0, FPSCR.RN, src)
208 result <- bfp64_CONVERT_FROM_BFP(rnd)
209 cls <- fprf_CLASS_BFP64(result)
211 if xx_flag = 1 then SetFX(FPSCR.XX)
218 <!-- note the PowerISA spec. explicitly has empty lines before/after SetFX,
219 don't remove them -->
221 Convert from a unsigned/signed 32/64-bit integer in RB to a 64-bit
224 If converting from a unsigned/signed 32-bit integer to a 64-bit float,
225 rounding is never necessary, so `FPSCR` is unmodified and exceptions are
226 never raised. Otherwise, `FPSCR` is modified and exceptions are raised
229 Rc=1 tests FRT and sets CR1, exactly like all other Scalar Floating-Point
232 Special Registers altered:
236 FPRF FR FI FX XX (if IT[0]=1)
241 | Assembly Alias | Full Instruction |
242 |--------------------|---------------------|
243 | `ctfprw FRT, RB` | `ctfpr FRT, RB, 0` |
244 | `ctfprw. FRT, RB` | `ctfpr. FRT, RB, 0` |
245 | `ctfpruw FRT, RB` | `ctfpr FRT, RB, 1` |
246 | `ctfpruw. FRT, RB` | `ctfpr. FRT, RB, 1` |
247 | `ctfprd FRT, RB` | `ctfpr FRT, RB, 2` |
248 | `ctfprd. FRT, RB` | `ctfpr. FRT, RB, 2` |
249 | `ctfprud FRT, RB` | `ctfpr FRT, RB, 3` |
250 | `ctfprud. FRT, RB` | `ctfpr. FRT, RB, 3` |
256 ## Convert To Floating-Point Register Single
263 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21-30 | 31 | Form |
264 |-----|------|-------|-------|-------|-------|----|--------|
265 | PO | FRT | IT | // | RB | XO | Rc | X-Form |
268 # rounding may be necessary. based off xscvuxdsp
271 case(0): # Signed 32-bit
272 src <- bfp_CONVERT_FROM_SI32((RB)[32:63])
273 case(1): # Unsigned 32-bit
274 src <- bfp_CONVERT_FROM_UI32((RB)[32:63])
275 case(2): # Signed 64-bit
276 src <- bfp_CONVERT_FROM_SI64((RB))
277 default: # Unsigned 64-bit
278 src <- bfp_CONVERT_FROM_UI64((RB))
279 rnd <- bfp_ROUND_TO_BFP32(FPSCR.RN, src)
280 result32 <- bfp32_CONVERT_FROM_BFP(rnd)
281 cls <- fprf_CLASS_BFP32(result32)
282 result <- DOUBLE(result32)
284 if xx_flag = 1 then SetFX(FPSCR.XX)
291 <!-- note the PowerISA spec. explicitly has empty lines before/after SetFX,
292 don't remove them -->
294 Convert from a unsigned/signed 32/64-bit integer in RB to a 32-bit
295 float in FRT, following the usual 32-bit float in 64-bit float format.
296 `FPSCR` is modified and exceptions are raised as usual.
298 Rc=1 tests FRT and sets CR1, exactly like all other Scalar Floating-Point
301 Special Registers altered:
310 | Assembly Alias | Full Instruction |
311 |---------------------|---------------------|
312 | `ctfprws FRT, RB` | `ctfpr FRT, RB, 0` |
313 | `ctfprws. FRT, RB` | `ctfpr. FRT, RB, 0` |
314 | `ctfpruws FRT, RB` | `ctfpr FRT, RB, 1` |
315 | `ctfpruws. FRT, RB` | `ctfpr. FRT, RB, 1` |
316 | `ctfprds FRT, RB` | `ctfpr FRT, RB, 2` |
317 | `ctfprds. FRT, RB` | `ctfpr. FRT, RB, 2` |
318 | `ctfpruds FRT, RB` | `ctfpr FRT, RB, 3` |
319 | `ctfpruds. FRT, RB` | `ctfpr. FRT, RB, 3` |
325 ## Floating-point to Integer Conversion Overview
327 <div id="fpr-to-gpr-conversion-mode"></div>
329 IEEE 754 doesn't specify what results are obtained when converting a NaN
330 or out-of-range floating-point value to integer, so different programming
331 languages and ISAs have made different choices. Below is an overview
332 of the different variants, listing the languages and hardware that
333 implements each variant.
335 For convenience, those different conversion semantics will be given names
336 based on which common ISA or programming language uses them, since there
337 may not be an established name for them:
339 **Standard OpenPower conversion**
341 This conversion performs "saturation with NaN converted to minimum
342 valid integer". This is also exactly the same as the x86 ISA conversion
343 semantics. OpenPOWER however has instructions for both:
345 * rounding mode read from FPSCR
346 * rounding mode always set to truncate
348 **Java/Saturating conversion**
350 For the sake of simplicity, the FP -> Integer conversion semantics
351 generalized from those used by Java's semantics (and Rust's `as`
352 operator) will be referred to as [Java/Saturating conversion
353 semantics](#fp-to-int-java-saturating-conversion-semantics).
355 Those same semantics are used in some way by all of the following
356 languages (not necessarily for the default conversion method):
359 [FP -> Integer conversion](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3)
360 (only for long/int results)
361 * Rust's FP -> Integer conversion using the
362 [`as` operator](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics)
364 [`llvm.fptosi.sat`](https://llvm.org/docs/LangRef.html#llvm-fptosi-sat-intrinsic) and
365 [`llvm.fptoui.sat`](https://llvm.org/docs/LangRef.html#llvm-fptoui-sat-intrinsic) intrinsics
366 * SPIR-V's OpenCL dialect's
367 [`OpConvertFToU`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToU) and
368 [`OpConvertFToS`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToS)
369 instructions when decorated with
370 [the `SaturatedConversion` decorator](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_decoration_a_decoration).
371 * WebAssembly has also introduced
372 [trunc_sat_u](ttps://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-u) and
373 [trunc_sat_s](https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-s)
375 **JavaScript conversion**
377 For the sake of simplicity, the FP -> Integer conversion
378 semantics generalized from those used by JavaScripts's `ToInt32`
379 abstract operation will be referred to as [JavaScript conversion
380 semantics](#fp-to-int-javascript-conversion-semantics).
382 This instruction is present in ARM assembler as FJCVTZS
383 <https://developer.arm.com/documentation/dui0801/g/hko1477562192868>
387 All of these instructions have an Rc=1 mode which sets CR0
388 in the normal way for any instructions producing a GPR result.
389 Additionally, when OE=1, if the numerical value of the FP number
390 is not 100% accurately preserved (due to truncation or saturation
391 and including when the FP number was NaN) then this is considered
392 to be an integer Overflow condition, and CR0.SO, XER.SO and XER.OV
393 are all set as normal for any GPR instructions that overflow.
397 ### FP to Integer Conversion Simplified Pseudo-code
401 | term | result type | definition |
402 |---------------------------|-------------|-----------------------------------------------------------------------------------------------|
403 | `fp` | -- | `f32` or `f64` (or other types from SimpleV) |
404 | `int` | -- | `u32`/`u64`/`i32`/`i64` (or other types from SimpleV) |
405 | `uint` | -- | the unsigned integer of the same bit-width as `int` |
406 | `int::BITS` | `int` | the bit-width of `int` |
407 | `uint::MIN_VALUE` | `uint` | the minimum value `uint` can store: `0` |
408 | `uint::MAX_VALUE` | `uint` | the maximum value `uint` can store: `2^int::BITS - 1` |
409 | `int::MIN_VALUE` | `int` | the minimum value `int` can store : `-2^(int::BITS-1)` |
410 | `int::MAX_VALUE` | `int` | the maximum value `int` can store : `2^(int::BITS-1) - 1` |
411 | `int::VALUE_COUNT` | Integer | the number of different values `int` can store (`2^int::BITS`). too big to fit in `int`. |
412 | `rint(fp, rounding_mode)` | `fp` | rounds the floating-point value `fp` to an integer according to rounding mode `rounding_mode` |
414 <div id="fp-to-int-openpower-conversion-semantics"></div>
415 OpenPower conversion semantics (section A.2 page 1009 (page 1035) of
419 def fp_to_int_open_power<fp, int>(v: fp) -> int:
421 return int::MIN_VALUE
422 if v >= int::MAX_VALUE:
423 return int::MAX_VALUE
424 if v <= int::MIN_VALUE:
425 return int::MIN_VALUE
426 return (int)rint(v, rounding_mode)
429 <div id="fp-to-int-java-saturating-conversion-semantics"></div>
430 [Java/Saturating conversion semantics](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3)
431 (only for long/int results)
432 (with adjustment to add non-truncate rounding modes):
435 def fp_to_int_java_saturating<fp, int>(v: fp) -> int:
438 if v >= int::MAX_VALUE:
439 return int::MAX_VALUE
440 if v <= int::MIN_VALUE:
441 return int::MIN_VALUE
442 return (int)rint(v, rounding_mode)
445 <div id="fp-to-int-javascript-conversion-semantics"></div>
446 Section 7.1 of the ECMAScript / JavaScript
447 [conversion semantics](https://262.ecma-international.org/11.0/#sec-toint32)
448 (with adjustment to add non-truncate rounding modes):
451 def fp_to_int_java_script<fp, int>(v: fp) -> int:
452 if v is NaN or infinite:
454 v = rint(v, rounding_mode) # assume no loss of precision in result
455 v = v mod int::VALUE_COUNT # 2^32 for i32, 2^64 for i64, result is non-negative
464 ## Convert From Floating-Point Register
467 cffpr RT, FRB, CVM, IT
468 cffpr. RT, FRB, CVM, IT
469 cffpro RT, FRB, CVM, IT
470 cffpro. RT, FRB, CVM, IT
473 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21 | 22-30 | 31 | Form |
474 |-----|------|-------|-------|-------|----|-------|----|---------|
475 | PO | RT | IT | CVM | FRB | OE | XO | Rc | XO-Form |
478 # based on xscvdpuxws
480 src <- bfp_CONVERT_FROM_BFP64((FRB))
483 case(0): # Signed 32-bit
484 range_min <- bfp_CONVERT_FROM_SI32(0x8000_0000)
485 range_max <- bfp_CONVERT_FROM_SI32(0x7FFF_FFFF)
486 js_mask <- 0x0000_0000_FFFF_FFFF
487 case(1): # Unsigned 32-bit
488 range_min <- bfp_CONVERT_FROM_UI32(0)
489 range_max <- bfp_CONVERT_FROM_UI32(0xFFFF_FFFF)
490 js_mask <- 0x0000_0000_FFFF_FFFF
491 case(2): # Signed 64-bit
492 range_min <- bfp_CONVERT_FROM_SI64(-0x8000_0000_0000_0000)
493 range_max <- bfp_CONVERT_FROM_SI64(0x7FFF_FFFF_FFFF_FFFF)
494 js_mask <- 0xFFFF_FFFF_FFFF_FFFF
495 default: # Unsigned 64-bit
496 range_min <- bfp_CONVERT_FROM_UI64(0)
497 range_max <- bfp_CONVERT_FROM_UI64(0xFFFF_FFFF_FFFF_FFFF)
498 js_mask <- 0xFFFF_FFFF_FFFF_FFFF
500 if (CVM[2] = 1) | (FPSCR.RN = 0b01) then
501 rnd <- bfp_ROUND_TO_INTEGER_TRUNC(src)
502 else if FPSCR.RN = 0b00 then
503 rnd <- bfp_ROUND_TO_INTEGER_NEAR_EVEN(src)
504 else if FPSCR.RN = 0b10 then
505 rnd <- bfp_ROUND_TO_INTEGER_CEIL(src)
506 else if FPSCR.RN = 0b11 then
507 rnd <- bfp_ROUND_TO_INTEGER_FLOOR(src)
510 case(0, 1): # OpenPower semantics
512 result <- si64_CONVERT_FROM_BFP(range_min)
513 else if bfp_COMPARE_GT(rnd, range_max) then
514 result <- ui64_CONVERT_FROM_BFP(range_max)
515 else if bfp_COMPARE_LT(rnd, range_min) then
516 result <- si64_CONVERT_FROM_BFP(range_min)
517 else if IT[1] = 1 then # Unsigned 32/64-bit
518 result <- ui64_CONVERT_FROM_BFP(rnd)
519 else # Signed 32/64-bit
520 result <- si64_CONVERT_FROM_BFP(rnd)
521 case(2, 3): # Java/Saturating semantics
524 else if bfp_COMPARE_GT(rnd, range_max) then
525 result <- ui64_CONVERT_FROM_BFP(range_max)
526 else if bfp_COMPARE_LT(rnd, range_min) then
527 result <- si64_CONVERT_FROM_BFP(range_min)
528 else if IT[1] = 1 then # Unsigned 32/64-bit
529 result <- ui64_CONVERT_FROM_BFP(rnd)
530 else # Signed 32/64-bit
531 result <- si64_CONVERT_FROM_BFP(rnd)
532 default: # JavaScript semantics
533 # CVM = 6, 7 are illegal instructions
534 # using a 128-bit intermediate works here because the largest type
535 # this instruction can convert from has 53 significand bits, and
536 # the largest type this instruction can convert to has 64 bits,
537 # and the sum of those is strictly less than the 128 bits of the
538 # intermediate result.
539 limit <- bfp_CONVERT_FROM_UI128([1] * 128)
540 if IsInf(rnd) | IsNaN(rnd) then
542 else if bfp_COMPARE_GT(bfp_ABSOLUTE(rnd), limit) then
545 result128 <- si128_CONVERT_FROM_BFP(rnd)
546 result <- result128[64:127] & js_mask
549 case(0): # Signed 32-bit
550 result <- EXTS64(result[32:63])
551 result_bfp <- bfp_CONVERT_FROM_SI32(result[32:63])
552 case(1): # Unsigned 32-bit
553 result <- EXTZ64(result[32:63])
554 result_bfp <- bfp_CONVERT_FROM_UI32(result[32:63])
555 case(2): # Signed 64-bit
556 result_bfp <- bfp_CONVERT_FROM_SI64(result)
557 default: # Unsigned 64-bit
558 result_bfp <- bfp_CONVERT_FROM_UI64(result)
560 overflow <- 0 # signals SO only when OE = 1
561 if IsNaN(src) | ¬bfp_COMPARE_EQ(rnd, result_bfp) then
562 overflow <- 1 # signals SO only when OE = 1
567 xx_flag <- ¬bfp_COMPARE_EQ(src, result_bfp)
568 inc_flag <- bfp_COMPARE_GT(bfp_ABSOLUTE(result_bfp), bfp_ABSOLUTE(src))
570 if vxsnan_flag = 1 then SetFX(FPSCR.VXSNAN)
571 if vxcvi_flag = 1 then SetFX(FPSCR.VXCVI)
572 if xx_flag = 1 then SetFX(FPSCR.XX)
574 vx_flag <- vxsnan_flag | vxcvi_flag
575 vex_flag <- FPSCR.VE & vx_flag
578 FPSCR.FPRF <- undefined
586 Convert from 64-bit float in FRB to a unsigned/signed 32/64-bit integer
587 in RT, with the conversion overflow/rounding semantics following the
588 chosen `CVM` value. `FPSCR` is modified and exceptions are raised as usual.
590 These instructions have an Rc=1 mode which sets CR0 in the normal
591 way for any instructions producing a GPR result. Additionally, when OE=1,
592 if the numerical value of the FP number is not 100% accurately preserved
593 (due to truncation or saturation and including when the FP number was
594 NaN) then this is considered to be an Integer Overflow condition, and
595 CR0.SO, XER.SO and XER.OV are all set as normal for any GPR instructions
596 that overflow. When `RT` is not written (`vex_flag = 1`), all CR0 bits
597 except SO are undefined.
599 Special Registers altered:
603 XER SO, OV, OV32 (if OE=1)
604 FPRF=0bUUUUU FR FI FX XX VXSNAN VXCV
609 | Assembly Alias | Full Instruction |
610 |--------------------------|---------------------------|
611 | `cffprw RT, FRB, CVM` | `cffpr RT, FRB, CVM, 0` |
612 | `cffprw. RT, FRB, CVM` | `cffpr. RT, FRB, CVM, 0` |
613 | `cffprwo RT, FRB, CVM` | `cffpro RT, FRB, CVM, 0` |
614 | `cffprwo. RT, FRB, CVM` | `cffpro. RT, FRB, CVM, 0` |
615 | `cffpruw RT, FRB, CVM` | `cffpr RT, FRB, CVM, 1` |
616 | `cffpruw. RT, FRB, CVM` | `cffpr. RT, FRB, CVM, 1` |
617 | `cffpruwo RT, FRB, CVM` | `cffpro RT, FRB, CVM, 1` |
618 | `cffpruwo. RT, FRB, CVM` | `cffpro. RT, FRB, CVM, 1` |
619 | `cffprd RT, FRB, CVM` | `cffpr RT, FRB, CVM, 2` |
620 | `cffprd. RT, FRB, CVM` | `cffpr. RT, FRB, CVM, 2` |
621 | `cffprdo RT, FRB, CVM` | `cffpro RT, FRB, CVM, 2` |
622 | `cffprdo. RT, FRB, CVM` | `cffpro. RT, FRB, CVM, 2` |
623 | `cffprud RT, FRB, CVM` | `cffpr RT, FRB, CVM, 3` |
624 | `cffprud. RT, FRB, CVM` | `cffpr. RT, FRB, CVM, 3` |
625 | `cffprudo RT, FRB, CVM` | `cffpro RT, FRB, CVM, 3` |
626 | `cffprudo. RT, FRB, CVM` | `cffpro. RT, FRB, CVM, 3` |