1 # SimpleV SVP64 polymorphic element width overrides
3 SimpleV, the Draft Cray-style Vectorisation for OpenPOWER, may
4 independently override both or either of the source or destination
5 register bitwidth in the base operation used to create the Vector
6 operation. In the case of IEEE754 FP operands this gives an
7 opportunity to add `FP16` as well.as `BF16` to the Power ISA
8 with no actual new Scalar opcodes.
10 However there is the potential for confusion as to the definition
11 of what Single and Double mean when the operand width has been
12 over-ridden. Simple-V therefore sets the following
13 "reinterpretation" rules:
15 * any operation whose assembler mnemonic does not end in "s"
16 (being defined in v3.0B as a "double" operation) is
17 instead an operation at the overridden elwidth for the
18 relevant operand, instead of a 64 bit "Double"
19 * any operation nominally defined as a "single" FP operation
20 is redefined to be **half the elwidth** rather than
21 "half of 64 bit" (32 bit, aka "Single")
25 * `sv.fmvtg/sw=32 RT.v, FRA.v` is defined as treating FRA
26 as a vector of *FP32* source operands each *32* bits wide
27 which are to be placed into *64* bit integer destination elements.
28 * `sv.fmvfgs/dw=32 FRT.v, RA.v` is defined as taking the bottom
29 32 bits of each RA integer source, then performing a **32 bit**
30 FP32 to **FP16** conversion and storing the result in the
31 **32 bits** of an FRT destination element.
33 "Single" is therefore redefined in SVP64 to be "half elwidth"
34 rather than Double width hardcoded to 64 and Single width
35 hardcoded to 32. This allows a full range of conversions
36 between FP64, FP32, FP16 and BF16.
38 Note however that attempts to perform "Single" operations on
39 FP16 elwidths will raise an illegal instruction trap: Half
40 of FP16 is FP8, which is not defined as a legal IEEE754 format.
42 # Simple-V SVP64 Saturation
44 SVP64 also allows for Saturation, such that the result is truncated
45 to the maximum or minimum range of the result operand rather than
48 There will be some interaction here with Conversion routines which
49 will need careful application of the SVP64 Saturation rules: some
50 work will be duplicated by the operation itself, but in some cases
51 it will change the result.
53 The critical thing to note is that SVP64 Saturation is to be considered
54 as the "priority override" where the operation should take place at
55 "Infinite bitwidth followed by a result post-analysis phase".
57 Thus if by chance an unsigned conversion to INT was carried out,
58 with a destination override to 16 bit results, in combination
59 with a **signed** SVP64 Saturation override, the result would
60 be truncated to within the range 0 to 0x7FFF. The actual
61 operation itself, being an *Unsigned* conversion, would set the
62 minimum value to zero, whilst the SVP64 *Signed* Saturation
63 would set the maximum to a Signed 16 bit integer.
65 As always with SVP64, some thought and care has to be put into
66 how the override behaviour will interact with the base scalar
69 # Equivalent OpenPower ISA v3.0 Assembly Language for FP -> Integer Conversion Modes
71 ## c (IEEE754 standard compliant)
74 int32_t toInt32(double number)
76 uint32_t result = (int32_t)number;
81 ### 64-bit float -> 32-bit signed integer
97 ```pub fn fcvttgd_rust(v: f64) -> i64 {
101 pub fn fcvttgud_rust(v: f64) -> u64 {
105 pub fn fcvttgw_rust(v: f64) -> i32 {
109 pub fn fcvttguw_rust(v: f64) -> u32 {
114 ### 64-bit float -> 64-bit signed integer
120 .quad 0x43dfffffffffffff
121 example::fcvttgd_rust:
123 addis 2, 12, .TOC.-.Lfunc_gep0@ha
124 addi 2, 2, .TOC.-.Lfunc_gep0@l
125 addis 3, 2, .LCPI0_0@toc@ha
130 lfs 0, .LCPI0_0@toc@l(3)
131 addis 3, 2, .LCPI0_1@toc@ha
134 lfd 0, .LCPI0_1@toc@l(3)
148 ### 64-bit float -> 64-bit unsigned integer
154 .quad 0x43efffffffffffff
155 example::fcvttgud_rust:
157 addis 2, 12, .TOC.-.Lfunc_gep1@ha
158 addi 2, 2, .TOC.-.Lfunc_gep1@l
159 addis 3, 2, .LCPI1_0@toc@ha
162 lfs 0, .LCPI1_0@toc@l(3)
163 addis 3, 2, .LCPI1_1@toc@ha
165 lfd 0, .LCPI1_1@toc@l(3)
177 ### 64-bit float -> 32-bit signed integer
183 .quad 0x41dfffffffc00000
184 example::fcvttgw_rust:
186 addis 2, 12, .TOC.-.Lfunc_gep2@ha
187 addi 2, 2, .TOC.-.Lfunc_gep2@l
188 addis 3, 2, .LCPI2_0@toc@ha
192 lfs 0, .LCPI2_0@toc@l(3)
193 addis 3, 2, .LCPI2_1@toc@ha
195 lfd 0, .LCPI2_1@toc@l(3)
211 ### 64-bit float -> 32-bit unsigned integer
217 .quad 0x41efffffffe00000
218 example::fcvttguw_rust:
220 addis 2, 12, .TOC.-.Lfunc_gep3@ha
221 addi 2, 2, .TOC.-.Lfunc_gep3@l
222 addis 3, 2, .LCPI3_0@toc@ha
225 lfs 0, .LCPI3_0@toc@l(3)
226 addis 3, 2, .LCPI3_1@toc@ha
228 lfd 0, .LCPI3_1@toc@l(3)
247 template<typename Target, typename Src>
248 inline Target bitwise_cast(Src v) {
255 int32_t missingOne = 1 << exp;
256 result &= missingOne - 1;
257 result += missingOne;
260 // If the input value was negative (we could test either 'number' or 'bits',
261 // but testing 'bits' is likely faster) invert the result appropriately.
262 return bits < 0 ? -result : result;
266 ### 64-bit float -> 32-bit signed integer
306 .byte 0,9,0,0,0,0,0,0