(no commit message)
[libreriscv.git] / openpower / sv / branches.mdwn
index 88f3626f2cafeba54f4a9267edc71834c3fd405b..75edd273c526e41571d77d17c955014c2eff0da4 100644 (file)
@@ -1,19 +1,29 @@
+[[!tag standards]]
 # SVP64 Branch Conditional behaviour
 
 **DRAFT STATUS**
 
 # SVP64 Branch Conditional behaviour
 
 **DRAFT STATUS**
 
-Please note: SVP64 Branch instructions should be
+Please note: although similar, SVP64 Branch instructions should be
 considered completely separate and distinct from
 standard scalar OpenPOWER-approved v3.0B branches.
 **v3.0B branches are in no way impacted, altered,
 changed or modified in any way, shape or form by
 the SVP64 Vectorised Variants**.
 
 considered completely separate and distinct from
 standard scalar OpenPOWER-approved v3.0B branches.
 **v3.0B branches are in no way impacted, altered,
 changed or modified in any way, shape or form by
 the SVP64 Vectorised Variants**.
 
+It is also
+extremely important to note that Branches are the
+sole semi-exception in SVP64 to `Scalar Identity Behaviour`.
+SVP64 Branches contain additional modes that are useful
+for scalar operations (i.e. even when VL=1 or when
+using single-bit predication).
+
 Links
 
 * <https://bugs.libre-soc.org/show_bug.cgi?id=664>
 * <http://lists.libre-soc.org/pipermail/libre-soc-dev/2021-August/003416.html>
 Links
 
 * <https://bugs.libre-soc.org/show_bug.cgi?id=664>
 * <http://lists.libre-soc.org/pipermail/libre-soc-dev/2021-August/003416.html>
+* <https://lists.libre-soc.org/pipermail/libre-soc-dev/2022-April/004678.html>
 * [[openpower/isa/branch]]
 * [[openpower/isa/branch]]
+* [[sv/cr_int_predication]]
 
 # Rationale
 
 
 # Rationale
 
@@ -34,7 +44,8 @@ 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 to run them.  3D GPU ISAs can test for this scenario
 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 to run them.  3D GPU ISAs can test for this scenario
-and jump over fully-masked-out operations, by spotting that
+and, with the appropriate predicate-analysis instruction,
+jump over fully-masked-out operations, by spotting that
 *all* Conditions are false.
 
 Unless Branches are aware and capable of such analysis, additional
 *all* Conditions are false.
 
 Unless Branches are aware and capable of such analysis, additional
@@ -46,7 +57,7 @@ Such instructions would be unavoidable, required, and costly
 by comparison to a single Vector-aware Branch.
 Therefore, in order to be commercially competitive, `sv.bc` and
 other Vector-aware Branch Conditional instructions are a high priority
 by comparison to a single Vector-aware Branch.
 Therefore, in order to be commercially competitive, `sv.bc` and
 other Vector-aware Branch Conditional instructions are a high priority
-for 3D GPU workloads.
+for 3D GPU (and OpenCL-style) workloads.
 
 Given that Power ISA v3.0B is already quite powerful, particularly
 the Condition Registers and their interaction with Branches, there
 
 Given that Power ISA v3.0B is already quite powerful, particularly
 the Condition Registers and their interaction with Branches, there
@@ -57,31 +68,42 @@ even if the branch points to the next instruction (no actual branch).
 
 # Overview
 
 
 # Overview
 
-When considering an "array" of branch-tests, there are four useful modes:
+When considering an "array" of branch-tests, there are four
+primarily-useful modes:
 AND, OR, NAND and NOR of all Conditions.
 AND, OR, NAND and NOR of all Conditions.
