(no commit message)
[libreriscv.git] / openpower / sv / branches.mdwn
index 7ec90552a3b06b94d1a8ad463c50c0e437efc021..554a90924cbc3d12202319ae8055c7774c174900 100644 (file)
@@ -15,30 +15,158 @@ Links
 * <http://lists.libre-soc.org/pipermail/libre-soc-dev/2021-August/003416.html>
 * [[openpower/isa/branch]]
 
+# Rationale
+
 Scalar 3.0B Branch Conditional operations, `bc`, `bctar` etc. test a
-Condition Register.  When doing so in a Vector Context, it is quite
-reasonable and logical to test a *Vector* of CR Fields. In 3D Shader
+Condition Register.  However for parallel processing it is simply impossible
+to perform multiple independent branches: the Program Counter simply
+cannot branch to multiple destinations based on multiple conditions.
+The best that can be done is
+to test multiple Conditions and make a decision of a *single* branch,
+based on analysis of a *Vector* of CR Fields
+which have just been calculated from a *Vector* of results.
+
+In 3D Shader
 binaries, which are inherently parallelised and predicated, testing all or
 some results and branching based on multiple tests is extremely common,
-and a fundamental part of Shader Compilers.  Therefore, `sv.bc` and
-other Vector-aware Branch Conditional instructions are worth including.
+and a fundamental part of Shader Compilers.  Example:
+without such multi-condition
+test-and-branch, if a predicate mask is all zeros a large batch of
+instructions may be masked out to `nop`, and it would waste
+CPU cycles not only to run them but also to load the predicate
+mask repeatedly for each one.  3D GPU ISAs can test for this scenario
+and jump over the fully-masked-out operations, by spotting that
+*all* Conditions are false. Or, conversely, they only call the function if at least
+one Condition is set.
+Therefore, in order to be commercially competitive, `sv.bc` and
+other Vector-aware Branch Conditional instructions are a high priority
+for 3D GPU workloads.
+
+Given that Power ISA v3.0B is already quite powerful, particularly
+the Condition Registers and their interaction with Branches, there
+are opportunities to create an extremely flexible and compact
+Vectorised Branch behaviour.  In addition, the side-effects (updating
+of CTR, truncation of VL, described below) make it a useful instruction
+even if the branch points to the next instruction (no actual branch).
+
+# Overview
+
+When considering an "array" of branch-tests, there are four useful modes:
+AND, OR, NAND and NOR of all Conditions.
+NAND and NOR may be synthesised by
+inverting `BO[2]` which just leaves two modes:
+
+* Branch takes place on the first CR Field test to succeed
+  (a Great Big OR of all condition tests)
+* Branch takes place only if **all** CR field tests succeed:
+  a Great Big AND of all condition tests
+  (including those where the predicate is masked out
+   and the corresponding CR Field is considered to be
+   set to `SNZ`)
+
+Early-exit is enacted such that the Vectorised Branch does not
+perform needless extra tests, which will help reduce reads on
+the Condition Register file.
+
+Additional useful behaviour involves two primary Modes (both of
+which may be enabled and combined):
+
+* **VLSET Mode**: identical to Data-Dependent Fail-First Mode
+  for Arithmetic SVP64 operations, with more
+  flexibility and a close interaction and integration into the
+  underlying base Scalar v3.0B Branch instruction.
+* **CTR-test Mode**: gives much more flexibility over when and why
+  CTR is decremented, including options to decrement if a Condition
+  test succeeds *or if it fails*.
+
+With these side-effects, basic Boolean Logic Analysis advises thay
+it is important to provide a means
+to enact them each based on whether testing succeeds *or fails*. This
+results in a not-insignificant number of additional Mode Augmentation bits,
+accompanying VLSET and CTR-test Modes respectively.
+
+It is also important to note that Vectorised Branches can be used
+in either SVP64 Horizontal-First or Vertical-First Mode. Essentially
+the behaviour is identical in both Modes.
+
+It is also important
+to bear in mind that, fundamentally, Vectorised Branch-Conditional
+is still extremely close to the Scalar v3.0B Branch-Conditional
+instructions, and that the same v3.0B Scalar Branch-Conditional
+instructions are still
+*completely separate and independent*, being unaltered and
+unaffected by their SVP64 variants in every conceivable way.
+
+# Format and fields
+
+SVP64 RM `MODE` (includes `ELWIDTH` and `ELWIDTH_SRC` bits) for Branch
+Conditional:
+
+| 4 | 5 | 6 | 7 | 19 | 20 |  21 | 22   23 |  description     |
+| - | - | - | - | -- | -- | --- |---------|----------------- |
+|ALL|LRu| / | / | 0  | 0  | /   |  SNZ sz | normal mode      |
+|ALL|LRu| / |VSb| 0  | 1  | VLI |  SNZ sz | VLSET mode       |
+|ALL|LRu|CTi| / | 1  | 0  | /   |  SNZ sz | CTR-test mode         |
+|ALL|LRu|CTi|VSb| 1  | 1  | VLI |  SNZ sz | CTR-test+VLSET mode   |
+
+Brief description of fields:
+
+* **sz**  if predication is enabled will put 4 copies of `SNZ` in place of
+  the src CR Field when the predicate bit is zero.  otherwise the element
+  is ignored or skipped, depending on context.
+* **ALL** when set, all branch conditional tests must pass in order for
+  the branch to succeed. When clear, it is the first sequentially
+  encountered successful test that causes the branch to succeed.
+  This is identical behaviour to how programming languages perform
+  early-exit on Boolean Logic chains.
+* **VLI** VLSET is identical to Data-dependent Fail-First mode.
+  In VLSET mode, VL is set equal (truncated) to the first point
+  where, assuming Conditions are tested sequentially, the branch succeeds
+  *or fails* depending if VSb is set.
+  If VLI (Vector Length Inclusive) is clear,
+  VL is truncated to *exclude* the current element, otherwise it is
+  included. SVSTATE.MVL is not changed: only VL.
+* **LRu**: Link Register Update. When set, Link Register will
+  only be updated if the Branch Condition succeeds. This avoids
+  destruction of LR during loops (particularly Vertical-First
+  ones).
+* **VSb** is most relevant for Vertical-First VLSET Mode. After testing,
+  if VSb is set, VL is truncated if the branch succeeds.  If VSb is clear,
+  VL is truncated if the branch did **not** take place.
+* **CTi** CTR inversion. CTR-test Mode normally decrements per element
+  tested. CTR inversion decrements if a test *fails*. Only relevant
+  in CTR-test Mode.
+
+# Vectorised CR Field numbering, and Scalar behaviour
+
+It is important to keep in mind that just like all SVP64 instructions,
+the `BI` field of the base v3.0B Branch Conditional instruction
+may be extended by SVP64 EXTRA augmentation, as well as be marked
+as either Scalar or Vector.
 
 The `BI` field of Branch Conditional operations is five bits, in scalar
