(no commit message)
[libreriscv.git] / openpower / sv / svp64_quirks.mdwn
index 404dbf564c597fdcac357c0cc4a8a75cc4212e6f..43d7249df22871f5bf4e230c0bd6acd6501e1873 100644 (file)
 # The Rules
 
 # The Rules
 
-SVP64 is designed around these fundamental and inviolate principles:
+[[!toc]]
+
+SVP64 is designed around fundamental and inviolate RISC principles.
+This gives a uniformity and regularity to the ISA, making implementation
+straightforward, which was why RISC
+as a concept became popular.
 
 1. There are no actual Vector instructions: Scalar instructions
    are the sole exclusive bedrock.
 2. No scalar instruction ever deviates in its encoding or meaning
 
 1. There are no actual Vector instructions: Scalar instructions
    are the sole exclusive bedrock.
 2. No scalar instruction ever deviates in its encoding or meaning
-   just because it is prefixed.
-3. A hardware-level for-loop makes vector elements 100% synonymous
-   with scalar instructions (the suffix)
+   just because it is prefixed (semantic caveats below)
+3. A hardware-level for-loop (the prefix) makes vector elements
+   100% synonymous with scalar instructions (the suffix)
+4. Exactly as with Scalar RISC ISAs, the uniformity does produce
+   "holes" in the encoding or some strange combinations.
+
+How can a Vector ISA even exist when no actual Vector instructions
+are permitted to be added? It comes down to the strict RISC abstraction.
+First you start from a **scalar** instruction (32-bit). Second, the
+Prefixing is applied *in the abstract* to give the *appearance*
+and ultimately the same effect as if an explicit Vector instruction
+had also been added.  Looking at the pseudocode of any Vector ISA
+(RVV, NEC SX Aurora, Cray)
+they always comprise (a) a for-loop around (b) element-based operations.
+It is perfectly reasonable and rational to separate (a) from (b)
+then find a powerful pre-existing
+Supercomputing-class ISA that qualifies for (b).
 
 
-That said, there are a few exceptional places where these rules get
+There are a few exceptional places where these rules get
 bent, and others where the rules take some explaining,
 bent, and others where the rules take some explaining,
