(no commit message)
[libreriscv.git] / openpower / sv / vector_ops.mdwn
index 6a80ee3b87d8519693790cf69a78577c550d70c1..67d95d4df20321619aff964b3f168ec178f47e84 100644 (file)
-# SV Vector Operations.
+[[!tag standards]]
 
-The core OpenPOWER ISA was designed as scalar: SV provides a level of abstraction to add variable-length element-independent parallelism. However, certain classes of instructions only make sense in a Vector context: AVC512 conflictd for example.  This section includes such examples.  Many of them are from the RISC-V Vector ISA (with thanks to the efforts of RVV's contributors)
+# SV Vector-assist Operations.
 
-However some of these actually could be added to a scalar ISA as bitmanipulation instructions.  These are separated out into their own section.
-Instructions suited to 3D GPU workloads (dotproduct, crossproduct, normalise) are out of scope: this document is for more general-purpose instructions that underpin and are critical to general-purpose Vector workloads (including GPU and VPU)
-
-.
 Links:
 
+* [[discussion]]
 * <https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#vector-register-gather-instructions>
-* <http://0x80.pl/notesen/2016-10-23-avx512-conflict-detection.html> conflictd example
+* <https://lists.libre-soc.org/pipermail/libre-soc-dev/2022-May/004884.html>
+* <https://bugs.libre-soc.org/show_bug.cgi?id=865> implementation in simulator
 * <https://bugs.libre-soc.org/show_bug.cgi?id=213>
 * <https://bugs.libre-soc.org/show_bug.cgi?id=142> specialist vector ops
- out of scope for this document
-
-# Vector
-
-## conflictd
-
-This is based on the AVX512 conflict detection instruction.  Internally the logic is used to detect address conflicts in LD/ST operations.  Two arrays of indices are given.
-
-    input = [100, 100,   3, 100,   5, 100, 100,   3]
-    conflict result = [
-         0b00000000,    // Note: first element always zero
-         0b00000001,    // 100 is present on #0
-         0b00000000,
-         0b00000011,    // 100 is present on #0 and #1
-         0b00000000,
-         0b00001011,    // 100 is present on #0, #1, #3
-         0b00011011,    // .. and #4
-         0b00000100     // 3 is present on #2
-    ]
-
-## iota
-
-Based on RVV vmiota.  vmiota may be viewed as a cumulative variant of cntlz, where instead of stopping at the first zero with a count to produce a single scalar result, the process continues on, producing another element at the next encounter of a 1.
-
-The viota.m instruction reads a source vector mask register and writes to each element of the destination vector register group the sum of all the bits of elements in the mask register whose index is less than the element, e.g., a parallel prefix sum of the mask values.
-
-This instruction can be masked, in which case only the enabled elements contribute to the sum and only the enabled elements are written.
-
-    viota.m vd, vs2, vm
+ out of scope for this document [[openpower/sv/3d_vector_ops]]
+* [[simple_v_extension/specification/bitmanip]] previous version,
+  contains pseudocode for sof, sif, sbf
+* <https://en.m.wikipedia.org/wiki/X86_Bit_manipulation_instruction_set#TBM_(Trailing_Bit_Manipulation)>
 
-Example
+The core Power ISA was designed as scalar: SV provides a level of abstraction to add variable-length element-independent parallelism.
+Therefore there are not that many cases where *actual* Vector
+instructions are needed. If they are, they are more "assistance"
+functions.  Two traditional Vector instructions were initially
+considered (conflictd and vmiota) however they may be synthesised
+from existing SVP64 instructions: vmiota may use [[svstep]].
+Details in [[discussion]]
 
-     7 6 5 4 3 2 1 0   Element number
+Notes:
 
-     1 0 0 1 0 0 0 1   v2 contents
-                       viota.m v4, v2 # Unmasked
-     2 2 2 1 1 1 1 0   v4 result
+* Instructions suited to 3D GPU workloads (dotproduct, crossproduct, normalise) are out of scope: this document is for more general-purpose instructions that underpin and are critical to general-purpose Vector workloads (including GPU and VPU)
+* Instructions related to the adaptation of CRs for use as predicate masks are covered separately, by crweird operations.  See [[sv/cr_int_predication]].
 
-     1 1 1 0 1 0 1 1   v0 contents
-     1 0 0 1 0 0 0 1   v2 contents
-     2 3 4 5 6 7 8 9   v4 contents
-                       viota.m v4, v2, v0.t # Masked
-     1 1 1 5 1 7 1 0   v4 results
+# Mask-suited Bitmanipulation
 
-The result value is zero-extended to fill the destination element if SEW is wider than the result. If the result value would overflow the destination SEW, the least-significant SEW bits are retained.
+Based on RVV masked set-before-first, set-after-first etc.
+and Intel and AMD Bitmanip instructions made generalised then
+advanced further to include masks, this is a single instruction
+covering 24 individual instructions in other ISAs.
+*(sbf/sof/sif moved to [[discussion]])*
 
-Traps on viota.m are always reported with a vstart of 0, and execution is always restarted from the beginning when resuming after a trap handler. An illegal instruction exception is raised if vstart is non-zero.
+BM2-Form
 
+|0..5  |6..10|11..15|16..20|21-25|26|27..31| Form |
+|------|-----|------|------|-----|--|------|------|
+| PO   |  RS |   RA |   RB |bm   |L |   XO | BM2-Form |
 
+* bmask RS,RA,RB,bm,L
 
-# Scalar
+The patterns within the pseudocode for AMD TBM and x86 BMI1 are
+as follows:
 
-These may all be viewed as suitable for fitting into a scalar bitmanip extension.
+* first pattern A: two options `x` or `~x`
+* second pattern B: three options `|` `&` or `^`
+* third pattern C: four options `x+1`, `x-1`, `~(x+1)` or `(~x)+1`
 
-## sbfm
+Thus it makes sense to create a single instruction
+that covers all of these.  A crucial addition that is essential
+for Scalable Vector usage as Predicate Masks, is the second mask parameter
+(RB).  The additional paramater, L, if set, will leave bits of RA masked
+by RB unaltered, otherwise those bits are set to zero. Note that when `RB=0`
+then instead of reading from the register file the mask is set to all ones.
 
-   sbfm RT, RA, RB!=0
+The lower two bits of `bm` set to 0b11 are `RESERVED`. An illegal instruction
+trap must be raised.
 
-Example
+Executable pseudocode demo:
 
-     7 6 5 4 3 2 1 0   Bit index
+```
+[[!inline pages="openpower/sv/bmask.py" quick="yes" raw="yes" ]]
+```
 
-     1 0 0 1 0 1 0 0   v3 contents
-                       vmsbf.m v2, v3
-     0 0 0 0 0 0 1 1   v2 contents
+# Carry-lookahead
 
-     1 0 0 1 0 1 0 1   v3 contents
-                       vmsbf.m v2, v3
-     0 0 0 0 0 0 0 0   v2
+As a single scalar 32-bit instruction, up to 64 carry-propagation bits
+may be computed.  When the output is then used as a Predicate mask it can
+be used to selectively perform the "add carry" of biginteger math, with
+`sv.addi/sm=rN RT.v, RA.v, 1`.
 
-     0 0 0 0 0 0 0 0   v3 contents
-                       vmsbf.m v2, v3
-     1 1 1 1 1 1 1 1   v2
+* cprop RT,RA,RB
+* cprop. RT,RA,RB
 
-     1 1 0 0 0 0 1 1   RB vcontents
-     1 0 0 1 0 1 0 0   v3 contents
-                       vmsbf.m v2, v3, v0.t
-     0 1 x x x x 1 1   v2 contents
+pseudocode:
 
-The vmsbf.m instruction takes a mask register as input and writes results to a mask register. The instruction writes a 1 to all active mask elements before the first source element that is a 1, then writes a 0 to that element and all following active elements. If there is no set bit in the source vector, then all active elements in the destination are written with a 1.
+    P = (RA)
+    G = (RB)
+    RT = ((P|G)+G)^P 
 
-## sifm
+X-Form
 
-The vector mask set-including-first instruction is similar to set-before-first, except it also includes the element with a set bit.
+| 0.5|6.10|11.15|16.20| 21..30     |31| name      |  Form   |
+| -- | -- | --- | --- | ---------  |--| ----      | ------- |
+| NN | RT | RA  | RB  | 0110001110 |Rc|     cprop | X-Form  |
 
-    sifm RT, RA, RB!=0
+used not just for carry lookahead, also a special type of predication mask operation.
 
- # Example
+* <https://www.geeksforgeeks.org/carry-look-ahead-adder/>
+* <https://media.geeksforgeeks.org/wp-content/uploads/digital_Logic6.png>
+* <https://electronics.stackexchange.com/questions/20085/whats-the-difference-with-carry-look-ahead-generator-block-carry-look-ahead-ge>
+* <https://i.stack.imgur.com/QSLKY.png>
+* <https://stackoverflow.com/questions/27971757/big-integer-addition-code>
+  `((P|G)+G)^P`
+* <https://en.m.wikipedia.org/wiki/Carry-lookahead_adder>
 
-     7 6 5 4 3 2 1 0   Bit number
+From QLSKY.png:
 
-     1 0 0 1 0 1 0 0   v3 contents
-                       vmsif.m v2, v3
-     0 0 0 0 0 1 1 1   v2 contents
+```
+    x0 = nand(CIn, P0)
+    C0 = nand(x0, ~G0)
 
-     1 0 0 1 0 1 0 1   v3 contents
-                       vmsif.m v2, v3
-     0 0 0 0 0 0 0 1   v2
+    x1 = nand(CIn, P0, P1)
+    y1 = nand(G0, P1)
+    C1 = nand(x1, y1, ~G1)
 
-     1 1 0 0 0 0 1 1   RB vcontents
-     1 0 0 1 0 1 0 0   v3 contents
-                       vmsif.m v2, v3, v0.t
-     1 1 x x x x 1 1   v2 contents
+    x2 = nand(CIn, P0, P1, P2)
+    y2 = nand(G0, P1, P2)
+    z2 = nand(G1, P2)
+    C1 = nand(x2, y2, z2, ~G2)
 
-## vmsof
+    # Gen*
+    x3 = nand(G0, P1, P2, P3)
+    y3 = nand(G1, P2, P3)
+    z3 = nand(G2, P3)
+    G* = nand(x3, y3, z3, ~G3)
+```
 
-The vector mask set-only-first instruction is similar to set-before-first, except it only sets the first element with a bit set, if any.
+```
+     P = (A | B) & Ci
+     G = (A & B)
+```
 
-    sofm RT, RA, RB
+Stackoverflow algorithm `((P|G)+G)^P` works on the cumulated bits of P and G from associated vector units (P and G are integers here).  The result of the algorithm is the new carry-in which already includes ripple, one bit of carry per element.
 
- # Example
+```
+    At each id, compute C[id] = A[id]+B[id]+0
+    Get G[id] = C[id] > radix -1
+    Get P[id] = C[id] == radix-1
+    Join all P[id] together, likewise G[id]
+    Compute newC = ((P|G)+G)^P
+    result[id] = (C[id] + newC[id]) % radix
+```   
 
-     7 6 5 4 3 2 1 0   Bit number
+two versions: scalar int version and CR based version.
 
-     1 0 0 1 0 1 0 0   v3 contents
-                       vmsof.m v2, v3
-     0 0 0 0 0 1 0 0   v2 contents
+scalar int version acts as a scalar carry-propagate, reading XER.CA as input, P and G as regs, and taking a radix argument.  the end bits go into XER.CA and CR0.ge
 
-     1 0 0 1 0 1 0 1   v3 contents
-                       vmsof.m v2, v3
-     0 0 0 0 0 0 0 1   v2
+vector version takes CR0.so as carry in, stores in CR0.so and CR.ge end bits.
 
-     1 1 0 0 0 0 1 1   RB vcontents
-     1 1 0 1 0 1 0 0   v3 contents
-                       vmsof.m v2, v3, v0.t
-     0 1 x x x x 0 0   v2 content
+if zero (no propagation) then CR0.eq is zero
 
+CR based version, TODO.