(no commit message)
[libreriscv.git] / openpower / sv / normal.mdwn
1 # Normal SVP64 Modes, for Arithmetic and Logical Operations
2
3 * <https://bugs.libre-soc.org/show_bug.cgi?id=574>
4 * <https://bugs.libre-soc.org/show_bug.cgi?id=558#c47>
5 * <https://bugs.libre-soc.org/show_bug.cgi?id=936> write on failfirst
6 * [[svp64]]
7
8 Normal SVP64 Mode covers Arithmetic and Logical operations
9 to provide suitable additional behaviour. The Mode
10 field is bits 19-23 of the [[svp64]] RM Field.
11
12 Table of contents:
13
14 [[!toc]]
15
16 ## Mode
17
18 Mode is an augmentation of SV behaviour, providing additional
19 functionality. Some of these alterations are element-based (saturation),
20 others involve post-analysis (predicate result) and others are
21 Vector-based (mapreduce, fail-on-first).
22
23 [[sv/ldst]], [[sv/cr_ops]] and [[sv/branches]] are covered separately:
24 the following Modes apply to Arithmetic and Logical SVP64 operations:
25
26 * **simple** mode is straight vectorisation. No augmentations: the
27 vector comprises an array of independently created results.
28 * **ffirst** or data-dependent fail-on-first: see separate section.
29 The vector may be truncated depending on certain criteria.
30 *VL is altered as a result*.
31 * **sat mode** or saturation: clamps each element result to a min/max
32 rather than overflows / wraps. Allows signed and unsigned clamping
33 for both INT and FP.
34 * **reduce mode**. If used correctly, a mapreduce (or a prefix sum)
35 is performed. See [[svp64/appendix]].
36 Note that there are comprehensive caveats when using this mode,
37 and it should not be confused with the Parallel Reduction [[sv/remap]].
38 * **pred-result** will test the result (CR testing selects a bit of CR
39 and inverts it, just like branch conditional testing) and if the
40 test fails it is as if the *destination* predicate bit was zero even
41 before starting the operation. When Rc=1 the CR element however is
42 still stored in the CR regfile, even if the test failed. See appendix
43 for details.
44
45 Note that ffirst and reduce modes are not anticipated to be
46 high-performance in some implementations. ffirst due to interactions
47 with VL, and reduce due to it requiring additional operations to produce
48 a result. simple, saturate and pred-result are however inter-element
49 independent and may easily be parallelised to give high performance,
50 regardless of the value of VL.
51
52 The Mode table for Arithmetic and Logical operations,
53 being bits 19-23 of SVP64 `RM`, is laid out as
54 follows:
55
56 | 0-1 | 2 | 3 4 | description |
57 | --- | --- |---------|-------------------------- |
58 | 00 | 0 | dz sz | simple mode |
59 | 00 | 1 | 0 RG | scalar reduce mode (mapreduce) |
60 | 00 | 1 | 1 / | reserved |
61 | 01 | inv | CR-bit | Rc=1: ffirst CR sel |
62 | 01 | inv | VLi RC1 | Rc=0: ffirst z/nonz |
63 | 10 | N | dz sz | sat mode: N=0/1 u/s |
64 | 11 | inv | CR-bit | Rc=1: pred-result CR sel |
65 | 11 | inv | zz RC1 | Rc=0: pred-result z/nonz |
66
67 Fields:
68
69 * **sz / dz** source-zeroing, destination-zeroing.
70 if predication is enabled will put zeros into the dest
71 (or as src in the case of twin pred) when the predicate bit is zero.
72 Otherwise the element is ignored or skipped, depending on context.
73 * **zz**: both sz and dz are set equal to this flag
74 * **inv CR bit** just as in branches (BO) these bits allow testing of
75 a CR bit and whether it is set (inv=0) or unset (inv=1)
76 * **RG** inverts the Vector Loop order (VL-1 downto 0) rather
77 than the normal 0..VL-1
78 * **N** sets signed/unsigned saturation.
79 * **RC1** as if Rc=1, enables access to `VLi`.
80 * **VLi** VL inclusive: in fail-first mode, the truncation of
81 VL *includes* the current element at the failure point rather
82 than excludes it from the count.
83
84 For LD/ST Modes, see [[sv/ldst]]. For Condition Registers see
85 [[sv/cr_ops]]. For Branch modes, see [[sv/branches]].
86
87 ## Rounding, clamp and saturate
88
89 See [[av_opcodes]] for relevant opcodes and use-cases.
90
91 To help ensure for example that audio quality is not compromised by
92 overflow, "saturation" is provided, as well as a way to detect when
93 saturation occurred if desired (Rc=1). When Rc=1 there will be a *vector*
94 of CRs, one CR per element in the result (Note: this is different from
95 VSX which has a single CR per block).
96
97 When N=0 the result is saturated to within the maximum range of an
98 unsigned value. For integer ops this will be 0 to 2^elwidth-1. Similar
99 logic applies to FP operations, with the result being saturated to
100 maximum rather than returning INF, and the minimum to +0.0
101
102 When N=1 the same occurs except that the result is saturated to the min
103 or max of a signed result, and for FP to the min and max value rather
104 than returning +/- INF.
105
106 When Rc=1, the CR "overflow" bit is set on the CR associated with
107 the element, to indicate whether saturation occurred. Note that
108 due to the hugely detrimental effect it has on parallel processing,
109 XER.SO is **ignored** completely and is **not** brought into play here.
110 The CR overflow bit is therefore simply set to zero if saturation did
111 not occur, and to one if it did. This behaviour (ignoring XER.SO) is
112 actually optional in the SFFS Compliancy Subset: for SVP64 it is made
113 mandatory *but only on Vectorised instructions*.
114
115 Note also that saturate on operations that set OE=1 must raise an Illegal
116 Instruction due to the conflicting use of the CR.so bit for storing
117 if saturation occurred. Vectorised Integer Operations that produce a
118 Carry-Out (CA, CA32): these two bits will be `UNDEFINED` if saturation
119 is also requested.
120
121 Note that the operation takes place at the maximum bitwidth (max of
122 src and dest elwidth) and that truncation occurs to the range of the
123 dest elwidth.
124
125 *Programmer's Note: Post-analysis of the Vector of CRs to find out if any
126 given element hit saturation may be done using a mapreduced CR op (cror),
127 or by using the new crrweird instruction with Rc=1, which will transfer
128 the required CR bits to a scalar integer and update CR0, which will allow
129 testing the scalar integer for nonzero. See [[sv/cr_int_predication]].
130 Alternatively, a Data-Dependent Fail-First may be used to truncate the
131 Vector Length to non-saturated elements, greatly increasing the productivity
132 of parallelised inner hot-loops.*
133
134 ## Reduce mode
135
136 Reduction in SVP64 is similar in essence to other Vector Processing ISAs,
137 but leverages the underlying scalar Base v3.0B operations. Thus it is
138 more a convention that the programmer may utilise to give the appearance
139 and effect of a Horizontal Vector Reduction. Due to the unusual decoupling
140 it is also possible to perform prefix-sum (Fibonacci Series) in certain
141 circumstances. Details are in the [[svp64/appendix]]
142
143 Reduce Mode should not be confused with Parallel Reduction [[sv/remap]].
144 As explained in the [[sv/svp64/appendix]] Reduce Mode switches off the check
145 which would normally stop looping if the result register is scalar.
146 Thus, the result scalar register, if also used as a source scalar,
147 may be used to perform sequential accumulation. This *deliberately*
148 sets up a chain of Register Hazard Dependencies, whereas Parallel Reduce
149 [[sv/remap]] deliberately issues a Tree-Schedule of operations that may
150 be parallelised.
151
152 *Hardware architectural note: implementations may optimise out the Hazard
153 Dependency chain as long as Sequential Program Execution Order is preserved.*
154
155 ## Data-dependent Fail-on-first
156
157 Data-dependent fail-on-first is CR-field-driven and is completely separate
158 and distinct from LD/ST Fail-First (also known as Fault-First). Note in
159 each case the assumption is that vector elements are required to appear
160 to be executed in sequential Program Order. When REMAP is not active,
161 element 0 would be the first.
162
163 Data-driven (CR-field-driven) fail-on-first activates when Rc=1 or other
164 CR-creating operation produces a result (including cmp). Similar to
165 Branch-Conditional,
166 an analysis of the CR is performed and if the test fails, the
167 vector operation terminates and discards all element operations **at and
168 above the current one**, and VL is truncated to either the *previous*
169 element or the current one, depending on whether VLi (VL "inclusive")
170 is clear or set, respectively.
171
172 Thus the new VL comprises a contiguous vector of results, all of which
173 pass the testing criteria (equal to zero, less than zero etc as defined
174 by the CR-bit test).
175
176 *Note: when VLi is clear, the behaviour at first seems counter-intuitive.
177 A result is calculated but if the test fails it is prohibited from being
178 actually written. This becomes intuitive again when it is remembered
179 that the length that VL is set to is the number of *written* elements, and
180 only when VLI is set will the current element be included in that count.*
181
182 The CR-based data-driven fail-on-first is "new" and not found in ARM SVE
183 or RVV. At the same time it is "old" because it is almost identical to
184 a generalised form of Z80's `CPIR` instruction. It is extremely useful
185 for reducing instruction count, however requires speculative execution
186 involving modifications of VL to get high performance implementations.
187 An additional mode (RC1=1) effectively turns what would otherwise be an
188 arithmetic operation into a type of `cmp`. The CR is stored (and the
189 CR.eq bit tested against the `inv` field). If the CR.eq bit is equal to
190 `inv` then the Vector is truncated and the loop ends.
191
192 VLi is only available as an option when `Rc=0` (or for instructions
193 which do not have Rc). When set, the current element is always also
194 included in the count (the new length that VL will be set to). This may
195 be useful in combination with "inv" to truncate the Vector to *exclude*
196 elements that fail a test, or, in the case of implementations of strncpy,
197 to include the terminating zero.
198
199 In CR-based data-driven fail-on-first there is only the option to select
200 and test one bit of each CR (just as with branch BO). For more complex
201 tests this may be insufficient. If that is the case, a vectorised crop
202 such as crand, cror or [[sv/cr_int_predication]] crweirder may be used,
203 and ffirst applied to the crop instead of to the arithmetic vector. Note
204 that crops are covered by the [[sv/cr_ops]] Mode format.
205
206 Use of Fail-on-first with Vertical-First Mode is not prohibited but is
207 not really recommended. The effect of truncating VL
208 may have unintended and unexpected consequences on subsequent instructions.
209 VLi set will be fine: it is when VLi is clear that problems may be faced.
210
211 *Programmer's note: `VLi` is only accessible in normal operations which in
212 turn limits the CR field bit-testing to only `EQ/NE`. [[sv/cr_ops]] are
213 not so limited. Thus it is possible to use for example `sv.cror/ff=gt/vli
214 *0,*0,*0`, which is not a `nop` because it allows Fail-First Mode to
215 perform a test and truncate VL.*
216
217 *Hardware implementor's note: effective Sequential Program Order must
218 be preserved. Speculative Execution is perfectly permitted as long as
219 the speculative elements are held back from writing to register files
220 (kept in Resevation Stations), until such time as the relevant CR Field
221 bit(s) has been analysed. All Speculative elements sequentially beyond
222 the test-failure point **MUST** be cancelled. This is no different from
223 standard Out-of-Order Execution and the modification effort to efficiently
224 support Data-Dependent Fail-First within a pre-existing Multi-Issue
225 Out-of-Order Engine is anticipated to be minimal. In-Order systems on
226 the other hand are expected, unavoidably, to be low-performance*.
227
228 Two extremely important aspects of ffirst are:
229
230 * LDST ffirst may never set VL equal to zero. This because on the first
231 element an exception must be raised "as normal".
232 * CR-based data-dependent ffirst on the other hand **can** set VL equal
233 to zero. This is the only means in the entirety of SV that VL may be set
234 to zero (with the exception of via the SV.STATE SPR). When VL is set
235 zero due to the first element failing the CR bit-test, all subsequent
236 vectorised operations are effectively `nops` which is
237 *precisely the desired and intended behaviour*.
238
239 The second crucial aspect, compared to LDST Ffirst:
240
241 * LD/ST Failfirst may (beyond the initial first element
242 conditions) truncate VL for any architecturally suitable reason. Beyond
243 the first element LD/ST Failfirst is arbitrarily speculative and 100%
244 non-deterministic.
245 * CR-based data-dependent first on the other hand MUST NOT truncate VL
246 arbitrarily to a length decided by the hardware: VL MUST only be
247 truncated based explicitly on whether a test fails. This because it is
248 a precise Deterministic test on which algorithms can and will will rely.
249
250 **Floating-point Exceptions**
251
252 When Floating-point exceptions are enabled VL must be truncated at
253 the point where the Exception appears not to have occurred. If `VLi`
254 is set then VL must include the faulting element, and thus the faulting
255 element will always raise its exception. If however `VLi` is clear then
256 VL **excludes** the faulting element and thus the exception will **never**
257 be raised.
258
259 Although very strongly discouraged the Exception Mode that permits
260 Floating Point Exception notification to arrive too late to unwind
261 is permitted (under protest, due it violating the otherwise 100%
262 Deterministic nature of Data-dependent Fail-first).
263
264 **Use of lax FP Exception Notification Mode could result in parallel
265 computations proceeding with invalid results that have to be explicitly
266 detected, whereas with the strict FP Execption Mode enabled, FFirst
267 truncates VL, allows subsequent parallel computation to avoid the
268 exceptions entirely**
269
270 ## Data-dependent fail-first on CR operations (crand etc)
271
272 Operations that actually produce or alter CR Field as a result have
273 their own SVP64 Mode, described in [[sv/cr_ops]].
274
275 ## pred-result mode
276
277 This mode merges common CR testing with predication, saving on instruction
278 count. Below is the pseudocode excluding predicate zeroing and elwidth
279 overrides. Note that the pseudocode for [[sv/cr_ops]] is slightly
280 different.
281
282 ```
283 for i in range(VL):
284 # predication test, skip all masked out elements.
285 if predicate_masked_out(i):
286 continue
287 result = op(iregs[RA+i], iregs[RB+i])
288 CRnew = analyse(result) # calculates eq/lt/gt
289 # Rc=1 always stores the CR field
290 if Rc=1 or RC1:
291 CR.field[offs+i] = CRnew
292 # now test CR, similar to branch
293 if RC1 or CRnew[BO[0:1]] != BO[2]:
294 continue # test failed: cancel store
295 # result optionally stored but CR always is
296 iregs[RT+i] = result
297 ```
298
299 The reason for allowing the CR element to be stored is so that
300 post-analysis of the CR Vector may be carried out. For example:
301 Saturation may have occurred (and been prevented from updating, by the
302 test) but it is desirable to know *which* elements fail saturation.
303
304 Note that RC1 Mode basically turns all operations into `cmp`. The
305 calculation is performed but it is only the CR that is written. The
306 element result is *always* discarded, never written (just like `cmp`).
307
308 Note that predication is still respected: predicate zeroing is slightly
309 different: elements that fail the CR test *or* are masked out are zero'd.
310
311 [[!tag standards]]
312
313 --------
314
315 \newpage{}
316