-and this page tracks them.
+and this page tracks them all.
+
+The modification caveat in (2) above semantically
+exempts element width overrides,
+which still do not actually modify the meaning of the instruction:
+an add remains an add, even if its override makes it an 8-bit add rather than
+a 64-bit add. Even add-with-carry remains an add-with-carry: it's just
+that when elwidth=8 in the Prefix it's an *8-bit* add-with-carry
+where the 9th bit becomes Carry-out (not the 65th bit).
+In other words, elwidth overrides **definitely** do not fundamentally
+alter the actual
+Scalar v3.0 ISA encoding itself.  Consequently we can still, in
+the strictest semantic sense, not be breaking rule (2).
+
+Likewise, other "modifications" such as saturation or Data-dependent
+Fail-First likewise are actually post-augmentation or post-analysis, and do
+not fundamentally change an add operation into a subtract
+for example, and under absolutely no circumstances do the actual 32-bit
+Scalar v3.0 operand field bits change or the number of operands change.
 
 
-*(An experiment was attempted to modify LD-immediate instructions
+In an early Draft of SVP64,
+an experiment was attempted, to modify LD-immediate instructions
 to include a
 third RC register i.e. reinterpret the normal
 to include a
 third RC register i.e. reinterpret the normal
-v3.0 32-bit instruction as a
-different encoding if SVP64-prefixed: it did not go well.
+v3.0 32-bit instruction as a completely
+different encoding if SVP64-prefixed. It did not go well.
 The complexity that resulted
 The complexity that resulted
-in the decode phase was too great)*
+in the decode phase was too great. The lesson was learned, the
+hard way: it would be infinitely preferable
+to add a 32-bit Scalar Load-with-Shift
+instruction *first*, which then inherently becomes Vectorised.
+Perhaps a future Power ISA spec will have this Load-with-Shift instruction:
+both ARM and x86 have it, because it saves greatly on instruction count in
+hot-loops.
+
+The other reason for not adding an SVP64-Prefixed instruction without
+also having it as a Scalar un-prefixed instruction is that if the
+32-bit encoding is ever allocated in a future revision
+of the Power ISA
+to a completely unrelated operation
+then how can a Vectorised version of that new instruction ever be added?
+The uniformity and RISC Abstraction is irreparably damaged.
+Bottom line here is that the fundamental RISC Principle is strictly adhered
+to, even though these are Advanced 64-bit Vector instructions.
+Advocates of the RISC Principle will appreciate the uniformity of
+SVP64 and the level of systematic abstraction kept between Prefix and Suffix.
+
+# Instruction Groups
+
+The basic principle of SVP64 is the prefix, which contains mode
+as well as register augmentation and predicates.  When thinking of
+instructions and Vectorising them, it is natural for arithmetic
+operations (ADD, OR) to be the first to spring to mind.
+Arithmetic instructions have registers, therefore augmentation
+applies, end of story, right?
+
+Except, Load and Store deals also with Memory, not just registers.
+Power ISA has Condition Register Fields: how can element widths
+apply there? And branches: how can you have Saturation on something
+that does not return an arithmetic result? In short: there are actually
+four different categories (five including those for which Vectorisation
+makes no sense at all, such as `sc` or `mtmsr`). The categories are:
+
+* arithmetic/logical including floating-point
+* Load/Store
+* Condition Register Field operations
+* branch
+
+**Arithmetic**
+
+Arithmetic (known as "normal" mode) is where Scalar and Parallel
+Reduction can be done: Saturation as well, and two new innovative
+modes for Vector ISAs: data-dependent fail-first and predicate result.
+Reduction and Saturation are common to see in Vector ISAs: it is just
+that they are usually added as explicit instructions,
+and NEC SX Aurora has even more iterative instructions. In SVP64 these
+concepts are applied in the abstract general form, which takes some
+getting used to.
+
+Reduction may, when applied to non-commutative
+instructions incorrectly, result in invalid results, but ultimately
+it is critical to think in terms of the "rules", that everything is
+Scalar instructions in strict Program Order.  Reduction on non-commutative
+Scalar Operations is not *prohibited*: the strict Program Order allows
+the programmer to think through what would happen and thus potentially
+actually come up with legitimate use.
+
+**Branches**
+
+Branch is the one and only place where the Scalar
+(non-prefixed) operations differ from the Vector (element)
+instructions (as explained in a separate section) although
+a case could be made for the perspective that they are identical,
+but the defaults for new parameters in the Scalar case makes branch
+identical to Power ISA v3.1 Scalar branches.
+
+The
+RM bits can be used for other purposes because the Arithmetic modes
+make no sense at all for a Branch.
+Almost the entire
+SVP64 RM Field is interpreted differently from other Modes, in
+order to support a wide range of parallel boolean condition options
+which are expected of a Vector / GPU ISA. These save a considerable
+number of instructions in tight inner loop situations.
+
+**CR Field Ops**
+
+Condition Register Fields are 4-bit wide and consequently element-width
+overrides make absolutely no sense whatsoever. Therefore the elwidth
+override field bits can be used for other purposes when Vectorising
+CR Field instructions.  Moreover, Rc=1 is completely invalid for
+CR operations such as `crand`: Rc=1 is for arithmetic operations, producing
+a "co-result" that goes into CR0 or CR1. Thus, the Arithmetic modes
+such as predicate-result make no sense, and neither does Saturation.
+All of these differences, which require quite a lot of logical
+reasoning and deduction, help explain why there is an entirely different
+CR ops Vectorisation Category.
+
+A particularly strange quirk of CR-based Vector Operations is that the
+Scalar Power ISA CR Register is 32-bits, but actually comprises eight
+CR Fields, CR0-CR7. With each CR Field being four bits (EQ, LT, GT, SO)
+this makes up 32 bits, and therefore a CR operand referring to one bit
+of the CR will be 5 bits in length (BA, BT).
+*However*, some instructions refer
+to a *CR Field* (CR0-CR7) and consequently these operands
+(BF, BFA etc) are only 3-bits.
+
+(*It helps here to think of the top 3 bits of BA as referring
+to a CR Field, like BFA does, and the bottom 2 bits of BA
+referring to
+EQ/LT/GT/SO within that Field*)
+
+With SVP64 extending the number of CR *Fields* to 128, the number of
+32-bit CR *Registers* extends to 16, in order to hold all 128 CR *Fields*
+(8 per CR Register). Then, it gets even more strange, when it comes
+to Vectorisation, which applies to the CR Field *numbers*.  The
+hardware-for-loop for Rc=1 for example starts at CR0 for element 0,
+and moves to CR1 for element 1, and so on.  The reason here is quite
+simple: each element result has to have its own CR Field co-result.
+
+In other words, the
+element is the 4-bit CR *Field*, not the bits *of* the 32-bit
+CR Register, and not the CR *Register* (of which there are now 16).
+All quite logical, but a little mind-bending.
+
+**Load/Store**
+
+LOAD/STORE is another area that has different needs: this time it is
+down to limitations in Scalar LD/ST. Vector ISAs have Load/Store modes
+which simply make no sense in a RISC Scalar ISA: element-stride and
+unit-stride and the entire concept of a stride itself (a spacing
+between elements) has no place at all in a Scalar ISA. The problems
+come when trying to *retrofit* the concept of "Vector Elements" onto
+a Scalar ISA. Consequently it required a couple of bits (Modes) in the SVP64
+RM Prefix to convey the stride mode, changing the Effective Address
+computation as a result. Interestingly, worth noting for Hardware
+designers: it did turn out to be possible to perform pre-multiplication
+of the D/DS Immediate by the stride amount, making it possible to avoid
+actually modifying the LD/ST Pipeline itself.
+
+Other areas where LD/ST went quirky: element-width overrides especially
+when combined with Saturation, given that LD/ST operations have byte,
+halfword, word, dword and quad variants. The interaction between these
+widths as part of the actual operation, and the source and destination
+elwidth overrides, was particularly obtuse and hard to derive: some care
+and attention is advised, here, when reading the specification,
+especially on arithmetic loads (lbarx, lharx etc.)
+
+**Non-vectorised**
+
+The concept of a Vectorised halt (`attn`) makes no sense. There are never
+going to be a Vector of global MSRs (Machine Status Register). `mtcr`
+on the other hand is a grey area: `mtspr` is clearly Vectoriseable.
+Even `td` and `tdi` makes a strange type of sense to permit it to be
+Vectorised, because a sequence of comparisons could be Vectorised.
+Vectorised System Calls (`sc`) or `tlbie` and other Cache or Virtual
+Nemory Management
+instructions, these make no sense to Vectorise.
+
+However, it is really quite important to not be tempted to conclude that
+just because these instructions are un-vectoriseable, the Prefix opcode space
+must be free for reiterpretation and use for other purposes. This would
+be a serious mistake because a future revision of the specification
+might *retire* the Scalar instruction, and, worse, replace it with another.
+Again this comes down to being quite strict about the rules: only Scalar
+instructions get Vectorised: there are *no* actual explicit Vector
+instructions.
+
+**Summary**
+
+Where a traditional Vector ISA effectively duplicates the entirety
+of a Scalar ISA and then adds additional instructions which only
+make sense in a Vector Context, such as Vector Shuffle, SVP64 goes to
+considerable lengths to keep strictly to augmentation and embedding
+of an entire Scalar ISA's instructions into an abstract Vectorisation
+Context. That abstraction subdivides down into Categories appropriate
+for the type of operation (Branch, CRs, Memory, Arithmetic),
+and each Category has its own relevant but
+ultimately rational quirks.
+
+# Abstraction between Prefix and Suffix
+
+In the introduction paragraph, a great fuss was made emphasising that
+the Prefix is kept separate from the Suffix.  The whole idea there is
+that a Multi-issue Decoder and subsequent pipelines would in no way have
+"back-propagation" of state that can only be determined far too late.
+This *has* been preserved, however there is a hiccup.
+
+Examining the Power ISA 3.1 a 64-bit Prefix was introduced, EXT001.
+The encoding of the prefix has 6 bits that are dedicated to letting
+the hardware know what the remainder of the Prefix bits mean: how they
+are formatted, even without having to examine the Suffix to which
+they are applied.
+
+SVP64 has such pressure on its 24-bit encoding that it was simply
+not possible to perform the same trick used by Power ISA 3.1 Prefixing.
+Therefore, rather unfortunately, it becomes necessary to perform
+a *partial decoding* of the v3.0 Suffix before the 24-bit SVP64 RM
+Fields may be identified.  Fortunately this is straightforward, and
+does not rely on any outside state, and even more fortunately
+for a Multi-Issue Execution decoder, the length 32/64 is also
+easy to identify by looking for the EXT001 pattern. Once identified
+the 32/64 bits may be passed independently to multiple Decoders in
+parallel.
+
+# Predication
+
+Predication is entirely missing from the Power ISA.
+Adding it would be a costly mistake because it cannot be retrofitted
+to an ISA without literally duplicating all instructions. Prefixing
+is about the only sane way to go.
+
+CR Fields as predicate masks could be spread across multiple register
+file entries, making them costly to read in one hit. Therefore the
+possibility exists that an instruction element writing to a CR Field
+could *overwrite* the Predicate mask CR Vector during the middle of
+a for-loop.
+
+Clearly this is bad, so don't do it.  If there are potential issues
+they can be avoided by using the crweird instructions to get CR Field
+bits into an Integer GPR (r3, r10 or r30) and use that GPR as a
+Predicate mask instead.
+
+Even in Vertical-First Mode, which is a single Scalar instruction executed
+with "offset" registers (in effect), the rule still applies: don't write
+to the same register being used as the predicate, it's `UNDEFINED`
+behaviour.
+
+## Single Predication
+
+So named because there is a Twin Predication concept as well, Single
+Predication is also unlike other Vector ISAs because it allows zeroing
+on both the source and destination.  This takes some explaining.
+
+In Vector ISAs, there is a Predicate Mask, it applies to the
+destination only, and there
+is a choice of actions when a Predicate Mask bit
+is zero:
+
+* set the destination element to zero 
+* skip that element operation entirely, leaving the destination unmodified
+
+The problem comes if the underlying register file SRAM is say 64-bit wide
+write granularity but the Vector elements are say 8-bit wide.
+Some Vector ISAs strongly advocate Zeroing because to leave one single
+element at a small bitwidth in amongst other elements where the register
+file does not have the prerequisite access granularity is very expensive,
+requiring a Read-Modify-Write cycle to preserve the untouched elements.
+Putting zero into the destination avoids that Read.
+
+This is technically very easy to solve: use a Register File that does
+in fact have the smallest element-level write-enable granularity.
+If the elements are 8 bit then allow 8-bit writes!
+
+With that technical issue solved there is nothing in the way of choosing
+to support both zeroing and non-zeroing (skipping) at the ISA level:
+SV chooses to further support both *on both the source and destination*.
+This can result in the source and destination
+element indices getting "out-of-sync" even though the Predicate Mask
+is the same because the behaviour is different when zeros in the
+Predicate are encountered.
+
+## Twin Predication
+
+Twin Predication is an entirely new concept not present in any commercial
+Vector ISA of the past forty years.  To explain how normal Single-predication
+is applied in a standard Vector ISA:
+
+* Predication on the **source** of a LOAD instruction creates something
+  called "Vector Compressed Load" (VCOMPRESS).
+* Predication on the **destination** of a STORE instruction creates something
+  called "Vector Expanded Store" (VEXPAND).
+* SVP64 allows the two to be put back-to-back: one on source, one on
+  destination.
+
+The above allows a reader familiar with VCOMPRESS and VEXPAND to
+conceptualise what the effect of Twin Predication is, but it actually
+goes much further: in *any* twin-predicated instruction (extsw, fmv)
+it is possible to apply one predicate to the source register (compressing
+the source element array) and another *completely separate* predicate
+to the destination register, not just on Load/Stores but on *arithmetic*
+operations.
+
+No other Vector ISA in the world has this back-to-back
+capability.  All true Vector
+ISAs have Predicate Masks: it is an absolutely essential characteristic.
+However none of them have abstracted dual predicates out to the extent
+where this VCOMPRESS-VEXPAND effect is applicable *in general* to a
+wide range of arithmetic
+instructions, as well as Load/Store.
+
+It is however important to note that not all instructions can be Twin
+Predicated (2P): some remain only Single Predicated (1P), as is normally found
+in other Vector ISAs. Arithmetic operations with
+four registers (3-in, 1-out, VA-Form for example) are Single. The reason
+is that there just wasn't enough space in the 24-bits of the SVP64 Prefix.
+Consequently, when using a given instruction, it is necessary to look
+up in the ISA Tables whether it is 1P or 2P. caveat emptor!
+
+Also worth a special mention: all Load/Store operations are Twin-Predicated.
+The underlying key to understanding:
+
+* one Predicate effectively applies to the Array of Memory *Addresses*,
+* the other Predicate effectively applies to the Array of Memory *Data*.
 
 # CR weird instructions
 
 
 # CR weird instructions
 