-NAND and NOR may be synthesised by
-inverting `BO[2]` which just leaves two modes:
+NAND and NOR may be synthesised from AND and OR by
+inverting `BO[1]` which just leaves two modes:
 
 
-* Branch takes place on the first CR Field test to succeed
+* 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
   (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.
 
 *Note: Early-exit is **MANDATORY** (required) behaviour.
 
 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.
 
 *Note: Early-exit is **MANDATORY** (required) behaviour.
-Branches **MUST** exit at the first failure point, for
+Branches **MUST** exit at the first sequentially-encountered
+failure point, for
 exactly the same reasons for which it is mandatory in
 programming languages doing early-exit: to avoid
 exactly the same reasons for which it is mandatory in
 programming languages doing early-exit: to avoid
-damaging side-effects. Speculative testing of Condition
-Register Fields is permitted, as is speculative updating
+damaging side-effects and to provide deterministic
+behaviour. Speculative testing of Condition
+Register Fields is permitted, as is speculative calculation
 of CTR, as long as, as usual in any Out-of-Order microarchitecture,
 of CTR, as long as, as usual in any Out-of-Order microarchitecture,
-that speculative testing is cancelled should an early-exit occur.*
+that speculative testing is cancelled should an early-exit occur.
+i.e. the speculation must be "precise": Program Order must be preserved*
+
+Also note that when early-exit occurs in Horizontal-first Mode,
+srcstep, dststep etc. are all reset, ready to begin looping from the
+beginning for the next instruction. However for Vertical-first
+Mode srcstep etc. are incremented "as usual" i.e. an early-exit
+has no special impact, regardless of whether the branch
+occurred or not. This can leave srcstep etc. in what may be
+considered an unusual
+state on exit from a loop and it is up to the programmer to
+reset srcstep, dststep etc. to known-good values.
 
 Additional useful behaviour involves two primary Modes (both of
 which may be enabled and combined):
 
 Additional useful behaviour involves two primary Modes (both of
 which may be enabled and combined):
@@ -90,6 +112,7 @@ which may be enabled and combined):
   for Arithmetic SVP64 operations, with more
   flexibility and a close interaction and integration into the
   underlying base Scalar v3.0B Branch instruction.
   for Arithmetic SVP64 operations, with more
   flexibility and a close interaction and integration into the
   underlying base Scalar v3.0B Branch instruction.
+  Truncation of VL takes place around the early-exit point.
 * **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*.
 * **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*.
@@ -100,9 +123,21 @@ 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.
 
 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.
+Predicate skipping or zeroing may, as usual with SVP64, be controlled
+by `sz`.
+Where the predicate is masked out and
+zeroing is enabled, then in such circumstances
+the same Boolean Logic Analysis dictates that
+rather than testing only against zero, the option to test
+against one is also prudent. This introduces a new
+immediate field, `SNZ`, which works in conjunction with
+`sz`.
+
+
+Vectorised Branches can be used
+in either SVP64 Horizontal-First or Vertical-First Mode. Essentially,
+at an element level, the behaviour is identical in both Modes,
+although the `ALL` bit is meaningless in Vertical-First Mode.
 
 It is also important
 to bear in mind that, fundamentally, Vectorised Branch-Conditional
 
 It is also important
 to bear in mind that, fundamentally, Vectorised Branch-Conditional
@@ -112,27 +147,40 @@ instructions are still
 *completely separate and independent*, being unaltered and
 unaffected by their SVP64 variants in every conceivable way.
 
 *completely separate and independent*, being unaltered and
 unaffected by their SVP64 variants in every conceivable way.
 
+*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*
+
 # Format and fields
 
 # Format and fields
 
+With element-width overrides being meaningless for Condition
+Register Fields, bits 4 thru 7 of SVP64 RM may be used for additional
+Mode bits.
+
 SVP64 RM `MODE` (includes `ELWIDTH` and `ELWIDTH_SRC` bits) for Branch
 Conditional:
 
 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   |
+| 4 | 5 | 6 | 7 | 17 | 18 | 19 | 20 |  21 | 22  23 |  description     |
+| - | - | - | - | -- | -- | -- | -- | --- |--------|----------------- |
+|ALL|SNZ| / | / |    |    | 0  | 0  | /   | LRu sz | normal mode      |
+|ALL|SNZ| / |VSb|    |    | 0  | 1  | VLI | LRu sz | VLSET mode       |
+|ALL|SNZ|CTi| / |    |    | 1  | 0  | /   | LRu sz | CTR-test mode         |
+|ALL|SNZ|CTi|VSb|    |    | 1  | 1  | VLI | LRu sz | CTR-test+VLSET mode   |
+
+TODO bits 17,18 for SVSTATE-variant of LR and LRu.
 
 Brief description of fields:
 
 * **sz=1** if predication is enabled and `sz=1` and a predicate
   element bit is zero, `SNZ` will
 
 Brief description of fields:
 
 * **sz=1** if predication is enabled and `sz=1` and a predicate
   element bit is zero, `SNZ` will