-v3.0B this would select one bit of the 32 bit CR.  In SVP64 there are
+v3.0B this would select one bit of the 32 bit CR,
+comprising eight CR Fields of 4 bits each.  In SVP64 there are
 16 32 bit CRs, containing 128 4-bit CR Fields.  Therefore, the 2 LSBs of
 `BI` select the bit from the CR Field (EQ LT GT SO), and the top 3 bits
 are extended to either scalar or vector and to select CR Fields 0..127
-as specified in SVP64 [[sv/svp64/appendix]]
+as specified in SVP64 [[sv/svp64/appendix]].
 
-When considering an "array" of branches, there are two useful modes:
+When the CR Fields selected by SVP64-Augmented `BI` is marked as scalar,
+then as the usual SVP64 rules apply:
+the loop ends at the first element tested, after taking
+predication into consideration. Thus, also as usual, when a predicate mask is
+given, and `BI` marked as scalar, and `sz` is zero, srcstep
+skips forward to the first non-zero predicated element, and only that
+one element is tested.
 
-* Branch takes place on the first CR test to succeed
-  (a Great Big OR of all condition tests)
-* Branch takes place only if **all** CR tests succeed:
-  a Great Big AND of all condition tests
-  (including those where the predicate is masked out
-   and the corresponding CR Field is considered to be
-   set to `SNZ`)
+In other words, the fact that this is a Branch
+Operation (instead of an arithmetic one) does not result, ultimately,
+in significant changes as to
+how SVP64 is fundamentally applied, except with respect to early-out
+opportunities and CTR-testing, which are outlined below.
+
+# Description and Modes
 
 In SVP64 Horizontal-First Mode, the first failure in ALL mode (Great Big
 AND) results in early exit: no more updates to CTR occur (if requested);
@@ -47,37 +175,34 @@ non-ALL mode (Great Big Or) on first success early exit also occurs,
 however this time with the Branch proceeding.  In both cases the testing
 of the Vector of CRs should be done in linear sequential order (or in
 REMAP re-sequenced order): such that tests that are sequentially beyond
