(no commit message)
[libreriscv.git] / openpower / sv / branches.mdwn
1 # SVP64 Branch Conditional behaviour
2
3 **DRAFT STATUS**
4
5 Please note: SVP64 Branch instructions should be
6 considered completely separate and distinct from
7 standard scalar OpenPOWER-approved v3.0B branches.
8 **v3.0B branches are in no way impacted, altered,
9 changed or modified in any way, shape or form by
10 the SVP64 Vectorised Variants**.
11
12 Links
13
14 * <https://bugs.libre-soc.org/show_bug.cgi?id=664>
15 * <http://lists.libre-soc.org/pipermail/libre-soc-dev/2021-August/003416.html>
16 * [[openpower/isa/branch]]
17
18 Scalar 3.0B Branch Conditional operations, `bc`, `bctar` etc. test a
19 Condition Register. However for parallel processing it is simply impossible
20 to perform multiple independent branches: the Program Counter simply
21 cannot branch to multiple destinations based on multiple conditions.
22 The best that can be done is
23 to test multiple Conditions and make a decision of a *single* branch,
24 based on analysis of a *Vector* of CR Fields
25 which have just been calculated from a *Vector* of results.
26
27 In 3D Shader
28 binaries, which are inherently parallelised and predicated, testing all or
29 some results and branching based on multiple tests is extremely common,
30 and a fundamental part of Shader Compilers. Example:
31 without such multi-condition
32 test-and-branch, if a predicate mask is all zeros a large batch of
33 instructions may be masked out to `nop`, and it would waste
34 CPU cycles not only to run them but also to load the predicate
35 mask repeatedly for each one. 3D GPU ISAs can test for this scenario
36 and jump over the fully-masked-out operations, by spotting that
37 *all* Conditions are false. Or, conversely, they only call the function if at least
38 one Condition) is set.
39 Therefore, in order to be commercially competitive, `sv.bc` and
40 other Vector-aware Branch Conditional instructions are a high priority
41 for 3D GPU workloads.
42
43 The `BI` field of Branch Conditional operations is five bits, in scalar
44 v3.0B this would select one bit of the 32 bit CR,
45 comprising eight CR Fields of 4 bits each. In SVP64 there are
46 16 32 bit CRs, containing 128 4-bit CR Fields. Therefore, the 2 LSBs of
47 `BI` select the bit from the CR Field (EQ LT GT SO), and the top 3 bits
48 are extended to either scalar or vector and to select CR Fields 0..127
49 as specified in SVP64 [[sv/svp64/appendix]].
50
51 When considering an "array" of branch-tests, there are four useful modes:
52 AND, OR, NAND and NOR of all Conditions.
53 NAND and NOR may be synthesised by
54 inverting `BO[2]` which just leaves two modes:
55
56 * Branch takes place on the first CR Field test to succeed
57 (a Great Big OR of all condition tests)
58 * Branch takes place only if **all** CR field tests succeed:
59 a Great Big AND of all condition tests
60 (including those where the predicate is masked out
61 and the corresponding CR Field is considered to be
62 set to `SNZ`)
63
64 When the CR Fields selected by SVP64-Augmented `BI` is marked as scalar,
65 then as the usual SVP64 rules apply,
66 the loop ends at the first element tested, after taking
67 predication into consideration. Thus, also as usual, when a predicate mask is
68 given, and `BI` marked as scalar, and `sz` is zero, srcstep
69 skips forward to the first non-zero predicated element, and only that
70 one element is tested.
71
72 In SVP64 Horizontal-First Mode, the first failure in ALL mode (Great Big
73 AND) results in early exit: no more updates to CTR occur (if requested);
74 no branch occurs, and LR is not updated (if requested). Likewise for
75 non-ALL mode (Great Big Or) on first success early exit also occurs,
76 however this time with the Branch proceeding. In both cases the testing
77 of the Vector of CRs should be done in linear sequential order (or in
78 REMAP re-sequenced order): such that tests that are sequentially beyond
79 the exit point are *not* carried out. (*Note: it is standard practice in
80 Programming languages to exit early from conditional tests, however
81 a little unusual to consider in an ISA that is designed for Parallel
82 Vector Processing. The reason is to have strictly-defined guaranteed
83 behaviour*)
84
85 In Vertical-First Mode, setting the `ALL` bit results in `UNDEFINED`
86 behaviour. Given that only one element is being tested at a time
87 in Vertical-First Mode, a test designed to be done on multiple
88 bits is meaningless.
89
90 Predication in both INT and CR modes may be applied to `sv.bc` and other
91 SVP64 Branch Conditional operations, exactly as they may be applied to
92 other SVP64 operations. When `sz` is zero, any masked-out Branch-element
93 operations are not included in condition testing, exactly like all other
94 SVP64 operations. With one exception this *includes* side-effects such as potentially updating
95 LR and CTR which will also be skipped. The exception here is when
96 `BO[2]=0, sz=0, CTR-test=0, CTi=1` and the relevant element
97 predicate mask bit is also zero:
98 under these special circumstances CTR will also decrement.
99
100 When `sz` is non-zero, this normally requests insertion of a zero
101 in place of the input data, when the relevant predicate mask bit is zero.
102 This would mean that a zero is inserted in place of `CR[BI+32]` for
103 testing against `BO`, which may not be desirable in all circumstances.
104 Therefore, an extra field is provided `SNZ`, which, if set, will insert
105 a **one** in place of a masked-out element, instead of a zero.
106
107 (*Note: Both options are provided because it is useful to deliberately
108 cause the Branch-Conditional Vector testing to fail at a specific point,
109 controlled by the Predicate mask. This is particularly useful in `VLSET`
110 mode, which will truncate SVSTATE.VL at the point of the first failed
111 test.*)
112
113 SVP64 RM `MODE` (includes `ELWIDTH` and `ELWIDTH_SRC` bits) for Branch
114 Conditional:
115
116 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 23 | description |
117 | - | - | - | - | -- | -- | --- |---------|----------------- |
118 |ALL|LRu| / | / | 0 | 0 | / | SNZ sz | normal mode |
119 |ALL|LRu| / |VSb| 0 | 1 | VLI | SNZ sz | VLSET mode |
120 |ALL|LRu|CTi| / | 1 | 0 | / | SNZ sz | CTR-test mode |
121 |ALL|LRu|CTi|VSb| 1 | 1 | VLI | SNZ sz | CTR-test+VLSET mode |
122
123 Fields:
124
125 * **sz** if predication is enabled will put 4 copies of `SNZ` in place of
126 the src CR Field when the predicate bit is zero. otherwise the element
127 is ignored or skipped, depending on context.
128 * **ALL** when set, all branch conditional tests must pass in order for
129 the branch to succeed. When clear, it is the first sequentially
130 encountered successful test that causes the branch to succeed.
131 * **VLI** VLSET is identical to Data-dependent Fail-First mode.
132 In VLSET mode, VL is set equal (truncated) to the first point
133 where, assuming Conditions are tested sequentially, the branch succeeds
134 *or fails* depending if VSb is set.
135 If VLI (Vector Length Inclusive) is clear,
136 VL is truncated to *exclude* the current element, otherwise it is
137 included. SVSTATE.MVL is not changed: only VL.
138 * **LRu**: Link Register Update. When set, Link Register will
139 only be updated if the Branch Condition succeeds. This avoids
140 destruction of LR during loops (particularly Vertical-First
141 ones).
142 * **VSb** is most relevant for Vertical-First VLSET Mode. After testing,
143 if VSb is set, VL is truncated if the branch succeeds. If VSb is clear,
144 VL is truncated if the branch did **not** take place.
145 * **CTi** CTR inversion. CTR Mode normally decrements per element
146 tested. CTR inversion decrements if a test *fails*.
147
148 Normally, CTR mode will decrement once per Condition Test, resulting
149 under normal circumstances that CTR reduces by up to VL in Horizontal-First
150 Mode. Just as when v3.0B Branch-Conditional saves at
151 least one instruction on tight inner loops through auto-decrementation
152 of CTR, likewise it is also possible to save instruction count for
153 SVP64 loops in both Vertical-First and Horizontal-First Mode, particularly
154 in circumstances where there is conditional interaction between the
155 element computation and testing, and the continuation (or otherwise)
156 of a given loop. The potential combinations of interactions is why CTR
157 testing options have been added.
158
159 If both CTR-test and VLSET Modes are requested, then because the CTR decrement is on a per element basis, the total amount that CTR is decremented
160 by will end up being VL *after* truncation (should that occur).
161
162 CTR-test mode and CTi interaction is as follows: note that
163 `BO[2]` is still required to be clear for decrements to be
164 considered.
165
166 * **CTR-test=0, CTi=0**: CTR decrements on a per-element basis
167 if `BO[2]` is zero. Masked-out elements when `sz=0` are
168 skipped.
169 * **CTR-test=0, CTi=1**: CTR decrements on a per-element basis
170 if `BO[2]` is zero and a masked-out element is skipped
171 (`sz=0` and predicate bit is zero). This one special case is the
172 **opposite** of other combinations.
173 * **CTR-test=1, CTi=0**: CTR decrements on a per-element basis
174 if `BO[2]` is zero and the Condition Test succeeds.
175 Masked-out elements when `sz=0` are skipped.
176 * **CTR-test=1, CTi=1**: CTR decrements on a per-element basis
177 if `BO[2]` is zero and the Condition Test *fails*.
178 Masked-out elements when `sz=0` are skipped.
179
180 Note that, interestingly, due to the side-effects of `VLSET` mode
181 it is actually useful to use Branch Conditional even
182 to perform no actual branch operation, i.e to point to the instruction
183 after the branch. Truncation of VL would thus conditionally occur yet control
184 flow alteration would not.
185
186 Also, the unconditional bit `BO[0]` is still relevant when Predication
187 is applied to the Branch because in `ALL` mode all nonmasked bits have
188 to be tested. Even when svstep mode or VLSET mode are not used, CTR
189 may still be decremented by the total number of nonmasked elements.
190 In short, Vectorised Branch becomes an extremely powerful tool.
191
192 `VLSET` mode with Vertical-First is particularly unusual. Vertical-First
193 is used for explicit looping, where the looping is to terminate if the end
194 of the Vector, VL, is reached. If however that loop is terminated early
195 because VL is truncated, VLSET with Vertical-First becomes meaningless.
196 Therefore, with `VSb`, the option to decide whether truncation should occur if the
197 branch succeeds *or* if the branch condition fails allows for flexibility
198 required.
199
200 `VLSET` mode with Horizontal-First when `VSb` is clear is still
201 useful, because it can be used to truncate VL to the first predicated
202 (non-masked-out) element.
203
204 Available options to combine:
205
206 * `BO[0]` to make an unconditional branch would seem irrelevant if
207 it were not for predication and for side-effects.
208 * `BO[1]` to select whether the CR bit being tested is zero or nonzero
209 * `R30` and `~R30` and other predicate mask options including CR and
210 inverted CR bit testing
211 * `sz` and `SNZ` to insert either zeros or ones in place of masked-out
212 predicate bits
213 * `ALL` or `ANY` behaviour corresponding to `AND` of all tests and
214 `OR` of all tests, respectively.
215
216 In addition to the above, it is necessary to select whether, in `svstep`
217 mode, the Vector CR Field is to be overwritten or not: in some cases it
218 is useful to know but in others all that is needed is the branch itself.
219
220 *Programming note: One important point is that SVP64 instructions are 64 bit.
221 (8 bytes not 4). This needs to be taken into consideration when computing
222 branch offsets: the offset is relative to the start of the instruction,
223 which includes the SVP64 Prefix*
224
225 Pseudocode for Horizontal-First Mode:
226
227 ```
228 cond_ok = not SVRMmode.ALL
229 for srcstep in range(VL):
230 # select predicate bit or zero/one
231 if predicate[srcstep]:
232 # get SVP64 extended CR field 0..127
233 SVCRf = SVP64EXTRA(BI>>2)
234 CRbits = CR{SVCRf}
235 testbit = CRbits[BI & 0b11]
236 # testbit = CR[BI+32+srcstep*4]
237 else if not SVRMmode.sz:
238 # inverted CTR test skip mode
239 if ¬BO[2] & CTRtest & ¬CTI then
240 CTR = CTR - 1
241 continue
242 else
243 testbit = SVRMmode.SNZ
244 # actual element test here
245 el_cond_ok <- BO[0] | ¬(testbit ^ BO[1])
246 # merge in the test
247 if SVRMmode.ALL:
248 cond_ok &= el_cond_ok
249 else
250 cond_ok |= el_cond_ok
251 # test for VL to be set (and exit)
252 if VLSET and VSb = el_cond_ok then
253 if SVRMmode.VLI
254 SVSTATE.VL = srcstep+1
255 else
256 SVSTATE.VL = srcstep
257 break
258 # early exit?
259 if SVRMmode.ALL:
260 if ~el_cond_ok:
261 break
262 else
263 if el_cond_ok:
264 break
265 if SVCRf.scalar:
266 break
267 ```
268
269 Pseudocode for Vertical-First Mode:
270
271 ```
272 # get SVP64 extended CR field 0..127
273 SVCRf = SVP64EXTRA(BI>>2)
274 CRbits = CR{SVCRf}
275 # select predicate bit or zero/one
276 if predicate[srcstep]:
277 if BRc = 1 then # CR0 vectorised
278 CR{SVCRf+srcstep} = CRbits
279 testbit = CRbits[BI & 0b11]
280 else if not SVRMmode.sz:
281 # inverted CTR test skip mode
282 if ¬BO[2] & CTRtest & ¬CTI then
283 CTR = CTR - 1
284 SVSTATE.srcstep = new_srcstep
285 exit # no branch testing
286 else
287 testbit = SVRMmode.SNZ
288 # actual element test here
289 cond_ok <- BO[0] | ¬(testbit ^ BO[1])
290 # test for VL to be set (and exit)
291 if VLSET and cond_ok = VSb then
292 if SVRMmode.VLI
293 SVSTATE.VL = new_srcstep+1
294 else
295 SVSTATE.VL = new_srcstep
296 ```
297
298 v3.0B branch pseudocode including LRu and CTR skipping
299
300 ```
301 if (mode_is_64bit) then M <- 0
302 else M <- 32
303 cond_ok <- BO[0] | ¬(CR[BI+32] ^ BO[1])
304 ctrdec = ¬BO[2]
305 if CTRtest & (cond_ok ^ CTi) then
306 ctrdec = 0b0
307 if ctrdec then CTR <- CTR - 1
308 ctr_ok <- BO[2] | ((CTR[M:63] != 0) ^ BO[3])
309 lr_ok <- SVRMmode.LRu
310 if ctr_ok & cond_ok then
311 if AA then NIA <-iea EXTS(BD || 0b00)
312 else NIA <-iea CIA + EXTS(BD || 0b00)
313 lr_ok <- 0b1
314 if LK & lr_ok then LR <-iea CIA + 4
315 ```
316
317 # Example Shader code
318
319 ```
320 while(a > 2) {
321 if(b < 5)
322 f();
323 else
324 g();
325 h();
326 }
327 ```
328
329 which compiles to something like:
330
331 ```
332 vec<i32> a, b;
333 // ...
334 pred loop_pred = a > 2;
335 while(loop_pred.any()) {
336 pred if_pred = loop_pred & (b < 5);
337 if(if_pred.any()) {
338 f(if_pred);
339 }
340 label1:
341 pred else_pred = loop_pred & ~if_pred;
342 if(else_pred.any()) {
343 g(else_pred);
344 }
345 h(loop_pred);
346 }
347 ```
348
349 which will end up as:
350
351 ```
352 sv.cmpi CR60.v a.v, 2 # vector compare a into CR60 vector
353 sv.crweird r30, CR60.GT # transfer GT vector to r30
354 while_loop:
355 sv.cmpi CR80.v, b.v, 5 # vector compare b into CR64 Vector
356 sv.bc/m=r30/~ALL/sz CR80.v.LT skip_f # skip when none
357 # only calculate loop_pred & pred_b because needed in f()
358 sv.crand CR80.v.SO, CR60.v.GT, CR80.V.LT # if = loop & pred_b
359 f(CR80.v.SO)
360 skip_f:
361 # illustrate inversion of pred_b. invert r30, test ALL
362 # rather than SOME, but masked-out zero test would FAIL,
363 # therefore masked-out instead is tested against 1 not 0
364 sv.bc/m=~r30/ALL/SNZ CR80.v.LT skip_g
365 # else = loop & ~pred_b, need this because used in g()
366 sv.crternari(A&~B) CR80.v.SO, CR60.v.GT, CR80.V.LT
367 g(CR80.v.SO)
368 skip_g:
369 # conditionally call h(r30) if any loop pred set
370 sv.bclr/m=r30/~ALL/sz BO[1]=1 h()
371 sv.bc/m=r30/~ALL/sz BO[1]=1 while_loop
372 ```