-  be substituted in place of the CR bit selected by `BI`.
-  the src CR Field when the predicate bit is zero. Contrast this with
+  be substituted in place of the CR bit selected by `BI`,
+  as the Condition tested.
+  Contrast this with
   normal SVP64 `sz=1` behaviour, where *only* a zero is put in
   place of masked-out predicate bits.
   normal SVP64 `sz=1` behaviour, where *only* a zero is put in
   place of masked-out predicate bits.
-* **sz=0** When `sz=0` skipping occurs as usual, but unlike all
+* **sz=0** When `sz=0` skipping occurs as usual on
+  masked-out elements, but unlike all
   other SVP64 behaviour which entirely skips an element with
   no related side-effects at all, there are certain
   special circumstances where CTR
   other SVP64 behaviour which entirely skips an element with
   no related side-effects at all, there are certain
   special circumstances where CTR
@@ -143,31 +191,44 @@ Brief description of fields:
   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.
   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.
+  In VLSET mode, VL *may* (depending on `VSb`) be truncated.
   If VLI (Vector Length Inclusive) is clear,
   VL is truncated to *exclude* the current element, otherwise it is
   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.
+  included. SVSTATE.MVL is not altered: only VL.
+* **LRu**: Link Register Update, used in conjunction with LK=1
+  to make LR update conditional
+* **VSb** In VLSET Mode, after testing,
+  if VSb is set, VL is truncated if the test succeeds.  If VSb is clear,
+  VL is truncated if a test *fails*. Masked-out (skipped)
+  bits are not considered
+  part of testing when `sz=0`
 * **CTi** CTR inversion. CTR-test Mode normally decrements per element
   tested. CTR inversion decrements if a test *fails*. Only relevant
   in CTR-test Mode.
 
 * **CTi** CTR inversion. CTR-test Mode normally decrements per element
   tested. CTR inversion decrements if a test *fails*. Only relevant
   in CTR-test Mode.
 
+LRu and CTR-test modes are where SVP64 Branches subtly differ from
+Scalar v3.0B Branches. `sv.bcl` for example will always update LR, whereas
+`sv.bcl/lru` will only update LR if the branch succeeds.
+
+Of special interest is that when using ALL Mode (Great Big AND
+of all Condition Tests), if `VL=0`,
+which is rare but can occur in Data-Dependent Modes, the Branch
+will always take place because there will be no failing Condition
+Tests to prevent it. Likewise when not using ALL Mode (Great Big OR
+of all Condition Tests) and `VL=0` the Branch is guaranteed not
+to occur because there will be no *successful* Condition Tests
+to make it happen.
+
 # 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
 # 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.
+as either Scalar or Vector. It is also crucially important to keep in mind
+that for CRs, SVP64 sequentially increments the CR *Field* numbers.
+CR *Fields* are treated as elements, not bit-numbers of the CR *register*.
 
 
-The `BI` field of Branch Conditional operations is five bits, in scalar
+The `BI` operand of Branch Conditional operations is five bits, in scalar
 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
 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
@@ -177,7 +238,8 @@ as specified in SVP64 [[sv/svp64/appendix]].
 
 When the CR Fields selected by SVP64-Augmented `BI` is marked as scalar,
 then as the usual SVP64 rules apply:
 
 When the CR Fields selected by SVP64-Augmented `BI` is marked as scalar,
 then as the usual SVP64 rules apply:
-the Vector loop ends at the first element tested, after taking
+the Vector loop ends at the first element tested
+(the first CR *Field*), 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
 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
@@ -186,11 +248,15 @@ one element is tested.
 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
 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 
-the unique properties associated with conditionally
+how SVP64 is fundamentally applied, except with respect to:
+
+* the unique properties associated with conditionally
  changing the Program
 Counter (aka "a Branch"), resulting in early-out
  changing the Program
 Counter (aka "a Branch"), resulting in early-out
-opportunities and CTR-testing, which are outlined below.
+opportunities
+* CTR-testing
+
+Both are outlined below, in later sections.
 
 # Horizontal-First and Vertical-First Modes
 
 
 # Horizontal-First and Vertical-First Modes
 
@@ -238,7 +304,6 @@ 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.*)
 
 mode, which will truncate SVSTATE.VL at the point of the first failed
 test.*)
 
-
 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
 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
@@ -250,24 +315,68 @@ 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.
 
 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):
