Normal SVP64 Modes, for Arithmetic and Logical Operations

Normal SVP64 Mode covers Arithmetic and Logical operations to provide suitable additional behaviour. The Mode field is bits 19-23 of the svp64 RM Field.

Table of contents:

Mode

Mode is an augmentation of SV behaviour, providing additional functionality. Some of these alterations are element-based (saturation), others involve post-analysis (predicate result) and others are Vector-based (mapreduce, fail-on-first).

ldst, cr ops and branches are covered separately: the following Modes apply to Arithmetic and Logical SVP64 operations:

  • normal mode is straight vectorisation. no augmentations: the vector comprises an array of independently created results.
  • ffirst or data-dependent fail-on-first: see separate section. the vector may be truncated depending on certain criteria. VL is altered as a result.
  • sat mode or saturation: clamps each element result to a min/max rather than overflows / wraps. allows signed and unsigned clamping for both INT and FP.
  • reduce mode. a mapreduce is performed. the result is a scalar. a result vector however is required, as the upper elements may be used to store intermediary computations. the result of the mapreduce is in the first element with a nonzero predicate bit. see appendix note that there are comprehensive caveats when using this mode.
  • pred-result will test the result (CR testing selects a bit of CR and inverts it, just like branch testing) and if the test fails it is as if the destination predicate bit was zero. When Rc=1 the CR element however is still stored in the CR regfile, even if the test failed. See appendix for details.

Note that ffirst and reduce modes are not anticipated to be high-performance in some implementations. ffirst due to interactions with VL, and reduce due to it requiring additional operations to produce a result. normal, saturate and pred-result are however inter-element independent and may easily be parallelised to give high performance, regardless of the value of VL.

The Mode table for Arithmetic and Logical operations is laid out as follows:

0-1 2 3 4 description
00 0 dz sz normal mode
00 1 0 RG scalar reduce mode (mapreduce), SUBVL=1
00 1 1 / parallel reduce mode (mapreduce), SUBVL=1
00 1 SVM RG subvector reduce mode, SUBVL>1
01 inv CR-bit Rc=1: ffirst CR sel
01 inv VLi RC1 Rc=0: ffirst z/nonz
10 N dz sz sat mode: N=0/1 u/s
11 inv CR-bit Rc=1: pred-result CR sel
11 inv dz RC1 Rc=0: pred-result z/nonz

Fields:

  • sz / dz if predication is enabled will put zeros into the dest (or as src in the case of twin pred) when the predicate bit is zero. otherwise the element is ignored or skipped, depending on context.
  • inv CR bit just as in branches (BO) these bits allow testing of a CR bit and whether it is set (inv=0) or unset (inv=1)
  • RG inverts the Vector Loop order (VL-1 downto 0) rather than the normal 0..VL-1
  • SVM sets "subvector" reduce mode
  • N sets signed/unsigned saturation.
  • RC1 as if Rc=1, stores CRs but not the result
  • VLi VL inclusive: in fail-first mode, the truncation of VL includes the current element at the failure point rather than excludes it from the count.

For LD/ST Modes, see ldst. For Condition Registers see cr ops. For Branch modes, see branches.

Rounding, clamp and saturate

See av opcodes for relevant opcodes and use-cases.

To help ensure that audio quality is not compromised by overflow, "saturation" is provided, as well as a way to detect when saturation occurred if desired (Rc=1). When Rc=1 there will be a vector of CRs, one CR per element in the result (Note: this is different from VSX which has a single CR per block).

When N=0 the result is saturated to within the maximum range of an unsigned value. For integer ops this will be 0 to 2elwidth-1. Similar logic applies to FP operations, with the result being saturated to maximum rather than returning INF, and the minimum to +0.0

When N=1 the same occurs except that the result is saturated to the min or max of a signed result, and for FP to the min and max value rather than returning +/- INF.

When Rc=1, the CR "overflow" bit is set on the CR associated with the element, to indicate whether saturation occurred. Note that due to the hugely detrimental effect it has on parallel processing, XER.SO is ignored completely and is not brought into play here. The CR overflow bit is therefore simply set to zero if saturation did not occur, and to one if it did.

Note also that saturate on operations that produce a carry output are prohibited due to the conflicting use of the CR.so bit for storing if saturation occurred.