-the exit point are *not* carried out. (*Note: is standard practice in
-Programming languages to exit early from conditional tests*)
-
-In Vertical-First Mode, the `ALL` bit should not be used.  If set,
-behaviour is `UNDEFINED`.  (*The reason is that Vertical-First hints may
-permit multiple elements up to hint length to be executed in parallel,
-however the number is entirely up to implementors.  Attempting to test
-an arbitrary indeterminate number of Conditional tests is impossible
-to define, and efforts to enforce such defined behaviour interfere with
-Vertical-First mode parallel opportunistic behaviour.*)
-
-In `svstep` mode, the whole CR Field, part of which is selected by `BI`
-(top 3 bits), is updated based on incrementing srcstep and dststep, and
-performing the same tests as [[sv/svstep]]. Following the step update,
-which involved writing to the exact CR Field about to be tested, the
-Branch Conditional instruction proceeds as normal (reading and testing
-the CR bit just updated, if the relevant `BO` bit is set).  Note that
-the SVSTATE fields are still updated, and the CR field still updated,
-even if the `BO` bits do not require CR testing.
+the exit point are *not* carried out. (*Note: it is standard practice in
+Programming languages to exit early from conditional tests, however
+a little unusual to consider in an ISA that is designed for Parallel
+Vector Processing. The reason is to have strictly-defined guaranteed
+behaviour*)
+
+In Vertical-First Mode, setting the `ALL` bit results in `UNDEFINED` 
+behaviour. Given that only one element is being tested at a time
+in Vertical-First Mode, a test designed to be done on multiple
+bits is meaningless.
 
 Predication in both INT and CR modes may be applied to `sv.bc` and other
 SVP64 Branch Conditional operations, exactly as they may be applied to
 other SVP64 operations.  When `sz` is zero, any masked-out Branch-element
-operations are not executed, exactly like all other SVP64 operations.
-
-However when `sz` is non-zero, this normally requests insertion of a zero
+operations are not included in condition testing, exactly like all other
+SVP64 operations, *including* side-effects such as potentially updating
+LR or CTR, which will also be skipped. There is *one* exception here,
+which is when
+`BO[2]=0, sz=0, CTR-test=0, CTi=1` and the relevant element
+predicate mask bit is also zero:
+under these special circumstances CTR will also decrement.
+
+When `sz` is non-zero, this normally requests insertion of a zero
 in place of the input data, when the relevant predicate mask bit is zero.
 This would mean that a zero is inserted in place of `CR[BI+32]` for
 testing against `BO`, which may not be desirable in all circumstances.
 Therefore, an extra field is provided `SNZ`, which, if set, will insert
-a **one** in place of a masked-out element instead of a zero.
+a **one** in place of a masked-out element, instead of a zero.
 
 (*Note: Both options are provided because it is useful to deliberately
 cause the Branch-Conditional Vector testing to fail at a specific point,
@@ -85,47 +210,52 @@ controlled by the Predicate mask. This is particularly useful in `VLSET`
 mode, which will truncate SVSTATE.VL at the point of the first failed
 test.*)
 
-SVP64 RM `MODE` for Branch Conditional:
 