+Also, the unconditional bit `BO[0]` is still relevant when Predication
+is applied to the Branch because in `ALL` mode all nonmasked bits have
+to be tested, and when `sz=0` skipping occurs.
+Even when VLSET mode is not used, CTR
+may still be decremented by the total number of nonmasked elements,
+acting in effect as either a popcount or cntlz depending on which
+mode bits are set.
+In short, Vectorised Branch becomes an extremely powerful tool.
 
 
-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.
+**Micro-Architectural Implementation Note**: *when implemented on
+top of a Multi-Issue Out-of-Order Engine it is possible to pass
+a copy of the predicate and the prerequisite CR Fields to all
+Branch Units, as well as the current value of CTR at the time of
+multi-issue, and for each Branch Unit to compute how many times
+CTR would be subtracted, in a fully-deterministic and parallel
+fashion. A SIMD-based Branch Unit, receiving and processing
+multiple CR Fields covered by multiple predicate bits, would
+do the exact same thing. Obviously, however, if CTR is modified
+within any given loop (mtctr) the behaviour of CTR is no longer
+deterministic.*
+
+## Link Register Update
+
+For a Scalar Branch, unconditional updating of the Link Register
+LR is useful and practical. However, if a loop of CR Fields is
+tested, unconditional updating of LR becomes problematic.
+
+For example when using `bclr` with `LRu=1,LK=0` in Horizontal-First Mode,
+LR's value will be unconditionally overwritten after the first element,
+such that for execution (testing) of the second element, LR
+has the value `CIA+8`. This is covered in the `bclrl` example, in
+a later section.
+
+The addition of a LRu bit modifies behaviour in conjunction
+with LK, as follows:
+
+* `sv.bc` When LRu=0,LK=0, Link Register is not updated
+* `sv.bcl` When LRu=0,LK=1, Link Register is updated unconditionally
+* `sv.bcl/lru` When LRu=1,LK=1, Link Register will
+  only be updated if the Branch Condition fails.
+* `sv.bc/lru` When LRu=1,LK=0, Link Register will only be updated if
+  the Branch Condition succeeds.
+
+This avoids
+destruction of LR during loops (particularly Vertical-First
+ones).
+
+## CTR-test
+
+Where a standard Scalar v3.0B branch unconditionally decrements
+CTR when `BO[2]` is clear, CTR-test Mode introduces more flexibility
+which allows CTR to be used for many more types of Vector loops
+constructs.
 
 CTR-test mode and CTi interaction is as follows: note that
 
 CTR-test mode and CTi interaction is as follows: note that
-`BO[2]` is still required to be clear for decrements to be
-considered.
+`BO[2]` is still required to be clear for CTR decrements to be
+considered, exactly as is the case in Scalar Power ISA v3.0B
 
 * **CTR-test=0, CTi=0**: CTR decrements on a per-element basis
   if `BO[2]` is zero. Masked-out elements when `sz=0` are
 
 * **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.
+  skipped (i.e. CTR is *not* decremented when the predicate
+  bit is zero and `sz=0`).
 * **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
 * **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
@@ -275,15 +384,27 @@ considered.
   completely different from normal SVP64 `sz=0` behaviour)
 * **CTR-test=1, CTi=0**: CTR decrements on a per-element basis
   if `BO[2]` is zero and the Condition Test succeeds.
   completely different from normal SVP64 `sz=0` behaviour)
 * **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.
+  Masked-out elements when `sz=0` are skipped (including
+  not decrementing CTR)
 * **CTR-test=1, CTi=1**: CTR decrements on a per-element basis
   if `BO[2]` is zero and the Condition Test *fails*.
 * **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.
+  Masked-out elements when `sz=0` are skipped (including
+  not decrementing CTR)
 
 `CTR-test=0, CTi=1, sz=0` requires special emphasis because it is the
 only time in the entirety of SVP64 that has side-effects when
 a predicate mask bit is clear.  **All** other SVP64 operations
 entirely skip an element when sz=0 and a predicate mask bit is zero.
 
 `CTR-test=0, CTi=1, sz=0` requires special emphasis because it is the
 only time in the entirety of SVP64 that has side-effects when
 a predicate mask bit is clear.  **All** other SVP64 operations
 entirely skip an element when sz=0 and a predicate mask bit is zero.
+It is also critical to emphasise that in this unusual mode, 
+no other side-effects occur: **only** CTR is decremented, i.e. the
+rest of the Branch operation is skipped.
+
+## VLSET Mode
+
+VLSET Mode truncates the Vector Length so that subsequent instructions
+operate on a reduced Vector Length. This is similar to
+Data-dependent Fail-First and LD/ST Fail-First, where for VLSET the
+truncation occurs at the Branch decision-point.
 
 Interestingly, due to the side-effects of `VLSET` mode
 it is actually useful to use Branch Conditional even
 
 Interestingly, due to the side-effects of `VLSET` mode
 it is actually useful to use Branch Conditional even
