3 # SVP64 polymorphic elwidth overrides
5 SimpleV, the Draft Cray-style Vectorization for OpenPOWER, may
6 independently override both or either of the source or destination
7 register bitwidth in the base operation used to create the Vector
8 operation. In the case of IEEE754 FP operands this gives an
9 opportunity to add `FP16` as well.as `BF16` to the Power ISA
10 with no actual new Scalar opcodes.
12 However there is the potential for confusion as to the definition
13 of what Single and Double mean when the operand width has been
14 over-ridden. Simple-V therefore sets the following
15 "reinterpretation" rules:
17 * any operation whose assembler mnemonic does not end in "s"
18 (being defined in v3.0B as a "double" operation) is
19 instead an operation at the overridden elwidth for the
20 relevant operand, instead of a 64 bit "Double"
21 * any operation nominally defined as a "single" FP operation
22 is redefined to be **half the elwidth** rather than
23 "half of 64 bit" (32 bit, aka "Single")
27 * `sv.fmvtg/sw=32 RT.v, FRA.v` is defined as treating FRA
28 as a vector of *FP32* source operands each *32* bits wide
29 which are to be placed into *64* bit integer destination elements.
30 * `sv.fmvfgs/dw=32 FRT.v, RA.v` is defined as taking the bottom
31 32 bits of each RA integer source, then performing a **32 bit**
32 FP32 to **FP16** conversion and storing the result in the
33 **32 bits** of an FRT destination element.
35 "Single" is therefore redefined in SVP64 to be "half elwidth"
36 rather than Double width hardcoded to 64 and Single width
37 hardcoded to 32. This allows a full range of conversions
38 between FP64, FP32, FP16 and BF16.
40 Note however that attempts to perform "Single" operations on
41 FP16 elwidths will raise an illegal instruction trap: Half
42 of FP16 is FP8, which is not defined as a legal IEEE754 format.
44 # Simple-V SVP64 Saturation
46 SVP64 also allows for Saturation, such that the result is truncated
47 to the maximum or minimum range of the result operand rather than
50 There will be some interaction here with Conversion routines which
51 will need careful application of the SVP64 Saturation rules: some
52 work will be duplicated by the operation itself, but in some cases
53 it will change the result.
55 The critical thing to note is that SVP64 Saturation is to be considered
56 as the "priority override" where the operation should take place at
57 "Infinite bitwidth followed by a result post-analysis phase".
59 Thus if by chance an unsigned conversion to INT was carried out,
60 with a destination override to 16 bit results, in combination
61 with a **signed** SVP64 Saturation override, the result would
62 be truncated to within the range 0 to 0x7FFF. The actual
63 operation itself, being an *Unsigned* conversion, would set the
64 minimum value to zero, whilst the SVP64 *Signed* Saturation
65 would set the maximum to a Signed 16 bit integer.
67 As always with SVP64, some thought and care has to be put into
68 how the override behaviour will interact with the base scalar
71 # Power ISA v3.0 Assembly Equivalents<a name="assembler"></a>
73 Demonstration of how much assembler is needed if these Language-specific
74 FP -> Integer Conversion Modes are not available
76 ## c (IEEE754 standard compliant)
79 int32_t toInt32(double number)
81 uint32_t result = (int32_t)number;
86 ### 64-bit float -> 32-bit signed integer
103 pub fn fcvttgd_rust(v: f64) -> i64 {
107 pub fn fcvttgud_rust(v: f64) -> u64 {
111 pub fn fcvttgw_rust(v: f64) -> i32 {
115 pub fn fcvttguw_rust(v: f64) -> u32 {
120 ### 64-bit float -> 64-bit signed integer
126 .quad 0x43dfffffffffffff
127 example::fcvttgd_rust:
129 addis 2, 12, .TOC.-.Lfunc_gep0@ha
130 addi 2, 2, .TOC.-.Lfunc_gep0@l
131 addis 3, 2, .LCPI0_0@toc@ha
136 lfs 0, .LCPI0_0@toc@l(3)
137 addis 3, 2, .LCPI0_1@toc@ha
140 lfd 0, .LCPI0_1@toc@l(3)
154 ### 64-bit float -> 64-bit unsigned integer
160 .quad 0x43efffffffffffff
161 example::fcvttgud_rust:
163 addis 2, 12, .TOC.-.Lfunc_gep1@ha
164 addi 2, 2, .TOC.-.Lfunc_gep1@l
165 addis 3, 2, .LCPI1_0@toc@ha
168 lfs 0, .LCPI1_0@toc@l(3)
169 addis 3, 2, .LCPI1_1@toc@ha
171 lfd 0, .LCPI1_1@toc@l(3)
183 ### 64-bit float -> 32-bit signed integer
189 .quad 0x41dfffffffc00000
190 example::fcvttgw_rust:
192 addis 2, 12, .TOC.-.Lfunc_gep2@ha
193 addi 2, 2, .TOC.-.Lfunc_gep2@l
194 addis 3, 2, .LCPI2_0@toc@ha
198 lfs 0, .LCPI2_0@toc@l(3)
199 addis 3, 2, .LCPI2_1@toc@ha
201 lfd 0, .LCPI2_1@toc@l(3)
217 ### 64-bit float -> 32-bit unsigned integer
223 .quad 0x41efffffffe00000
224 example::fcvttguw_rust:
226 addis 2, 12, .TOC.-.Lfunc_gep3@ha
227 addi 2, 2, .TOC.-.Lfunc_gep3@l
228 addis 3, 2, .LCPI3_0@toc@ha
231 lfs 0, .LCPI3_0@toc@l(3)
232 addis 3, 2, .LCPI3_1@toc@ha
234 lfd 0, .LCPI3_1@toc@l(3)
253 template<typename Target, typename Src>
254 inline Target bitwise_cast(Src v) {
261 int32_t missingOne = 1 << exp;
262 result &= missingOne - 1;
263 result += missingOne;
266 // If the input value was negative (we could test either 'number' or 'bits',
267 // but testing 'bits' is likely faster) invert the result appropriately.
268 return bits < 0 ? -result : result;
272 ### 64-bit float -> 32-bit signed integer
312 .byte 0,9,0,0,0,0,0,0