-| 0-1 |  2  |  3   4  |  description              |
-| --- | --- |---------|-------------------------- |
-| 00  | SNZ |  ALL sz | normal mode                      |
-| 01  | VLI |  ALL sz | VLSET mode                      |
-| 10  | SNZ |  ALL sz | svstep mode                      |
-| 11  | VLI |  ALL sz | svstep VLSET mode, in Horizontal-First        |
-| 11  | VLI |  SNZ sz | svstep VLSET mode, in Vertical-First    |
-
-Fields:
-
-* **sz**  if predication is enabled will put 4 copies of `SNZ` in place of
-  the src CR Field when the predicate bit is zero.  otherwise the element
-  is ignored or skipped, depending on context.
-* **ALL** when set, all branch conditional tests must pass in order for
-  the branch to succeed.
-* **VLI** In VLSET mode, VL is set equal (truncated) to the first
-  branch which succeeds.  If VLI (Vector Length Inclusive) is clear,
-  VL is truncated to *exclude* the current element, otherwise it is
-  included. SVSTATE.MVL is not changed.
-
-svstep mode will run an increment of SVSTATE srcstep and dststep
-(which is still useful in Horizontal First Mode).  Unlike `svstep.`
-however which updates only CR0 with the testing of REMAP loop progress,
-the CR Field is taken from the branch `BI` field, and updated prior to
-proceeding to each element branch conditional testing.
-
-Note that, interestingly, due to the useful side-effects of `VLSET` mode
-and `svstep` mode it is actually useful to use Branch Conditional even
+Normally, CTR mode will decrement once per Condition Test, resulting
+under normal circumstances that CTR reduces by up to VL in Horizontal-First
+Mode. Just as when v3.0B Branch-Conditional saves at
+least one instruction on tight inner loops through auto-decrementation
+of CTR, likewise it is also possible to save instruction count for
+SVP64 loops in both Vertical-First and Horizontal-First Mode, particularly
+in circumstances where there is conditional interaction between the
+element computation and testing, and the continuation (or otherwise)
+of a given loop. The potential combinations of interactions is why CTR
+testing options have been added.
+
+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
+by will end up being VL *after* truncation (should that occur). In
+other words, the order is strictly (as can be seen in pseudocode, below):
+
+1. compute the test
+2. (optionally) decrement CTR
+3. (optionally) truncate VL
+4. decide (based on step 1) whether to terminate looping
+   (including not executing step 5)
+5. decide whether to branch.
+
+CTR-test mode and CTi interaction is as follows: note that
+`BO[2]` is still required to be clear for decrements to be
+considered.
+
+* **CTR-test=0, CTi=0**: CTR decrements on a per-element basis
+  if `BO[2]` is zero. Masked-out elements when `sz=0` are
+  skipped.
+* **CTR-test=0, CTi=1**: CTR decrements on a per-element basis
+  if `BO[2]` is zero and a masked-out element is skipped
+  (`sz=0` and predicate bit is zero). This one special case is the
+  **opposite** of other combinations.
+* **CTR-test=1, CTi=0**: CTR decrements on a per-element basis
+  if `BO[2]` is zero and the Condition Test succeeds.
+  Masked-out elements when `sz=0` are skipped.
+* **CTR-test=1, CTi=1**: CTR decrements on a per-element basis
+  if `BO[2]` is zero and the Condition Test *fails*.
+  Masked-out elements when `sz=0` are skipped.
+
+Note that, interestingly, due to the side-effects of `VLSET` mode
+it is actually useful to use Branch Conditional even
 to perform no actual branch operation, i.e to point to the instruction
-after the branch.
-
-In particular, svstep mode is still useful for Horizontal-First Mode
-particularly in combination with REMAP. All "loop end" conditions
-will be tested on a per-element basis and placed into a Vector of CRs
-starting from the point specified by the Branch `BI` field.  This Vector
-of CR Fields may then be subsequently used as a Predicate Mask, and,
-furthermore, if VLSET mode was requested, VL will have been set to the
-length of one of the loop endpoints, again as specified by the bit from
-the Branch `BI` field.
+after the branch. Truncation of VL would thus conditionally occur yet control
+flow alteration would not.
 
 Also, the unconditional bit `BO[0]` is still relevant when Predication
 is applied to the Branch because in `ALL` mode all nonmasked bits have
@@ -133,6 +263,18 @@ to be tested. Even when svstep mode or VLSET mode are not used, CTR
 may still be decremented by the total number of nonmasked elements.
 In short, Vectorised Branch becomes an extremely powerful tool.
 
+`VLSET` mode with Vertical-First is particularly unusual. Vertical-First
+is used for explicit looping, where the looping is to terminate if the end
+of the Vector, VL, is reached. If however that loop is terminated early
+because VL is truncated, VLSET with Vertical-First becomes meaningless.
+Therefore, with `VSb`, the option to decide whether truncation should occur if the
+branch succeeds *or* if the branch condition fails allows for flexibility
+required.
+
+`VLSET` mode with Horizontal-First when `VSb` is clear is still
+useful, because it can be used to truncate VL to the first predicated
+(non-masked-out) element.
+
 Available options to combine:
 
 * `BO[0]` to make an unconditional branch would seem irrelevant if
@@ -146,31 +288,15 @@ Available options to combine:
   `OR` of all tests, respectively.
 
 In addition to the above, it is necessary to select whether, in `svstep`
