1 <!-- main body for int_fp_mv.mdwn (without fmvis/fishmv) and ls006.mdwn -->
4 Tables that are used by
5 `fmvtg[s][.]`/`fmvfg[s][.]`/`fcvt[s]tg[o][.]`/`fcvtfg[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 `fmvtg` is just copying bits, `FPSCR` is not affected in any way.
58 Rc=1 tests RT and sets CR0, exactly like all other Scalar Fixed-Point
61 Special Registers altered:
69 ## Floating Move To GPR Single
76 | 0-5 | 6-10 | 11-15 | 16-20 | 21-30 | 31 | Form |
77 |-----|------|-------|-------|-------|----|--------|
78 | PO | RT | // | FRB | XO | Rc | X-Form |
81 RT <- [0] * 32 || SINGLE((FRB)) # SINGLE since that's what stfs uses
84 Move a BFP32 from a FPR to a GPR, by using `SINGLE` to extract the standard
85 `BFP32` form from FRB and zero-extending the result to 64-bits and storing to
86 RT. This is equivalent to `stfs` followed by `lwz`.
87 As `fmvtgs` is just copying the BFP32 form, `FPSCR` is not affected in any way.
89 Rc=1 tests RT and sets CR0, exactly like all other Scalar Fixed-Point
92 Special Registers altered:
102 ## Double-Precision Floating Move From GPR
109 | 0-5 | 6-10 | 11-15 | 16-20 | 21-30 | 31 | Form |
110 |-----|------|-------|-------|-------|----|--------|
111 | PO | FRT | // | RB | XO | Rc | X-Form |
117 move a 64-bit float from a GPR to a FPR, just copying bits of the IEEE 754
118 representation directly. This is equivalent to `std` followed by `lfd`.
119 As `fmvfg` is just copying bits, `FPSCR` is not affected in any way.
121 Rc=1 tests FRT and sets CR1, exactly like all other Scalar Floating-Point
124 Special Registers altered:
132 ## Floating Move From GPR Single
139 | 0-5 | 6-10 | 11-15 | 16-20 | 21-30 | 31 | Form |
140 |-----|------|-------|-------|-------|----|--------|
141 | PO | FRT | // | RB | XO | Rc | X-Form |
144 FRT <- DOUBLE((RB)[32:63]) # DOUBLE since that's what lfs uses
147 Move a BFP32 from a GPR to a FPR, by using `DOUBLE` on the least significant
148 32-bits of RB to do the standard BFP32 in BFP64 trick and store the result in
149 FRT. This is equivalent to `stw` followed by `lfs`.
150 As `fmvfgs` is just copying the BFP32 form, `FPSCR` is not affected in any way.
152 Rc=1 tests FRT and sets CR1, exactly like all other Scalar Floating-Point
155 Special Registers altered:
167 Unlike the move instructions
168 these instructions perform conversions between Integer and
169 Floating Point. Truncation can therefore occur, as well
172 ## Double-Precision Floating Convert From Integer In GPR
179 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21-30 | 31 | Form |
180 |-----|------|-------|-------|-------|-------|----|--------|
181 | PO | FRT | IT | // | RB | XO | Rc | X-Form |
184 if IT[0] = 0 then # 32-bit int -> 64-bit float
185 # rounding never necessary, so don't touch FPSCR
186 # based off xvcvsxwdp
187 if IT = 0 then # Signed 32-bit
188 src <- bfp_CONVERT_FROM_SI32((RB)[32:63])
189 else # IT = 1 -- Unsigned 32-bit
190 src <- bfp_CONVERT_FROM_UI32((RB)[32:63])
191 FRT <- bfp64_CONVERT_FROM_BFP(src)
193 # rounding may be necessary. based off xscvuxdsp
196 case(0): # Signed 32-bit
197 src <- bfp_CONVERT_FROM_SI32((RB)[32:63])
198 case(1): # Unsigned 32-bit
199 src <- bfp_CONVERT_FROM_UI32((RB)[32:63])
200 case(2): # Signed 64-bit
201 src <- bfp_CONVERT_FROM_SI64((RB))
202 default: # Unsigned 64-bit
203 src <- bfp_CONVERT_FROM_UI64((RB))
204 rnd <- bfp_ROUND_TO_BFP64(FPSCR.RN, src)
205 result <- bfp64_CONVERT_FROM_BFP(rnd)
206 cls <- fprf_CLASS_BFP64(result)
208 if xx_flag = 1 then SetFX(FPSCR.XX)
215 <!-- note the PowerISA spec. explicitly has empty lines before/after SetFX,
216 don't remove them -->
218 Convert from a unsigned/signed 32/64-bit integer in RB to a 64-bit
221 If converting from a unsigned/signed 32-bit integer to a 64-bit float,
222 rounding is never necessary, so `FPSCR` is unmodified and exceptions are
223 never raised. Otherwise, `FPSCR` is modified and exceptions are raised
226 Rc=1 tests FRT and sets CR1, exactly like all other Scalar Floating-Point
229 Special Registers altered:
233 FPRF FR FI FX XX (if IT[0]=1)
238 | Assembly Alias | Full Instruction |
239 |----------------------|----------------------|
240 | `fcvtfgw FRT, RB` | `fcvtfg FRT, RB, 0` |
241 | `fcvtfgw. FRT, RB` | `fcvtfg. FRT, RB, 0` |
242 | `fcvtfguw FRT, RB` | `fcvtfg FRT, RB, 1` |
243 | `fcvtfguw. FRT, RB` | `fcvtfg. FRT, RB, 1` |
244 | `fcvtfgd FRT, RB` | `fcvtfg FRT, RB, 2` |
245 | `fcvtfgd. FRT, RB` | `fcvtfg. FRT, RB, 2` |
246 | `fcvtfgud FRT, RB` | `fcvtfg FRT, RB, 3` |
247 | `fcvtfgud. FRT, RB` | `fcvtfg. FRT, RB, 3` |
253 ## Floating Convert From Integer In GPR Single
260 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21-30 | 31 | Form |
261 |-----|------|-------|-------|-------|-------|----|--------|
262 | PO | FRT | IT | // | RB | XO | Rc | X-Form |
265 # rounding may be necessary. based off xscvuxdsp
268 case(0): # Signed 32-bit
269 src <- bfp_CONVERT_FROM_SI32((RB)[32:63])
270 case(1): # Unsigned 32-bit
271 src <- bfp_CONVERT_FROM_UI32((RB)[32:63])
272 case(2): # Signed 64-bit
273 src <- bfp_CONVERT_FROM_SI64((RB))
274 default: # Unsigned 64-bit
275 src <- bfp_CONVERT_FROM_UI64((RB))
276 rnd <- bfp_ROUND_TO_BFP32(FPSCR.RN, src)
277 result32 <- bfp32_CONVERT_FROM_BFP(rnd)
278 cls <- fprf_CLASS_BFP32(result32)
279 result <- DOUBLE(result32)
281 if xx_flag = 1 then SetFX(FPSCR.XX)
288 <!-- note the PowerISA spec. explicitly has empty lines before/after SetFX,
289 don't remove them -->
291 Convert from a unsigned/signed 32/64-bit integer in RB to a 32-bit
292 float in FRT, following the usual 32-bit float in 64-bit float format.
293 `FPSCR` is modified and exceptions are raised as usual.
295 Rc=1 tests FRT and sets CR1, exactly like all other Scalar Floating-Point
298 Special Registers altered:
307 | Assembly Alias | Full Instruction |
308 |----------------------|----------------------|
309 | `fcvtfgws FRT, RB` | `fcvtfg FRT, RB, 0` |
310 | `fcvtfgws. FRT, RB` | `fcvtfg. FRT, RB, 0` |
311 | `fcvtfguws FRT, RB` | `fcvtfg FRT, RB, 1` |
312 | `fcvtfguws. FRT, RB` | `fcvtfg. FRT, RB, 1` |
313 | `fcvtfgds FRT, RB` | `fcvtfg FRT, RB, 2` |
314 | `fcvtfgds. FRT, RB` | `fcvtfg. FRT, RB, 2` |
315 | `fcvtfguds FRT, RB` | `fcvtfg FRT, RB, 3` |
316 | `fcvtfguds. FRT, RB` | `fcvtfg. FRT, RB, 3` |
322 ## Floating-point to Integer Conversion Overview
324 <div id="fpr-to-gpr-conversion-mode"></div>
326 IEEE 754 doesn't specify what results are obtained when converting a NaN
327 or out-of-range floating-point value to integer, so different programming
328 languages and ISAs have made different choices. Below is an overview
329 of the different variants, listing the languages and hardware that
330 implements each variant.
332 For convenience, we will give those different conversion semantics names
333 based on which common ISA or programming language uses them, since there
334 may not be an established name for them:
336 **Standard OpenPower conversion**
338 This conversion performs "saturation with NaN converted to minimum
339 valid integer". This is also exactly the same as the x86 ISA conversion
340 semantics. OpenPOWER however has instructions for both:
342 * rounding mode read from FPSCR
343 * rounding mode always set to truncate
345 **Java/Saturating conversion**
347 For the sake of simplicity, the FP -> Integer conversion semantics
348 generalized from those used by Java's semantics (and Rust's `as`
349 operator) will be referred to as [Java/Saturating conversion
350 semantics](#fp-to-int-java-saturating-conversion-semantics).
352 Those same semantics are used in some way by all of the following
353 languages (not necessarily for the default conversion method):
356 [FP -> Integer conversion](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3)
357 (only for long/int results)
358 * Rust's FP -> Integer conversion using the
359 [`as` operator](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics)
361 [`llvm.fptosi.sat`](https://llvm.org/docs/LangRef.html#llvm-fptosi-sat-intrinsic) and
362 [`llvm.fptoui.sat`](https://llvm.org/docs/LangRef.html#llvm-fptoui-sat-intrinsic) intrinsics
363 * SPIR-V's OpenCL dialect's
364 [`OpConvertFToU`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToU) and
365 [`OpConvertFToS`](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpConvertFToS)
366 instructions when decorated with
367 [the `SaturatedConversion` decorator](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_decoration_a_decoration).
368 * WebAssembly has also introduced
369 [trunc_sat_u](ttps://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-u) and
370 [trunc_sat_s](https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-sat-s)
372 **JavaScript conversion**
374 For the sake of simplicity, the FP -> Integer conversion
375 semantics generalized from those used by JavaScripts's `ToInt32`
376 abstract operation will be referred to as [JavaScript conversion
377 semantics](#fp-to-int-javascript-conversion-semantics).
379 This instruction is present in ARM assembler as FJCVTZS
380 <https://developer.arm.com/documentation/dui0801/g/hko1477562192868>
384 All of these instructions have an Rc=1 mode which sets CR0
385 in the normal way for any instructions producing a GPR result.
386 Additionally, when OE=1, if the numerical value of the FP number
387 is not 100% accurately preserved (due to truncation or saturation
388 and including when the FP number was NaN) then this is considered
389 to be an integer Overflow condition, and CR0.SO, XER.SO and XER.OV
390 are all set as normal for any GPR instructions that overflow.
394 ### FP to Integer Conversion Simplified Pseudo-code
398 | term | result type | definition |
399 |---------------------------|-------------|----------------------------------------------------------------------------------------------------|
400 | `fp` | -- | `f32` or `f64` (or other types from SimpleV) |
401 | `int` | -- | `u32`/`u64`/`i32`/`i64` (or other types from SimpleV) |
402 | `uint` | -- | the unsigned integer of the same bit-width as `int` |
403 | `int::BITS` | `int` | the bit-width of `int` |
404 | `uint::MIN_VALUE` | `uint` | the minimum value `uint` can store: `0` |
405 | `uint::MAX_VALUE` | `uint` | the maximum value `uint` can store: `2^int::BITS - 1` |
406 | `int::MIN_VALUE` | `int` | the minimum value `int` can store : `-2^(int::BITS-1)` |
407 | `int::MAX_VALUE` | `int` | the maximum value `int` can store : `2^(int::BITS-1) - 1` |
408 | `int::VALUE_COUNT` | Integer | the number of different values `int` can store (`2^int::BITS`). too big to fit in `int`. |
409 | `rint(fp, rounding_mode)` | `fp` | rounds the floating-point value `fp` to an integer according to rounding mode `rounding_mode` |
411 <div id="fp-to-int-openpower-conversion-semantics"></div>
412 OpenPower conversion semantics (section A.2 page 1009 (page 1035) of
416 def fp_to_int_open_power<fp, int>(v: fp) -> int:
418 return int::MIN_VALUE
419 if v >= int::MAX_VALUE:
420 return int::MAX_VALUE
421 if v <= int::MIN_VALUE:
422 return int::MIN_VALUE
423 return (int)rint(v, rounding_mode)
426 <div id="fp-to-int-java-saturating-conversion-semantics"></div>
427 [Java/Saturating conversion semantics](https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.3)
428 (only for long/int results)
429 (with adjustment to add non-truncate rounding modes):
432 def fp_to_int_java_saturating<fp, int>(v: fp) -> int:
435 if v >= int::MAX_VALUE:
436 return int::MAX_VALUE
437 if v <= int::MIN_VALUE:
438 return int::MIN_VALUE
439 return (int)rint(v, rounding_mode)
442 <div id="fp-to-int-javascript-conversion-semantics"></div>
443 Section 7.1 of the ECMAScript / JavaScript
444 [conversion semantics](https://262.ecma-international.org/11.0/#sec-toint32)
445 (with adjustment to add non-truncate rounding modes):
448 def fp_to_int_java_script<fp, int>(v: fp) -> int:
449 if v is NaN or infinite:
451 v = rint(v, rounding_mode) # assume no loss of precision in result
452 v = v mod int::VALUE_COUNT # 2^32 for i32, 2^64 for i64, result is non-negative
461 ## Double-Precision Floating Convert To Integer In GPR
464 fcvttg RT, FRB, CVM, IT
465 fcvttg. RT, FRB, CVM, IT
466 fcvttgo RT, FRB, CVM, IT
467 fcvttgo. RT, FRB, CVM, IT
470 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21 | 22-30 | 31 | Form |
471 |-----|------|-------|-------|-------|----|-------|----|---------|
472 | PO | RT | IT | CVM | FRB | OE | XO | Rc | XO-Form |
475 # based on xscvdpuxws
477 src <- bfp_CONVERT_FROM_BFP64((FRB))
480 case(0): # Signed 32-bit
481 range_min <- bfp_CONVERT_FROM_SI32(0x8000_0000)
482 range_max <- bfp_CONVERT_FROM_SI32(0x7FFF_FFFF)
483 js_mask <- 0x0000_0000_FFFF_FFFF
484 case(1): # Unsigned 32-bit
485 range_min <- bfp_CONVERT_FROM_UI32(0)
486 range_max <- bfp_CONVERT_FROM_UI32(0xFFFF_FFFF)
487 js_mask <- 0x0000_0000_FFFF_FFFF
488 case(2): # Signed 64-bit
489 range_min <- bfp_CONVERT_FROM_SI64(-0x8000_0000_0000_0000)
490 range_max <- bfp_CONVERT_FROM_SI64(0x7FFF_FFFF_FFFF_FFFF)
491 js_mask <- 0xFFFF_FFFF_FFFF_FFFF
492 default: # Unsigned 64-bit
493 range_min <- bfp_CONVERT_FROM_UI64(0)
494 range_max <- bfp_CONVERT_FROM_UI64(0xFFFF_FFFF_FFFF_FFFF)
495 js_mask <- 0xFFFF_FFFF_FFFF_FFFF
497 if (CVM[2] = 1) | (FPSCR.RN = 0b01) then
498 rnd <- bfp_ROUND_TO_INTEGER_TRUNC(src)
499 else if FPSCR.RN = 0b00 then
500 rnd <- bfp_ROUND_TO_INTEGER_NEAR_EVEN(src)
501 else if FPSCR.RN = 0b10 then
502 rnd <- bfp_ROUND_TO_INTEGER_CEIL(src)
503 else if FPSCR.RN = 0b11 then
504 rnd <- bfp_ROUND_TO_INTEGER_FLOOR(src)
507 case(0, 1): # OpenPower semantics
509 result <- si64_CONVERT_FROM_BFP(range_min)
510 else if bfp_COMPARE_GT(rnd, range_max) then
511 result <- ui64_CONVERT_FROM_BFP(range_max)
512 else if bfp_COMPARE_LT(rnd, range_min) then
513 result <- si64_CONVERT_FROM_BFP(range_min)
514 else if IT[1] = 1 then # Unsigned 32/64-bit
515 result <- ui64_CONVERT_FROM_BFP(range_max)
516 else # Signed 32/64-bit
517 result <- si64_CONVERT_FROM_BFP(range_max)
518 case(2, 3): # Java/Saturating semantics
521 else if bfp_COMPARE_GT(rnd, range_max) then
522 result <- ui64_CONVERT_FROM_BFP(range_max)
523 else if bfp_COMPARE_LT(rnd, range_min) then
524 result <- si64_CONVERT_FROM_BFP(range_min)
525 else if IT[1] = 1 then # Unsigned 32/64-bit
526 result <- ui64_CONVERT_FROM_BFP(range_max)
527 else # Signed 32/64-bit
528 result <- si64_CONVERT_FROM_BFP(range_max)
529 default: # JavaScript semantics
530 # CVM = 6, 7 are illegal instructions
531 # this works because the largest type we try to convert from has
532 # 53 significand bits, and the largest type we try to convert to
533 # has 64 bits, and the sum of those is strictly less than the 128
534 # bits of the intermediate result.
535 limit <- bfp_CONVERT_FROM_UI128([1] * 128)
536 if IsInf(rnd) | IsNaN(rnd) then
538 else if bfp_COMPARE_GT(bfp_ABSOLUTE(rnd), limit) then
541 result128 <- si128_CONVERT_FROM_BFP(rnd)
542 result <- result128[64:127] & js_mask
545 case(0): # Signed 32-bit
546 result <- EXTS64(result[32:63])
547 result_bfp <- bfp_CONVERT_FROM_SI32(result[32:63])
548 case(1): # Unsigned 32-bit
549 result <- EXTZ64(result[32:63])
550 result_bfp <- bfp_CONVERT_FROM_UI32(result[32:63])
551 case(2): # Signed 64-bit
552 result_bfp <- bfp_CONVERT_FROM_SI64(result)
553 default: # Unsigned 64-bit
554 result_bfp <- bfp_CONVERT_FROM_UI64(result)
556 overflow <- 0 # signals SO only when OE = 1
557 if IsNaN(src) | ¬bfp_COMPARE_EQ(rnd, result_bfp) then
558 overflow <- 1 # signals SO only when OE = 1
561 else if ¬bfp_COMPARE_EQ(src, result_bfp) then
564 if vxsnan_flag = 1 then SetFX(FPSCR.VXSNAN)
565 if vxcvi_flag = 1 then SetFX(FPSCR.VXCVI)
566 if xx_flag = 1 then SetFX(FPSCR.XX)
568 vx_flag <- vxsnan_flag | vxcvi_flag
569 vex_flag <- FPSCR.VE & vx_flag
572 FPSCR.FPRF <- undefined
580 Convert from 64-bit float in FRB to a unsigned/signed 32/64-bit integer
581 in RT, with the conversion overflow/rounding semantics following the
582 chosen `CVM` value. `FPSCR` is modified and exceptions are raised as usual.
584 These instructions have an Rc=1 mode which sets CR0 in the normal
585 way for any instructions producing a GPR result. Additionally, when OE=1,
586 if the numerical value of the FP number is not 100% accurately preserved
587 (due to truncation or saturation and including when the FP number was
588 NaN) then this is considered to be an Integer Overflow condition, and
589 CR0.SO, XER.SO and XER.OV are all set as normal for any GPR instructions
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 | `fcvttgw RT, FRB, CVM` | `fcvttg RT, FRB, CVM, 0` |
605 | `fcvttgw. RT, FRB, CVM` | `fcvttg. RT, FRB, CVM, 0` |
606 | `fcvttgwo RT, FRB, CVM` | `fcvttgo RT, FRB, CVM, 0` |
607 | `fcvttgwo. RT, FRB, CVM` | `fcvttgo. RT, FRB, CVM, 0` |
608 | `fcvttguw RT, FRB, CVM` | `fcvttg RT, FRB, CVM, 1` |
609 | `fcvttguw. RT, FRB, CVM` | `fcvttg. RT, FRB, CVM, 1` |
610 | `fcvttguwo RT, FRB, CVM` | `fcvttgo RT, FRB, CVM, 1` |
611 | `fcvttguwo. RT, FRB, CVM` | `fcvttgo. RT, FRB, CVM, 1` |
612 | `fcvttgd RT, FRB, CVM` | `fcvttg RT, FRB, CVM, 2` |
613 | `fcvttgd. RT, FRB, CVM` | `fcvttg. RT, FRB, CVM, 2` |
614 | `fcvttgdo RT, FRB, CVM` | `fcvttgo RT, FRB, CVM, 2` |
615 | `fcvttgdo. RT, FRB, CVM` | `fcvttgo. RT, FRB, CVM, 2` |
616 | `fcvttgud RT, FRB, CVM` | `fcvttg RT, FRB, CVM, 3` |
617 | `fcvttgud. RT, FRB, CVM` | `fcvttg. RT, FRB, CVM, 3` |
618 | `fcvttgudo RT, FRB, CVM` | `fcvttgo RT, FRB, CVM, 3` |
619 | `fcvttgudo. RT, FRB, CVM` | `fcvttgo. RT, FRB, CVM, 3` |
625 ## Floating Convert Single To Integer In GPR
628 fcvtstg RT, FRB, CVM, IT
629 fcvtstg. RT, FRB, CVM, IT
630 fcvtstgo RT, FRB, CVM, IT
631 fcvtstgo. RT, FRB, CVM, IT
634 | 0-5 | 6-10 | 11-12 | 13-15 | 16-20 | 21 | 22-30 | 31 | Form |
635 |-----|------|-------|-------|-------|----|-------|----|---------|
636 | PO | RT | IT | CVM | FRB | OE | XO | Rc | XO-Form |
639 # based on xscvdpuxws
641 src <- bfp_CONVERT_FROM_BFP32(SINGLE((FRB)))
644 case(0): # Signed 32-bit
645 range_min <- bfp_CONVERT_FROM_SI32(0x8000_0000)
646 range_max <- bfp_CONVERT_FROM_SI32(0x7FFF_FFFF)
647 js_mask <- 0x0000_0000_FFFF_FFFF
648 case(1): # Unsigned 32-bit
649 range_min <- bfp_CONVERT_FROM_UI32(0)
650 range_max <- bfp_CONVERT_FROM_UI32(0xFFFF_FFFF)
651 js_mask <- 0x0000_0000_FFFF_FFFF
652 case(2): # Signed 64-bit
653 range_min <- bfp_CONVERT_FROM_SI64(-0x8000_0000_0000_0000)
654 range_max <- bfp_CONVERT_FROM_SI64(0x7FFF_FFFF_FFFF_FFFF)
655 js_mask <- 0xFFFF_FFFF_FFFF_FFFF
656 default: # Unsigned 64-bit
657 range_min <- bfp_CONVERT_FROM_UI64(0)
658 range_max <- bfp_CONVERT_FROM_UI64(0xFFFF_FFFF_FFFF_FFFF)
659 js_mask <- 0xFFFF_FFFF_FFFF_FFFF
661 if (CVM[2] = 1) | (FPSCR.RN = 0b01) then
662 rnd <- bfp_ROUND_TO_INTEGER_TRUNC(src)
663 else if FPSCR.RN = 0b00 then
664 rnd <- bfp_ROUND_TO_INTEGER_NEAR_EVEN(src)
665 else if FPSCR.RN = 0b10 then
666 rnd <- bfp_ROUND_TO_INTEGER_CEIL(src)
667 else if FPSCR.RN = 0b11 then
668 rnd <- bfp_ROUND_TO_INTEGER_FLOOR(src)
671 case(0, 1): # OpenPower semantics
673 result <- si64_CONVERT_FROM_BFP(range_min)
674 else if bfp_COMPARE_GT(rnd, range_max) then
675 result <- ui64_CONVERT_FROM_BFP(range_max)
676 else if bfp_COMPARE_LT(rnd, range_min) then
677 result <- si64_CONVERT_FROM_BFP(range_min)
678 else if IT[1] = 1 then # Unsigned 32/64-bit
679 result <- ui64_CONVERT_FROM_BFP(range_max)
680 else # Signed 32/64-bit
681 result <- si64_CONVERT_FROM_BFP(range_max)
682 case(2, 3): # Java/Saturating semantics
685 else if bfp_COMPARE_GT(rnd, range_max) then
686 result <- ui64_CONVERT_FROM_BFP(range_max)
687 else if bfp_COMPARE_LT(rnd, range_min) then
688 result <- si64_CONVERT_FROM_BFP(range_min)
689 else if IT[1] = 1 then # Unsigned 32/64-bit
690 result <- ui64_CONVERT_FROM_BFP(range_max)
691 else # Signed 32/64-bit
692 result <- si64_CONVERT_FROM_BFP(range_max)
693 default: # JavaScript semantics
694 # CVM = 6, 7 are illegal instructions
695 # this works because the largest type we try to convert from has
696 # 53 significand bits, and the largest type we try to convert to
697 # has 64 bits, and the sum of those is strictly less than the 128
698 # bits of the intermediate result.
699 limit <- bfp_CONVERT_FROM_UI128([1] * 128)
700 if IsInf(rnd) | IsNaN(rnd) then
702 else if bfp_COMPARE_GT(bfp_ABSOLUTE(rnd), limit) then
705 result128 <- si128_CONVERT_FROM_BFP(rnd)
706 result <- result128[64:127] & js_mask
709 case(0): # Signed 32-bit
710 result <- EXTS64(result[32:63])
711 result_bfp <- bfp_CONVERT_FROM_SI32(result[32:63])
712 case(1): # Unsigned 32-bit
713 result <- EXTZ64(result[32:63])
714 result_bfp <- bfp_CONVERT_FROM_UI32(result[32:63])
715 case(2): # Signed 64-bit
716 result_bfp <- bfp_CONVERT_FROM_SI64(result)
717 default: # Unsigned 64-bit
718 result_bfp <- bfp_CONVERT_FROM_UI64(result)
720 overflow <- 0 # signals SO only when OE = 1
721 if IsNaN(src) | ¬bfp_COMPARE_EQ(rnd, result_bfp) then
722 overflow <- 1 # signals SO only when OE = 1
725 else if ¬bfp_COMPARE_EQ(src, result_bfp) then
728 if vxsnan_flag = 1 then SetFX(FPSCR.VXSNAN)
729 if vxcvi_flag = 1 then SetFX(FPSCR.VXCVI)
730 if xx_flag = 1 then SetFX(FPSCR.XX)
732 vx_flag <- vxsnan_flag | vxcvi_flag
733 vex_flag <- FPSCR.VE & vx_flag
736 FPSCR.FPRF <- undefined
744 Convert from 32-bit float in FRB to a unsigned/signed 32/64-bit integer
745 in RT, with the conversion overflow/rounding semantics following the
746 chosen `CVM` value, following the usual 32-bit float in 64-bit float
747 format. `FPSCR` is modified and exceptions are raised as usual.
749 These instructions have an Rc=1 mode which sets CR0 in the normal
750 way for any instructions producing a GPR result. Additionally, when OE=1,
751 if the numerical value of the FP number is not 100% accurately preserved
752 (due to truncation or saturation and including when the FP number was
753 NaN) then this is considered to be an Integer Overflow condition, and
754 CR0.SO, XER.SO and XER.OV are all set as normal for any GPR instructions
757 Special Registers altered:
761 XER SO, OV, OV32 (if OE=1)
762 FPRF=0bUUUUU FR FI FX XX VXSNAN VXCV
767 | Assembly Alias | Full Instruction |
768 |----------------------------|-----------------------------|
769 | `fcvtstgw RT, FRB, CVM` | `fcvtstg RT, FRB, CVM, 0` |
770 | `fcvtstgw. RT, FRB, CVM` | `fcvtstg. RT, FRB, CVM, 0` |
771 | `fcvtstgwo RT, FRB, CVM` | `fcvtstgo RT, FRB, CVM, 0` |
772 | `fcvtstgwo. RT, FRB, CVM` | `fcvtstgo. RT, FRB, CVM, 0` |
773 | `fcvtstguw RT, FRB, CVM` | `fcvtstg RT, FRB, CVM, 1` |
774 | `fcvtstguw. RT, FRB, CVM` | `fcvtstg. RT, FRB, CVM, 1` |
775 | `fcvtstguwo RT, FRB, CVM` | `fcvtstgo RT, FRB, CVM, 1` |
776 | `fcvtstguwo. RT, FRB, CVM` | `fcvtstgo. RT, FRB, CVM, 1` |
777 | `fcvtstgd RT, FRB, CVM` | `fcvtstg RT, FRB, CVM, 2` |
778 | `fcvtstgd. RT, FRB, CVM` | `fcvtstg. RT, FRB, CVM, 2` |
779 | `fcvtstgdo RT, FRB, CVM` | `fcvtstgo RT, FRB, CVM, 2` |
780 | `fcvtstgdo. RT, FRB, CVM` | `fcvtstgo. RT, FRB, CVM, 2` |
781 | `fcvtstgud RT, FRB, CVM` | `fcvtstg RT, FRB, CVM, 3` |
782 | `fcvtstgud. RT, FRB, CVM` | `fcvtstg. RT, FRB, CVM, 3` |
783 | `fcvtstgudo RT, FRB, CVM` | `fcvtstgo RT, FRB, CVM, 3` |
784 | `fcvtstgudo. RT, FRB, CVM` | `fcvtstgo. RT, FRB, CVM, 3` |