-[[sv/int_cr_predication]] is by far the biggest violator of the SVP64
+[[sv/cr_int_predication]] is by far the biggest violator of the SVP64
 rules, for good reasons.  Transfers between Vectors of CR Fields and Integers
 for use as predicates is very awkward without them.
 
 rules, for good reasons.  Transfers between Vectors of CR Fields and Integers
 for use as predicates is very awkward without them.
 
@@ -38,7 +372,7 @@ From a hardware implementation perspective however they will need special
 handling as far as Hazard Dependencies are concerned, due to nonconformance
 (bit-level management)
 
 handling as far as Hazard Dependencies are concerned, due to nonconformance
 (bit-level management)
 
-# mv.x
+# mv.x (vector permute)
 
 [[sv/mv.x]] aka `GPR(RT) = GPR(GPR(RA))` is so horrendous in
 terms of Register Hazard Management that its addition to any Scalar
 
 [[sv/mv.x]] aka `GPR(RT) = GPR(GPR(RA))` is so horrendous in
 terms of Register Hazard Management that its addition to any Scalar
@@ -46,9 +380,10 @@ ISA is anathematic. In a Traditional Vector ISA however, where the
 indices are isolated behind a single Vector Hazard, there is no
 problem at all.  `sv.mv.x` is also fraught, precisely because it
 sits on top of a Standard Scalar register paradigm, not a Vector
 indices are isolated behind a single Vector Hazard, there is no
 problem at all.  `sv.mv.x` is also fraught, precisely because it
 sits on top of a Standard Scalar register paradigm, not a Vector