@@ -291,39 +412,89 @@ to perform no actual branch operation, i.e to point to the instruction
 after the branch. Truncation of VL would thus conditionally occur yet control
 flow alteration would not.
 
 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
-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
 `VLSET` mode with Vertical-First is particularly unusual. Vertical-First
-is dedigned to be used for explicit looping, where an explicit call to
+is designed to be used for explicit looping, where an explicit call to
 `svstep` is required to move both srcstep and dststep on to
 `svstep` is required to move both srcstep and dststep on to
-the next element, until VL (or other condition)is reached.
+the next element, until VL (or other condition) is reached.
 Vertical-First Looping is expected (required) 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.
 Vertical-First Looping is expected (required) 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.
+Resolving this would require two branches: one Conditional, the other
+branching unconditionally to create the loop, where the Conditional
+one jumps over it.
+
 Therefore, with `VSb`, the option to decide whether truncation should occur if the
 branch succeeds *or* if the branch condition fails allows for the flexibility
 required.  This allows a Vertical-First Branch to *either* be used as
 a branch-back (loop) *or* as part of a conditional exit or function
 call from *inside* a loop, and for VLSET to be integrated into both
 Therefore, with `VSb`, the option to decide whether truncation should occur if the
 branch succeeds *or* if the branch condition fails allows for the flexibility
 required.  This allows a Vertical-First Branch to *either* be used as
 a branch-back (loop) *or* as part of a conditional exit or function
 call from *inside* a loop, and for VLSET to be integrated into both
-types of decision-making.
+types of decision-making.  
 
 
-`VLSET` mode with Horizontal-First when `VSb` is clear is still
+In the case of a Vertical-First branch-back (loop), with `VSb=0` the branch takes
+place if success conditions are met, but on exit from that loop
+(branch condition fails), VL will be truncated. This is extremely
+useful.
+
+`VLSET` mode with Horizontal-First when `VSb=0` is still
 useful, because it can be used to truncate VL to the first predicated
 (non-masked-out) element.
 
 useful, because it can be used to truncate VL to the first predicated
 (non-masked-out) element.
 
-*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*
+The truncation point for VL, when VLi is clear, must not include skipped
+elements that preceded the current element being tested.
+Example: `sz=0, VLi=0, predicate mask = 0b110010` and the Condition
+Register failure point is at CR Field element 4.
+
+* Testing at element 0 is skipped because its predicate bit is zero
+* Testing at element 1 passed
+* Testing elements 2 and 3 are skipped because their
+  respective predicate mask bits are zero
+* Testing element 4 fails therefore VL is truncated to **2**
+  not 4 due to elements 2 and 3 being skipped.
+
+If `sz=1` in the above example *then* VL would have been set to 4 because
+in non-zeroing mode the zero'd elements are still effectively part of the
+Vector (with their respective elements set to `SNZ`)
+
+If `VLI=1` then VL would be set to 5 regardless of sz, due to being inclusive
+of the element actually being tested.
+
+## VLSET and CTR-test combined
+
+If both CTR-test and VLSET Modes are requested, it's important to
+observe the correct order. What occurs depends on whether VLi
+is enabled, because VLi affects the length, VL.
+
+If VLi (VL truncate inclusive) is set:
+
+1. compute the test including whether CTR triggers
+2. (optionally) decrement CTR
+3. (optionally) truncate VL (VSb inverts the decision)
+4. decide (based on step 1) whether to terminate looping
+   (including not executing step 5)
+5. decide whether to branch.
+
+If VLi is clear, then when a test fails that element
+and any following it
+should **not** be considered part of the Vector. Consequently:
+
+1. compute the branch test including whether CTR triggers
+2. if the test fails against VSb, truncate VL to the *previous*
+   element, and terminate looping. No further steps executed.
+3. (optionally) decrement CTR
+4. decide whether to branch.
 
 # Boolean Logic combinations
 
 
 # Boolean Logic combinations
 