-mode, the Vector CR Field is to be overwritten or not: in some cases
-it is useful to know but in others all that is needed is the branch itself.
-In the case of `sv.bc` there is no additional bitspace so the ``AA`
-field is re-interpreted instead to be `Rc`. For `sv.bclr`, there is free
-bitspace and so bit 16 has been chosen as `Rc`.
+mode, the Vector CR Field is to be overwritten or not: in some cases it
+is useful to know but in others all that is needed is the branch itself.
 
-**These interpretations are only available for sv.bc, they are NOT
-available for Power ISA v3.0B** i.e. only when embedded in an SVP64
-Prefix Context do these and all other parts of this specification
-apply.
+*Programming note: One important point is that SVP64 instructions are 64 bit.
+(8 bytes not 4). This needs to be taken into consideration when computing
+branch offsets: the offset is relative to the start of the instruction,
+which includes the SVP64 Prefix*
 
-Pseudocode for Rc in sv.bc
-
-```
-# Use bit 30 as Rc, disable AA
-Rc = AA
-AA = 0
-```
-
-Pseudocode for Rc in sv.bclr
-
-```
-# use bit 16 of opcode as Rc
-Rc = instr[16]
-```
+# Pseudocode and examples
 
 Pseudocode for Horizontal-First Mode:
 
@@ -181,15 +307,13 @@ for srcstep in range(VL):
     if predicate[srcstep]:
         # get SVP64 extended CR field 0..127
         SVCRf = SVP64EXTRA(BI>>2)
-        if svstep_mode then
-            new_srcstep, CRbits = SVSTATE_NEXT(srcstep)
-        else
-            CRbits = CR{SVCRf}
-        if Rc = 1 then # CR0 Vectorised
-            CR{0+srcstep} = CRbits
+        CRbits = CR{SVCRf}
         testbit = CRbits[BI & 0b11]
         # testbit = CR[BI+32+srcstep*4]
     else if not SVRMmode.sz:
+      # inverted CTR test skip mode
+      if ¬BO[2] & CTRtest & ¬CTI then
+         CTR = CTR - 1
         continue
     else
         testbit = SVRMmode.SNZ
@@ -201,7 +325,7 @@ for srcstep in range(VL):
     else
         cond_ok |= el_cond_ok
     # test for VL to be set (and exit)
-    if ~el_cond_ok and VLSET
+    if VLSET and VSb = el_cond_ok then
         if SVRMmode.VLI
             SVSTATE.VL = srcstep+1
         else
@@ -214,8 +338,8 @@ for srcstep in range(VL):
     else
         if el_cond_ok:
             break
-    if svstep_mode then
-        SVSTATE.srcstep = new_srcstep
+    if SVCRf.scalar:
+       break
 ```
 
 Pseudocode for Vertical-First Mode:
@@ -223,16 +347,16 @@ Pseudocode for Vertical-First Mode:
 ```
 # get SVP64 extended CR field 0..127
 SVCRf = SVP64EXTRA(BI>>2)
-if svstep_mode then
-    new_srcstep, CRbits = SVSTATE_NEXT(srcstep)
-else
-    CRbits = CR{SVCRf}
+CRbits = CR{SVCRf}
 # select predicate bit or zero/one
 if predicate[srcstep]:
-    if Rc = 1 then # CR0 vectorised
-        CR{0+srcstep} = CRbits
+    if BRc = 1 then # CR0 vectorised
+        CR{SVCRf+srcstep} = CRbits
     testbit = CRbits[BI & 0b11]
 else if not SVRMmode.sz:
+    # inverted CTR test skip mode
+    if ¬BO[2] & CTRtest & ¬CTI then
+       CTR = CTR - 1
     SVSTATE.srcstep = new_srcstep
     exit # no branch testing
 else
@@ -240,13 +364,30 @@ else
 # actual element test here
 cond_ok <- BO[0] | ¬(testbit ^ BO[1])
 # test for VL to be set (and exit)
-if ~cond_ok and VLSET
+if VLSET and cond_ok = VSb then
     if SVRMmode.VLI
         SVSTATE.VL = new_srcstep+1
     else
         SVSTATE.VL = new_srcstep
-if svstep_mode then
-    SVSTATE.srcstep = new_srcstep
+```
+
+v3.0B branch pseudocode including LRu and CTR skipping
+
+```
+if (mode_is_64bit) then M <- 0
+else M <- 32
+cond_ok <- BO[0] | ¬(CR[BI+32] ^ BO[1])
+ctrdec = ¬BO[2]
+if CTRtest & (cond_ok ^ CTi) then
+   ctrdec = 0b0
+if ctrdec then CTR <- CTR - 1
+ctr_ok <- BO[2] | ((CTR[M:63] != 0) ^ BO[3])
+lr_ok <- SVRMmode.LRu
+if ctr_ok & cond_ok then
+  if AA then NIA <-iea EXTS(BD || 0b00)
+  else       NIA <-iea CIA + EXTS(BD || 0b00)
+  lr_ok <- 0b1
+if LK & lr_ok then LR <-iea CIA + 4
 ```
 
 # Example Shader code