(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. When doing so in a Vector Context, it is quite
20 reasonable and logical to test and Branch on a *Vector* of CR Fields
21 which have just been calculated from a *Vector* of results. In 3D Shader
22 binaries, which are inherently parallelised and predicated, testing all or
23 some results and branching based on multiple tests is extremely common,
24 and a fundamental part of Shader Compilers. Therefore, `sv.bc` and
25 other Vector-aware Branch Conditional instructions are a high priority
26 for 3D GPUs.
27
28 The `BI` field of Branch Conditional operations is five bits, in scalar
29 v3.0B this would select one bit of the 32 bit CR. In SVP64 there are
30 16 32 bit CRs, containing 128 4-bit CR Fields. Therefore, the 2 LSBs of
31 `BI` select the bit from the CR Field (EQ LT GT SO), and the top 3 bits
32 are extended to either scalar or vector and to select CR Fields 0..127
33 as specified in SVP64 [[sv/svp64/appendix]]
34
35 When considering an "array" of branches, there are four useful modes:
36 AND, OR, NAND and NOR of all Conditions.
37 NAND and NOR may be synthesised by
38 inverting `BO[2]` which just leaves two modes:
39
40 * Branch takes place on the first CR test to succeed
41 (a Great Big OR of all condition tests)
42 * Branch takes place only if **all** CR tests succeed:
43 a Great Big AND of all condition tests
44 (including those where the predicate is masked out
45 and the corresponding CR Field is considered to be
46 set to `SNZ`)
47
48 In SVP64 Horizontal-First Mode, the first failure in ALL mode (Great Big
49 AND) results in early exit: no more updates to CTR occur (if requested);
50 no branch occurs, and LR is not updated (if requested). Likewise for
51 non-ALL mode (Great Big Or) on first success early exit also occurs,
52 however this time with the Branch proceeding. In both cases the testing
53 of the Vector of CRs should be done in linear sequential order (or in
54 REMAP re-sequenced order): such that tests that are sequentially beyond
55 the exit point are *not* carried out. (*Note: it is standard practice in
56 Programming languages to exit early from conditional tests, however
57 a little unusual to consider in an ISA that is designed for Parallel
58 Vector Processing. The reason is to have strictly-defined guaranteed
59 behaviour*)
60
61 In Vertical-First Mode, the `ALL` bit still applies, but to the elements
62 that are executed up to the Hint length, in parallel batches. See
63 [[sv/setvl]] for the definition of Vertical-First Hint.
64
65 In `svstep` mode, srcstep and dststep are incremented, and then
66 tested exactly as in [[sv/svstep]]. When Rc=1 the test results
67 are wtitten into the whole CR Field (the exact same one
68 about to be tested by the Branch Condition). Following the svstep
69 update, the
70 Branch Conditional instruction proceeds as normal (reading and testing
71 the CR bit just updated, if the relevant `BO` bit is set). Note that
72 the SVSTATE srcstep and dststep fields are still updated
73 and the CR field still updated, even if `BO[0]` is set.
74
75 Predication in both INT and CR modes may be applied to `sv.bc` and other
76 SVP64 Branch Conditional operations, exactly as they may be applied to
77 other SVP64 operations. When `sz` is zero, any masked-out Branch-element
78 operations are not executed, exactly like all other SVP64 operations.
79
80 However when `sz` is non-zero, this normally requests insertion of a zero
81 in place of the input data, when the relevant predicate mask bit is zero.
82 This would mean that a zero is inserted in place of `CR[BI+32]` for
83 testing against `BO`, which may not be desirable in all circumstances.
84 Therefore, an extra field is provided `SNZ`, which, if set, will insert
85 a **one** in place of a masked-out element instead of a zero.
86
87 (*Note: Both options are provided because it is useful to deliberately
88 cause the Branch-Conditional Vector testing to fail at a specific point,
89 controlled by the Predicate mask. This is particularly useful in `VLSET`
90 mode, which will truncate SVSTATE.VL at the point of the first failed
91 test.*)
92
93 SVP64 RM `MODE` (includes `ELWIDTH` and `ELWIDTH_SRC` bits) for Branch Conditional:
94
95 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 23 | description |
96 | - | - | - | - | -- | -- | --- |---------|-------------------- |
97 |ALL|LRu| / | / | 0 | 0 | / | SNZ sz | normal mode |
98 |ALL|LRu| / |VSb| 0 | 1 | VLI | SNZ sz | VLSET mode |
99 |ALL|LRu|BRc| / | 1 | 0 | / | SNZ sz | svstep mode |
100 |ALL|LRu|BRc|VSb| 1 | 1 | VLI | SNZ sz | svstep+VLSET mode |
101
102 Fields:
103
104 * **sz** if predication is enabled will put 4 copies of `SNZ` in place of
105 the src CR Field when the predicate bit is zero. otherwise the element
106 is ignored or skipped, depending on context.
107 * **ALL** when set, all branch conditional tests must pass in order for
108 the branch to succeed.
109 * **VLI** Identical to Data-dependent Fail-First mode.
110 In VLSET mode, VL is set equal (truncated) to the first point
111 where, assuming Conditions are tested sequentially, the branch succeeds
112 *or fails* depending if VSb is set.
113 If VLI (Vector Length Inclusive) is clear,
114 VL is truncated to *exclude* the current element, otherwise it is
115 included. SVSTATE.MVL is not changed: only VL.
116 * **LRu**: Link Register Update. When set, Link Register will
117 only be updated if the Branch Condition succeeds. This avoids
118 destruction of LR during loops (particularly Vertical-First
119 ones).
120 * **BRc** Branch variant of Rc. Instructs svstep testing to overwrite
121 the CR Field about to be tested. Only takes effect in svstep mode
122 * **VSb** is most relevant for Vertical-First VLSET Mode. After testing,
123 if VSb is set, VL is truncated if the branch succeeds. If VSb is clear,
124 VL is truncated if the branch did **not** take place.
125
126 svstep mode will run an increment of SVSTATE srcstep and dststep
127 (which is still useful in Horizontal First Mode). Unlike `svstep.`
128 however which updates only CR0 with the testing of REMAP loop progress,
129 the CR Field is taken from the branch `BI` field, and, if `BRc`
130 is set, updated prior to
131 proceeding to each element branch conditional testing.
132 * This implies that the prior contents of the CR Vector are ignored*
133 when `BRc` is set.
134
135 Note that, interestingly, due to the useful side-effects of `VLSET` mode
136 and `svstep` mode it is actually useful to use Branch Conditional even
137 to perform no actual branch operation, i.e to point to the instruction
138 after the branch.
139
140 In particular, svstep mode is still useful for Horizontal-First Mode
141 particularly in combination with REMAP. All "loop end" conditions
142 will be tested on a per-element basis and placed into a Vector of CRs
143 starting from the point specified by the Branch `BI` field. This Vector
144 of CR Fields may then be subsequently used as a Predicate Mask, and,
145 furthermore, if VLSET mode was requested, VL will have been set to the
146 length of one of the loop endpoints, again as specified by the bit from
147 the Branch `BI` field.
148
149 Also, the unconditional bit `BO[0]` is still relevant when Predication
150 is applied to the Branch because in `ALL` mode all nonmasked bits have
151 to be tested. Even when svstep mode or VLSET mode are not used, CTR
152 may still be decremented by the total number of nonmasked elements.
153 In short, Vectorised Branch becomes an extremely powerful tool.
154
155 `VLSET` mode with Vertical-First is particularly unusual. Vertical-First
156 is used for explicit looping, where the looping is to terminate if
157 the end of the Vector, VL, is reached. If however that loop is terminated
158 early because VL is truncated, VLSET with Vertical-First becomes
159 meaningless. Therefore, the option to decide whether truncation should
160 occur if the branch succeeds *or* if the branch condition fails allows
161 for flexibility required.
162
163 `VLSET` mode with Horizontal-First when `VSb` is clear is still useful,
164 because it can be used to truncate VL to the first predicated (non-masked-out)
165 element.
166
167 Available options to combine:
168
169 * `BO[0]` to make an unconditional branch would seem irrelevant if
170 it were not for predication and for side-effects.
171 * `BO[1]` to select whether the CR bit being tested is zero or nonzero
172 * `R30` and `~R30` and other predicate mask options including CR and
173 inverted CR bit testing
174 * `sz` and `SNZ` to insert either zeros or ones in place of masked-out
175 predicate bits
176 * `ALL` or `ANY` behaviour corresponding to `AND` of all tests and
177 `OR` of all tests, respectively.
178
179 In addition to the above, it is necessary to select whether, in `svstep`
180 mode, the Vector CR Field is to be overwritten or not: in some cases
181 it is useful to know but in others all that is needed is the branch itself.
182
183 Pseudocode for Horizontal-First Mode:
184
185 ```
186 cond_ok = not SVRMmode.ALL
187 for srcstep in range(VL):
188 # select predicate bit or zero/one
189 if predicate[srcstep]:
190 # get SVP64 extended CR field 0..127
191 SVCRf = SVP64EXTRA(BI>>2)
192 if svstep_mode then
193 new_srcstep, CRbits = SVSTATE_NEXT(srcstep)
194 if BRc = 1 then # CR Vectorised overwritr
195 CR{SVCRf+srcstep} = CRbits
196 else
197 CRbits = CR{SVCRf}
198 testbit = CRbits[BI & 0b11]
199 # testbit = CR[BI+32+srcstep*4]
200 else if not SVRMmode.sz:
201 continue
202 else
203 testbit = SVRMmode.SNZ
204 # actual element test here
205 el_cond_ok <- BO[0] | ¬(testbit ^ BO[1])
206 # merge in the test
207 if SVRMmode.ALL:
208 cond_ok &= el_cond_ok
209 else
210 cond_ok |= el_cond_ok
211 # test for VL to be set (and exit)
212 if VLSET and VSb = el_cond_ok then
213 if SVRMmode.VLI
214 SVSTATE.VL = srcstep+1
215 else
216 SVSTATE.VL = srcstep
217 break
218 # early exit?
219 if SVRMmode.ALL:
220 if ~el_cond_ok:
221 break
222 else
223 if el_cond_ok:
224 break
225 if svstep_mode then
226 SVSTATE.srcstep = new_srcstep
227 ```
228
229 Pseudocode for Vertical-First Mode:
230
231 ```
232 # get SVP64 extended CR field 0..127
233 SVCRf = SVP64EXTRA(BI>>2)
234 if svstep_mode then
235 new_srcstep, CRbits = SVSTATE_NEXT(srcstep)
236 else
237 CRbits = CR{SVCRf}
238 # select predicate bit or zero/one
239 if predicate[srcstep]:
240 if BRc = 1 then # CR0 vectorised
241 CR{SVCRf+srcstep} = CRbits
242 testbit = CRbits[BI & 0b11]
243 else if not SVRMmode.sz:
244 SVSTATE.srcstep = new_srcstep
245 exit # no branch testing
246 else
247 testbit = SVRMmode.SNZ
248 # actual element test here
249 cond_ok <- BO[0] | ¬(testbit ^ BO[1])
250 # test for VL to be set (and exit)
251 if VLSET and cond_ok = VSb then
252 if SVRMmode.VLI
253 SVSTATE.VL = new_srcstep+1
254 else
255 SVSTATE.VL = new_srcstep
256 if svstep_mode then
257 SVSTATE.srcstep = new_srcstep
258 ```
259
260 # Example Shader code
261
262 ```
263 while(a > 2) {
264 if(b < 5)
265 f();
266 else
267 g();
268 h();
269 }
270 ```
271
272 which compiles to something like:
273
274 ```
275 vec<i32> a, b;
276 // ...
277 pred loop_pred = a > 2;
278 while(loop_pred.any()) {
279 pred if_pred = loop_pred & (b < 5);
280 if(if_pred.any()) {
281 f(if_pred);
282 }
283 label1:
284 pred else_pred = loop_pred & ~if_pred;
285 if(else_pred.any()) {
286 g(else_pred);
287 }
288 h(loop_pred);
289 }
290 ```
291
292 which will end up as:
293
294 ```
295 sv.cmpi CR60.v a.v, 2 # vector compare a into CR60 vector
296 sv.crweird r30, CR60.GT # transfer GT vector to r30
297 while_loop:
298 sv.cmpi CR80.v, b.v, 5 # vector compare b into CR64 Vector
299 sv.bc/m=r30/~ALL/sz CR80.v.LT skip_f # skip when none
300 # only calculate loop_pred & pred_b because needed in f()
301 sv.crand CR80.v.SO, CR60.v.GT, CR80.V.LT # if = loop & pred_b
302 f(CR80.v.SO)
303 skip_f:
304 # illustrate inversion of pred_b. invert r30, test ALL
305 # rather than SOME, but masked-out zero test would FAIL,
306 # therefore masked-out instead is tested against 1 not 0
307 sv.bc/m=~r30/ALL/SNZ CR80.v.LT skip_g
308 # else = loop & ~pred_b, need this because used in g()
309 sv.crternari(A&~B) CR80.v.SO, CR60.v.GT, CR80.V.LT
310 g(CR80.v.SO)
311 skip_g:
312 # conditionally call h(r30) if any loop pred set
313 sv.bclr/m=r30/~ALL/sz BO[1]=1 h()
314 sv.bc/m=r30/~ALL/sz BO[1]=1 while_loop
315 ```