-There are an extraordinary number of different combinations which
-provide completely different and useful behaviour.
+In a Scalar ISA, Branch-Conditional testing even of vector
+results may be performed through inversion of tests. NOR of
+all tests may be performed by inversion of the scalar condition
+and branching *out* from the scalar loop around elements,
+using scalar operations.
+
+In a parallel (Vector) ISA it is the ISA itself which must perform
+the prerequisite logic manipulation.
+Thus for SVP64 there are an extraordinary number of nesessary combinations 
+which provide completely different and useful behaviour.
 Available options to combine:
 
 * `BO[0]` to make an unconditional branch would seem irrelevant if
 Available options to combine:
 
 * `BO[0]` to make an unconditional branch would seem irrelevant if
@@ -340,7 +511,13 @@ Available options to combine:
 * `sz` and `SNZ` to insert either zeros or ones in place of masked-out
   predicate bits
 * `ALL` or `ANY` behaviour corresponding to `AND` of all tests and
 * `sz` and `SNZ` to insert either zeros or ones in place of masked-out
   predicate bits
 * `ALL` or `ANY` behaviour corresponding to `AND` of all tests and
-  `OR` of all tests, respectively. 
+  `OR` of all tests, respectively.
+* Predicate Mask bits, which combine in effect with the CR being
+  tested.
+* Inversion of Predicate Masks (`~r3` instead of `r3`, or using
+  `NE` rather than `EQ`) which results in an additional
+  level of possible ANDing, ORing etc. that would otherwise
+  need explicit instructions.
 
 The most obviously useful combinations here are to set `BO[1]` to zero
 in order to turn `ALL` into Great-Big-NAND and `ANY` into
 
 The most obviously useful combinations here are to set `BO[1]` to zero
 in order to turn `ALL` into Great-Big-NAND and `ANY` into
@@ -349,13 +526,68 @@ have to work round the fact that the Condition Testing is NOR or NAND.
 The alternative to not having additional behavioural inversion
 (`SNZ`, `VSb`, `CTi`) would be to have a second (unconditional)
 branch directly after the first, which the first branch jumps over.
 The alternative to not having additional behavioural inversion
 (`SNZ`, `VSb`, `CTi`) would be to have a second (unconditional)
 branch directly after the first, which the first branch jumps over.
-This contrived construct is avoided by the behavioural inversion bits.
+This contrivance is avoided by the behavioural inversion bits.
 
 # Pseudocode and examples
 
 
 # Pseudocode and examples
 
-Pseudocode for Horizontal-First Mode:
+Please see [[svp64/appendix]] regarding CR bit ordering and for
+the definition of `CR{n}`
+
+For comparative purposes this is a copy of the v3.0B `bc` pseudocode
+
+```
+if (mode_is_64bit) then M <- 0
+else M <- 32
+if ¬BO[2] then CTR <- CTR - 1
+ctr_ok <- BO[2] | ((CTR[M:63] != 0) ^ BO[3])
+cond_ok <- BO[0] | ¬(CR[BI+32] ^ BO[1])
+if ctr_ok & cond_ok then
+  if AA then NIA <-iea EXTS(BD || 0b00)
+  else       NIA <-iea CIA + EXTS(BD || 0b00)
+if LK then LR  <-iea  CIA + 4
+```
+
+Simplified pseudocode including LRu and CTR skipping, which illustrates
+clearly that SVP64 Scalar Branches (VL=1) are **not** identical to
+v3.0B Scalar Branches.  The key areas where differences occur are
+the inclusion of predication (which can still be used when VL=1), in
+when and why CTR is decremented (CTRtest Mode) and whether LR is
+updated (which is unconditional in v3.0B when LK=1, and conditional
+in SVP64 when LRu=1).
+
+```
+if (mode_is_64bit) then M <- 0
+else M <- 32
+testbit = CR[BI+32]
+if ¬predicate_bit then testbit = SVRMmode.SNZ
+ctr_ok <- BO[2] | ((CTR[M:63] != 0) ^ BO[3])
+cond_ok <- BO[0] | ¬(testbit ^ BO[1])
+if ¬predicate_bit & ¬SVRMmode.sz then
+  if ¬BO[2] & CTRtest & ¬CTi then
+    CTR = CTR - 1
+  # instruction finishes here
+else
+  if ¬BO[2] & ¬(CTRtest & (cond_ok ^ CTi)) then CTR <- CTR - 1
+  if VLSET and VSb = (cond_ok & ctr_ok) then
+    if SVRMmode.VLI then SVSTATE.VL = srcstep+1
+    else                 SVSTATE.VL = srcstep
+  lr_ok <- LK
+  if ctr_ok & cond_ok then
+    if AA then NIA <-iea EXTS(BD || 0b00)
+    else       NIA <-iea CIA + EXTS(BD || 0b00)
+    if SVRMmode.LRu then lr_ok <- ¬lr_ok
+  if lr_ok then LR <-iea CIA + 4
+```
+
+Below is the pseudocode for SVP64 Branches, which is a little less
+obvious but identical to the above. The lack of obviousness is down
+to the early-exit opportunities.
+
+Effective pseudocode for Horizontal-First Mode:
 
 ```
 
 ```