Post-analysis of the Vector of CRs to find out if any given element hit saturation may be done using a mapreduced CR op (cror), or by using the new crweird instruction, transferring the relevant CR bits to a scalar integer and testing it for nonzero. see cr int predication

Note that the operation takes place at the maximum bitwidth (max of src and dest elwidth) and that truncation occurs to the range of the dest elwidth.

Reduce mode

Reduction in SVP64 is similar in essence to other Vector Processing ISAs, but leverages the underlying scalar Base v3.0B operations. Thus it is more a convention that the programmer may utilise to give the appearance and effect of a Horizontal Vector Reduction. Details are in the appendix

Fail-on-first

Data-dependent fail-on-first has two distinct variants: one for LD/ST, the other for arithmetic operations (actually, CR-driven). Note in each case the assumption is that vector elements are required appear to be executed in sequential Program Order, element 0 being the first.

  • Data-driven (CR-driven) fail-on-first activates when Rc=1 or other CR-creating operation produces a result (including cmp). Similar to branch, an analysis of the CR is performed and if the test fails, the vector operation terminates and discards all element operations at and above the current one, and VL is truncated to either the previous element or the current one, depending on whether VLi (VL "inclusive") is set.

Thus the new VL comprises a contiguous vector of results, all of which pass the testing criteria (equal to zero, less than zero).

The CR-based data-driven fail-on-first is new and not found in ARM SVE or RVV. It is extremely useful for reducing instruction count, however requires speculative execution involving modifications of VL to get high performance implementations. An additional mode (RC1=1) effectively turns what would otherwise be an arithmetic operation into a type of cmp. The CR is stored (and the CR.eq bit tested against the inv field). If the CR.eq bit is equal to inv then the Vector is truncated and the loop ends. Note that when RC1=1 the result elements are never stored, only the CRs.

VLi is only available as an option when Rc=0 (or for instructions which do not have Rc). When set, the current element is always also included in the count (the new length that VL will be set to). This may be useful in combination with "inv" to truncate the Vector to exclude elements that fail a test, or, in the case of implementations of strncpy, to include the terminating zero.

In CR-based data-driven fail-on-first there is only the option to select and test one bit of each CR (just as with branch BO). For more complex tests this may be insufficient. If that is the case, a vectorised crops (crand, cror) may be used, and ffirst applied to the crop instead of to the arithmetic vector.

One extremely important aspect of ffirst is:

  • LDST ffirst may never set VL equal to zero. This because on the first element an exception must be raised "as normal".
  • CR-based data-dependent ffirst on the other hand can set VL equal to zero. This is the only means in the entirety of SV that VL may be set to zero (with the exception of via the SV.STATE SPR). When VL is set zero due to the first element failing the CR bit-test, all subsequent vectorised operations are effectively nops which is precisely the desired and intended behaviour.

CR-based data-dependent first on the other hand MUST not truncate VL arbitrarily to a length decided by the hardware: VL MUST only be truncated based explicitly on whether a test fails. This because it is a precise test on which algorithms will rely.

Data-dependent fail-first on CR operations (crand etc)

Operations that actually produce or alter CR Field as a result have their own SVP64 Mode, described in cr ops

pred-result mode

This mode merges common CR testing with predication, saving on instruction count. Below is the pseudocode excluding predicate zeroing and elwidth overrides. Note that the pseudocode for cr ops is slightly different.

for i in range(VL):
    # predication test, skip all masked out elements.
    if predicate_masked_out(i):
         continue
    result = op(iregs[RA+i], iregs[RB+i])
    CRnew = analyse(result) # calculates eq/lt/gt
    # Rc=1 always stores the CR
    if Rc=1 or RC1:
        crregs[offs+i] = CRnew
    # now test CR, similar to branch
    if RC1 or CRnew[BO[0:1]] != BO[2]:
        continue # test failed: cancel store
    # result optionally stored but CR always is
    iregs[RT+i] = result

The reason for allowing the CR element to be stored is so that post-analysis of the CR Vector may be carried out. For example: Saturation may have occurred (and been prevented from updating, by the test) but it is desirable to know which elements fail saturation.

Note that RC1 Mode basically turns all operations into cmp. The calculation is performed but it is only the CR that is written. The element result is always discarded, never written (just like cmp).

Note that predication is still respected: predicate zeroing is slightly different: elements that fail the CR test or are masked out are zero'd.