-ISA, with separate and distinct Vector registers.
+ISA with separate and distinct Vector registers.
 
 
-To help partly solve this, `sv.mv.x` has to be made relative:
+To help partly solve this, `sv.mv.x` would have had to have
+been made relative:
 
 ```
 for i in range(VL):
 
 ```
 for i in range(VL):
@@ -59,11 +394,249 @@ The reason for doing so is that MAXVL or VL may be used to limit
 the number of Register Hazards that need to be raised to a fixed
 quantity, at Issue time.
 
 the number of Register Hazards that need to be raised to a fixed
 quantity, at Issue time.
 
-`mv.x` itself will still have to be added as a Scalar instruction,
-but the behaviour of `sv.mv.x` will have to be different from that
+`mv.x` itself would still have to be added as a Scalar instruction,
+but the behaviour of `sv.mv.x` would have to be different from that
 Scalar version.
 
 Normally, Scalar Instructions have a good justification for being
 added as Scalar instructions on their own merit. `mv.x` is the
 Scalar version.
 
 Normally, Scalar Instructions have a good justification for being
 added as Scalar instructions on their own merit. `mv.x` is the
-polar opposite, and as such qualifies for a special mention in
-this section.
+polar opposite, and in the end, the idea was thrown out, and Indexed
+REMAP added in its place.  Indexed REMAP comes with its own quirks,
+solving the Hazard problem, described in a later section.
+
+# Branch-Conditional
+
+[[sv/branches]] are a very special exception to the rule that there
+shall be no deviation from the corresponding
+Scalar instruction.  This because of the tight
+integration with looping and the application of Boolean Logic
+manipulation needed for Parallel operations (predicate mask usage).
+This results in an extremely important observation that `scalar identity
+behaviour` is violated: the SV Prefixed variant of branch is **not** the same
+operation as the unprefixed 32-bit scalar version.
+
+One key difference is that LR is only updated if certain additional
+conditions are met, whereas Scalar `bclrl` for example unconditionally
+overwrites LR.
+
+Another is that the Vectorised Branch-Conditional instructions are the
+only ones where there are side-effects on predication when skipping
+is enabled. This is so as to be able to use CTR to count down
+*masked-out* elements.
+
+Well over 500 Vectorised branch instructions exist in SVP64 due to the
+number of options available: close integration and interaction with
+the base Scalar Branch was unavoidable in order to create Conditional
+Branching suitable for parallel 3D / CUDA GPU workloads.
+
+# Saturation
+
+The application of Saturation as a retro-fit to a Scalar ISA is challenging.
+It does help that within the SFFS Compliancy subset there are no Saturated
+operations at all: they are only added in VSX.
+
+Saturation does not inherently change the instruction itself: it does however
+come with some fundamental implications, when applied. For example:
+a Floating-Point operation that would normally raise an exception will
+no longer do so, instead setting the CR1.SO Flag.  Another quirky
+example: signed operations which produce a negative result will be
+truncated to zero if Unsigned Saturation is requested.
+
+One very important aspect for implementors is that the operation in
+effect has to be considered to be performed at infinite precision,
+followed by saturation detection. In practice this does not actually
+require infinite precision hardware! Two 8-bit integers being
+added can only ever overflow into a 9-bit result.
+
+Overall some care and consideration needs to be applied.
+
+# Fail-First
+
+Fail-First (both the Load/Store and Data-Dependent variants)
+is worthy of a special mention in its own right. Where VL is
+normally forward-looking and may be part of a pre-decode phase
+in a (simplified) pipelined architecture with no Read-after-Write Hazards,
+Fail-First changes that because at any point during the execution
+of the element-level instructions, one of those elements may not only
+terminate further continuation of the hardware-for-looping but also
+effect a change of VL:
+
+```
+for i in range(VL):
+    result = element_operation(GPR(RA+i), GPR(RB+i))
+    if test(result):
+        VL = i
+        break
+```
+
+This is not exactly a violation of SVP64 Rules, more of a breakage
+of user expectations, particularly for LD/ST where exceptions
+would normally be expected to be raised, Fail-First provides for
+avoidance of those exceptions.
+
+For Hardware implementers, a standard Out-of-Order micro-architecture
+allows for Cancellation of speculatively-executed elements that extended
+beyond the Vector Truncation point.  In-order systems will have a slightly
+harder time and may choose to execute one element only at a time, reducing
+performance as a result.
+
+# OE=1
+
+The hardware cost of Sticky Overflow in a parallel environment is immense.
+The SFFS Compliancy Level is permitted optionally to support XER.SO.
+Therefore the decision is made to make it mandatory **not** to
+support XER.SO. However, CR.SO *is* supported such that when Rc=1
+is set the CR.SO flag will contain only the overflow of
+the current instruction, rather than being actually "sticky".
+Hardware Out-of-Order designers will recognise and appreciate
+that the Hazards are
+reduced to Read-After-Write (RAW) and that the WAR Hazard is removed.
+
+This is sort-of a quirk and sort-of not, because the option to support
+XER.SO is already optional from the SFFS Compliancy Level.
+
+# Indexed REMAP and CR Field Predication Hazards
+
+Normal Vector ISAs and those Packed SIMD ISAs inspired by them have
+Vector "Permute" or "Shuffle" instructions. These provide a Vector of
+indices whereby another Vector is reordered (permuted, shuffled) according
+to the indices.  Register Hazard Managent here is trivial because there
+are three registers: indices source vector, elements source vector to
+be shuffled, result vector.
+
+For SVP64 which is based on top of a Scalar Register File paradigm,
+combined with the hard requirement to respect full Register Hazard
+Management as if element instructions were actual Scalar instructions,
+the addition of a Vector permute instruction under these strict
+conditions would result in a catastrophic
+reduction in performance, due to having to consider Read-after-Write
+and Write-after-Read Hazards *at the element level*.
+
+A little leniency and rule-bending is therefore required.
+
+Rather than add explicit Vector permute instructions, the "Indexing"
+has been separated out into a REMAP Schedule.  When an Indexed
+REMAP is requested, it is assumed (required, of software) that
+subsequent instructions intending to use those indices *will not*
+attempt to modify the indices. It is *Software* that must consider them
+to be read-only.
+
+This simple relaxation of the rules releases Hardware from having the
+horrendous job of dynamically detecting Write-after-Read Hazards on a
+huge range of registers.
+
+A similar Hazard problem exists for CR Field Predicates, in Vertical-First
+Mode.  Instructions could modify CR Fields currently being used as Predicate
+Masks: detecting this is so horrendous for hardware resource utilisation
+and hardware complexity that, again, the decision is made to relax these
+constraints and for Software to take that into account.
+
+# Floating-Point "Single" becomes "Half"
+
+In several places in the Power ISA there are operations that are on
+32-bit quantities in 64-bit registers.  The best example is FP which
+has 64-bit operations (`fadd`) and 32-bit operations (`fadds` or
+FP Add "single").  Element-width overrides it would seem to
+be unnecessary, under these circumstances.
+
+However, it is not possible for `fadds` to fit two elements into
+64-bit: that breaks the simplicity of SVP64.
+Bear in mind that the FP32 bits are spread out across a 64
+bit register in FP64 format.  The solution here was to consider the
+"s" at the end of each instruction
+to mean "half of the element's width". Thus, `sv.fadds/ew=32`
+actually stores an FP16 spread out across the 32 bits of an
+element, in FP32 format, where `sv.fadd/ew=32` stores a full
+FP32 result into the full 32 bits.
+
+Where this breaks down is when attempting to do half-width on
+BF16 or FP16 operations: there does not exist a BF8 or an IEEE754 FP8
+format, so these (`sv.fadds/ew=8`) should be avoided.
+
+# Vertical-First and Subvectors
+
+Documented in the [[sv/setvl]] page, Vertical-First goes through
+elements second instructions first and requires an explicit
+[[sv/svstep]] instruction to move to the next element,
+(whereas Horizontal-First
+loops through elements in full first before moving on to
+the next instruction): *Subvectors are considered "elements"*
+in Vertical-First Mode.
+
+This is conceptually quite easy to keep in mind that a Vertical-First
+instruction does one element at a time, and when SUBVL is set,
+that "element" in essence becomes a vec2/3/4.
+
+# Swizzle and Pack/Unpack
+
+These are both so weird it's best to just read the pages in full
+and pay attention: [[sv/mv.swizzle]] and [[sv/mv.vec]].
+Swizzle Moves only engage with vec2/3/4, *reordering* the copying
+of the sub-vector elements (including allowing repeats and skips)
+based on an immediate supplied by the instruction.  The fun
+comes when Pack/Unpack are enabled, and it is really important
+to be aware how the Arrays of vec2/3/4 become re-ordered
+*and swizzled at the same time*.
+
+Pack/Unpack started out as 
+[[sv/mv.vec]] but became its own distinct Mode over time.
+The main thing to keep in mind about Pack/Unpack
+is that it engages a swap of the ordering of the VL-SUBVL
+nested for-loops, in exactly the same way that Matrix REMAP
+can do.
+When Pack or Unpack is enabled it is the SUBVL for-loop
+that becomes outermost.  A bit of thought shows that this is
+a 2D "Transpose" where Dimension X is VL and Dimension Y is SUBVL.
+However *both* source *and* destination may be independently
+"Transposed", which makes no sense at all until the fact that
+Swizzle can have a *different SUBVL* is taken into account.
+
+Basically Pack/Unpack covers everything that VSX `vpkpx` and
+other ops can do, and then some: Saturation included, for arithmetic ops.
+
+# LD/ST with zero-immediate vs mapreduce mode
+
+LD/ST operations with a zero immediate effectively means that on a
+Vector operation the element index to offset the memory location is
+multiplied by zero.  Thus, a sequence of LD operations will load from
+the exact same address, and likewise STs to the exact same address.
+
+Ordinarily this would make absolutely no sense whatsoever, except
+that Power ISA has cache-inhibited LD/STs (Power ISA v.1, Book III,
+1.6.1, p1033), for accessing memory-mapped
+peripherals and other crucial uses.  Thus, *despite not being a mapreduce mode*,
+zero-immediates cause multiple hits on the same element.
+
+Mapreduce mode is not actually mapreduce at all: it is
+a relaxation of the normal rule where if the destination is a Scalar the
+Vector for-looping is not terminated on first write to the destination.
+Instead, the developer is expected to exploit the strict Program Order,
+make one of the sources the same as that Scalar destination, effectively
+making that Scalar register an "Accumulator", thus creating the *appearance*
+(effect) of Simple-V having a mapreduce capability, when in fact it is
+more of an artefact.
+
+LD/ST zero-immediate has similar quirky overwriting as the "mapreduce"
+mode, but actually requires the registers to be Vectors.  It is simply
+a mathematical artefact of multiplying by zero, which happens to be
+useful for cache-inhibited operations.
+
+# Limited space in LD/ST Mode
+
+As pointed out in the [[sv/ldst]] page there is limited space in only
+5 mode bits to fully express all potential modes of operation.
+
+* LD/ST Immediate has no individual control over src/dest zeroing,
+  whereas LD/ST Indexed does.
+* LD/ST Immediate has no Saturated Pack/Unpack (Arithmetic Mode does)
+* LD/ST Indexed has no Pack/Unpack (REMAP may be used instead)
+
+These are not insurmountable problems: there do exist workarounds.
+For example it is possible to set up Matrix REMAP to perform the same
+job as Pack/Unpack, at which point the LD/ST "Saturation" mode may
+be used, saving on costly intermediary registers at double the LD
+width.  Also, although potentially costly it may be possible to
+use Indexed Mode after using `svstep` to compute a sequence of
+Indices, then activate either `sz` or `dz` as required, as a workaround
+for LDST Immediate only having `zz`.
+