+if (mode_is_64bit) then M <- 0
+else M <- 32
 cond_ok = not SVRMmode.ALL
 for srcstep in range(VL):
     # select predicate bit or zero/one
 cond_ok = not SVRMmode.ALL
 for srcstep in range(VL):
     # select predicate bit or zero/one
@@ -366,35 +598,43 @@ for srcstep in range(VL):
         testbit = CRbits[BI & 0b11]
         # testbit = CR[BI+32+srcstep*4]
     else if not SVRMmode.sz:
         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
+        # inverted CTR test skip mode
+        if ¬BO[2] & CTRtest & ¬CTI then
+          CTR = CTR - 1
+        continue # skip to next element
     else
         testbit = SVRMmode.SNZ
     # actual element test here
     else
         testbit = SVRMmode.SNZ
     # actual element test here
+    ctr_ok <- BO[2] | ((CTR[M:63] != 0) ^ BO[3])   
     el_cond_ok <- BO[0] | ¬(testbit ^ BO[1])
     el_cond_ok <- BO[0] | ¬(testbit ^ BO[1])
+    # check if CTR dec should occur
+    ctrdec = ¬BO[2]
+    if CTRtest & (el_cond_ok ^ CTi) then
+       ctrdec = 0b0
+    if ctrdec then CTR <- CTR - 1
     # merge in the test
     if SVRMmode.ALL:
     # merge in the test
     if SVRMmode.ALL:
-        cond_ok &= el_cond_ok
+        cond_ok &= (el_cond_ok & ctr_ok)
     else
     else
-        cond_ok |= el_cond_ok
+        cond_ok |= (el_cond_ok & ctr_ok)
     # test for VL to be set (and exit)
     # test for VL to be set (and exit)
-    if VLSET and VSb = el_cond_ok then
-        if SVRMmode.VLI
-            SVSTATE.VL = srcstep+1
-        else
-            SVSTATE.VL = srcstep
+    if VLSET and VSb = (el_cond_ok & ctr_ok) then
+        if SVRMmode.VLI then SVSTATE.VL = srcstep+1
+        else                 SVSTATE.VL = srcstep
         break
     # early exit?
         break
     # early exit?
-    if SVRMmode.ALL:
-        if ~el_cond_ok:
-            break
-    else
-        if el_cond_ok:
-            break
+    if SVRMmode.ALL != (el_cond_ok & ctr_ok):
+         break
+    # SVP64 rules about Scalar registers still apply!
     if SVCRf.scalar:
        break
     if SVCRf.scalar:
        break
+# loop finally done, now test if branch (and update LR)
+lr_ok <- LK
+if cond_ok then
+    if AA then NIA <-iea EXTS(BD || 0b00)
+    else       NIA <-iea CIA + EXTS(BD || 0b00)
+    if SVRMmode.LRu then lr_ok <- ¬lr_ok
+if lr_ok then LR <-iea CIA + 4
 ```
 
 Pseudocode for Vertical-First Mode:
 ```
 
 Pseudocode for Vertical-First Mode:
@@ -426,28 +666,10 @@ if VLSET and cond_ok = VSb then
         SVSTATE.VL = new_srcstep
 ```
 
         SVSTATE.VL = 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
 
 ```
 # Example Shader code
 
 ```
+// assume f() g() or h() modify a and/or b
 while(a > 2) {
     if(b < 5)
         f();
 while(a > 2) {
     if(b < 5)
         f();
@@ -463,13 +685,18 @@ which compiles to something like:
 vec<i32> a, b;
 // ...
 pred loop_pred = a > 2;
 vec<i32> a, b;
 // ...
 pred loop_pred = a > 2;
+// loop continues while any of a elements greater than 2
 while(loop_pred.any()) {
 while(loop_pred.any()) {
+    // vector of predicate bits
     pred if_pred = loop_pred & (b < 5);
     pred if_pred = loop_pred & (b < 5);
+    // only call f() if at least 1 bit set
     if(if_pred.any()) {
         f(if_pred);
     }
 label1:
     if(if_pred.any()) {
         f(if_pred);
     }
 label1:
+    // loop mask ANDs with inverted if-test
     pred else_pred = loop_pred & ~if_pred;
     pred else_pred = loop_pred & ~if_pred;
+    // only call g() if at least 1 bit set
     if(else_pred.any()) {
         g(else_pred);
     }
     if(else_pred.any()) {
         g(else_pred);
     }
@@ -480,8 +707,8 @@ label1:
 which will end up as:
 
 ```
 which will end up as:
 
 ```
-   sv.cmpi CR60.v a.v, 2      # vector compare a into CR60 vector
-   sv.crweird r30, CR60.GT # transfer GT vector to r30
+   # start from while loop test point
+   b looptest
 while_loop:
    sv.cmpi CR80.v, b.v, 5     # vector compare b into CR64 Vector
    sv.bc/m=r30/~ALL/sz CR80.v.LT skip_f # skip when none
 while_loop:
    sv.cmpi CR80.v, b.v, 5     # vector compare b into CR64 Vector
    sv.bc/m=r30/~ALL/sz CR80.v.LT skip_f # skip when none
@@ -499,5 +726,80 @@ skip_f:
 skip_g:
    # conditionally call h(r30) if any loop pred set
    sv.bclr/m=r30/~ALL/sz BO[1]=1 h()
 skip_g:
    # conditionally call h(r30) if any loop pred set
    sv.bclr/m=r30/~ALL/sz BO[1]=1 h()
+looptest:
+   sv.cmpi CR60.v a.v, 2      # vector compare a into CR60 vector
+   sv.crweird r30, CR60.GT # transfer GT vector to r30
    sv.bc/m=r30/~ALL/sz BO[1]=1 while_loop
    sv.bc/m=r30/~ALL/sz BO[1]=1 while_loop
+end:
+```
+# TODO LRu example
+
+show why LRu would be useful in a loop.  Imagine the following
+c code:
+
+```
+for (int i = 0; i < 8; i++) {
+    if (x < y) break;
+}
+```
+
+Under these circumstances exiting from the loop is not only
+based on CTR it has become conditional on a CR result.
+Thus it is desirable that NIA *and* LR only be modified
+if the conditions are met
+
+
+v3.0 pseudocode for `bclrl`:
+
+```
+if (mode_is_64bit) then M <- 0
+else M <- 32
+if ¬BO[2]  then CTR <- CTR - 1
+ctr_ok <- BO[2] | ((CTR[M:63] != 0) ^ BO[3])
+cond_ok <- BO[0] | ¬(CR[BI+32] ^  BO[1])
+if ctr_ok & cond_ok then NIA <-iea LR[0:61] || 0b00
+if LK then LR <-iea CIA + 4
+```
+
+the latter part for SVP64 `bclrl` becomes:
+
+```
+for i in 0 to VL-1:
+    ...
+    ...
+    cond_ok <- BO[0] | ¬(CR[BI+32] ^  BO[1])
+    lr_ok <- LK
+    if ctr_ok & cond_ok then
+       NIA <-iea LR[0:61] || 0b00
+       if SVRMmode.LRu then lr_ok <- ¬lr_ok
+    if lr_ok then LR <-iea CIA + 4
+    # if NIA modified exit loop
+```
+
+The reason why should be clear from this being a Vector loop:
+unconditional destruction of LR when LK=1 makes `sv.bclrl`
+ineffective, because the intention going into the loop is
+that the branch should be to the copy of LR set at the *start*
+of the loop, not half way through it.
+However if the change to LR only occurs if
+the branch is taken then it becomes a useful instruction.
+
+The following pseudocode should **not** be implemented because
+it violates the fundamental principle of SVP64 which is that
+SVP64 looping is a thin wrapper around Scalar Instructions.
+The pseducode below is more an actual Vector ISA Branch and
+as such is not at all appropriate:
+
+```
+for i in 0 to VL-1:
+    ...
+    ...
+    cond_ok <- BO[0] | ¬(CR[BI+32] ^  BO[1])
+    if ctr_ok & cond_ok then NIA <-iea LR[0:61] || 0b00
+# only at the end of looping is LK checked.
+# this completely violates the design principle of SVP64
+# and would actually need to be a separate (scalar)
+# instruction "set LR to CIA+4 but retrospectively"
+# which is clearly impossible
+if LK then LR <-iea CIA + 4
 ```
 ```