FMOP4S (non-widening)

Floating-point quarter-tile outer products, subtracting

This instruction generates four independent quarter-tile floating-point outer products from the sub-matrices in the half-vectors of the one or two first and second source vectors and subtracts the results from the corresponding elements of a 16-bit, 32-bit, or 64-bit element ZA tile.

In case of the half-precision variant, each of the quarter-tile outer products is generated by multiplying the SVLH÷2 × 1 sub-matrix of half-precision values held in the half-vectors of the first source vectors by the 1 × SVLH÷2 sub-matrix of half-precision values held in the half-vectors of the second source vectors. In case of the single-precision variant, each of the quarter-tile outer products is generated by multiplying the SVLS÷2 × 1 sub-matrix of single-precision values held in the half-vectors of the first source vectors by the 1 × SVLS÷2 sub-matrix of single-precision values held in the half-vectors of the second source vectors. In case of the double-precision variant, each of the quarter-tile outer products is generated by multiplying the SVLD÷2 × 1 sub-matrix of double-precision values held in the half-vectors of the first source vectors by the 1 × SVLD÷2 sub-matrix of double-precision values held in the half-vectors of the second source vectors.

The resulting quarter-tile SVLH÷2 × SVLH÷2 half-precision outer products in case of the half-precision variant, SVLS÷2 × SVLS÷2 single-precision outer products in case of the single-precision variant, or SVLD÷2 × SVLD÷2 double-precision outer products in case of the double-precision variant are destructively subtracted from the destination ZA tile. This is equivalent to performing a single multiply-subtract from each of the destination tile elements.

This instruction follows SME ZA-targeting floating-point behaviors.

This instruction is unpredicated.

Encoding: Half-precision, single and multiple vectors

Variants: FEAT_SME_MOP4 && FEAT_SME_F16F16 (FEAT_SME_MOP4 && FEAT_SME_F16F16)

313029282726252423222120191817161514131211109876543210
1000000100010000000001100
MZmNZnSZAda

FMOP4S <ZAda>.H, <Zn>.H, { <Zm1>.H-<Zm2>.H }

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) || !IsFeatureImplemented(FEAT_SME_F16F16) then
    EndOfDecode(Decode_UNDEF);
constant integer esize = 16;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 1;
constant integer mreg = 2;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Encoding: Half-precision, single vectors

Variants: FEAT_SME_MOP4 && FEAT_SME_F16F16 (FEAT_SME_MOP4 && FEAT_SME_F16F16)

313029282726252423222120191817161514131211109876543210
1000000100000000000001100
MZmNZnSZAda

FMOP4S <ZAda>.H, <Zn>.H, <Zm>.H

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) || !IsFeatureImplemented(FEAT_SME_F16F16) then
    EndOfDecode(Decode_UNDEF);
constant integer esize = 16;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 1;
constant integer mreg = 1;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Encoding: Half-precision, multiple and single vectors

Variants: FEAT_SME_MOP4 && FEAT_SME_F16F16 (FEAT_SME_MOP4 && FEAT_SME_F16F16)

313029282726252423222120191817161514131211109876543210
1000000100000000000101100
MZmNZnSZAda

FMOP4S <ZAda>.H, { <Zn1>.H-<Zn2>.H }, <Zm>.H

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) || !IsFeatureImplemented(FEAT_SME_F16F16) then
    EndOfDecode(Decode_UNDEF);
constant integer esize = 16;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 2;
constant integer mreg = 1;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Encoding: Half-precision, multiple vectors

Variants: FEAT_SME_MOP4 && FEAT_SME_F16F16 (FEAT_SME_MOP4 && FEAT_SME_F16F16)

313029282726252423222120191817161514131211109876543210
1000000100010000000101100
MZmNZnSZAda

FMOP4S <ZAda>.H, { <Zn1>.H-<Zn2>.H }, { <Zm1>.H-<Zm2>.H }

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) || !IsFeatureImplemented(FEAT_SME_F16F16) then
    EndOfDecode(Decode_UNDEF);
constant integer esize = 16;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 2;
constant integer mreg = 2;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Encoding: Single-precision, single and multiple vectors

Variants: FEAT_SME_MOP4 (ARMv9.6)

313029282726252423222120191817161514131211109876543210
100000000001000000000100
MZmNZnSZAda

FMOP4S <ZAda>.S, <Zn>.S, { <Zm1>.S-<Zm2>.S }

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) then EndOfDecode(Decode_UNDEF);
constant integer esize = 32;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 1;
constant integer mreg = 2;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Encoding: Single-precision, single vectors

Variants: FEAT_SME_MOP4 (ARMv9.6)

313029282726252423222120191817161514131211109876543210
100000000000000000000100
MZmNZnSZAda

FMOP4S <ZAda>.S, <Zn>.S, <Zm>.S

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) then EndOfDecode(Decode_UNDEF);
constant integer esize = 32;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 1;
constant integer mreg = 1;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Encoding: Single-precision, multiple and single vectors

Variants: FEAT_SME_MOP4 (ARMv9.6)

313029282726252423222120191817161514131211109876543210
100000000000000000010100
MZmNZnSZAda

FMOP4S <ZAda>.S, { <Zn1>.S-<Zn2>.S }, <Zm>.S

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) then EndOfDecode(Decode_UNDEF);
constant integer esize = 32;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 2;
constant integer mreg = 1;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Encoding: Single-precision, multiple vectors

Variants: FEAT_SME_MOP4 (ARMv9.6)

313029282726252423222120191817161514131211109876543210
100000000001000000010100
MZmNZnSZAda

FMOP4S <ZAda>.S, { <Zn1>.S-<Zn2>.S }, { <Zm1>.S-<Zm2>.S }

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) then EndOfDecode(Decode_UNDEF);
constant integer esize = 32;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 2;
constant integer mreg = 2;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Encoding: Double-precision, single and multiple vectors

Variants: FEAT_SME_MOP4 && FEAT_SME_F64F64 (FEAT_SME_MOP4 && FEAT_SME_F64F64)

313029282726252423222120191817161514131211109876543210
10000000110100000000011
MZmNZnSZAda

FMOP4S <ZAda>.D, <Zn>.D, { <Zm1>.D-<Zm2>.D }

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) || !IsFeatureImplemented(FEAT_SME_F64F64) then
    EndOfDecode(Decode_UNDEF);
constant integer esize = 64;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 1;
constant integer mreg = 2;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Encoding: Double-precision, single vectors

Variants: FEAT_SME_MOP4 && FEAT_SME_F64F64 (FEAT_SME_MOP4 && FEAT_SME_F64F64)

313029282726252423222120191817161514131211109876543210
10000000110000000000011
MZmNZnSZAda

FMOP4S <ZAda>.D, <Zn>.D, <Zm>.D

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) || !IsFeatureImplemented(FEAT_SME_F64F64) then
    EndOfDecode(Decode_UNDEF);
constant integer esize = 64;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 1;
constant integer mreg = 1;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Encoding: Double-precision, multiple and single vectors

Variants: FEAT_SME_MOP4 && FEAT_SME_F64F64 (FEAT_SME_MOP4 && FEAT_SME_F64F64)

313029282726252423222120191817161514131211109876543210
10000000110000000001011
MZmNZnSZAda

FMOP4S <ZAda>.D, { <Zn1>.D-<Zn2>.D }, <Zm>.D

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) || !IsFeatureImplemented(FEAT_SME_F64F64) then
    EndOfDecode(Decode_UNDEF);
constant integer esize = 64;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 2;
constant integer mreg = 1;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Encoding: Double-precision, multiple vectors

Variants: FEAT_SME_MOP4 && FEAT_SME_F64F64 (FEAT_SME_MOP4 && FEAT_SME_F64F64)

313029282726252423222120191817161514131211109876543210
10000000110100000001011
MZmNZnSZAda

FMOP4S <ZAda>.D, { <Zn1>.D-<Zn2>.D }, { <Zm1>.D-<Zm2>.D }

Decoding algorithm

if !IsFeatureImplemented(FEAT_SME_MOP4) || !IsFeatureImplemented(FEAT_SME_F64F64) then
    EndOfDecode(Decode_UNDEF);
constant integer esize = 64;
constant integer n = UInt('0':Zn:'0');
constant integer m = UInt('1':Zm:'0');
constant integer nreg = 2;
constant integer mreg = 2;
constant integer da = UInt(ZAda);
constant boolean sub_op = TRUE;

Operation

CheckStreamingSVEAndZAEnabled();
constant integer VL = CurrentVL;
constant integer hvsize = VL DIV 2;
constant integer dim = hvsize DIV esize;
constant integer tilesize = 4*dim*dim*esize;
constant bits(tilesize) op3 = ZAtile[da, esize, tilesize];
bits(tilesize) result;

for outprod = 0 to 3
    constant integer row_hv = outprod DIV 2;
    constant integer col_hv = outprod MOD 2;
    constant integer row_base = row_hv * dim;
    constant integer col_base = col_hv * dim;

    constant bits(VL) op1 = Z[n + (nreg-1)*col_hv, VL];
    constant bits(VL) op2 = Z[m + (mreg-1)*row_hv, VL];

    for row = 0 to dim-1
        for col = 0 to dim-1
            constant integer row_idx  = row_base + row;
            constant integer col_idx  = col_base + col;
            constant integer tile_idx = row_idx * dim * 2 + col_idx;

            bits(esize) elem1 = Elem[op1, row_idx, esize];
            constant bits(esize) elem2 = Elem[op2, col_idx, esize];
            constant bits(esize) elem3 = Elem[op3, tile_idx, esize];

            if sub_op then elem1 = FPNeg(elem1, FPCR);
            Elem[result, tile_idx, esize] = FPMulAdd_ZA(elem3, elem1, elem2, FPCR);
ZAtile[da, esize, tilesize] = result;

Explanations

<ZAda>: For the "Half-precision, multiple and single vectors", "Half-precision, multiple vectors", "Half-precision, single and multiple vectors", and "Half-precision, single vectors" variants: is the name of the ZA tile ZA0-ZA1, encoded in the "ZAda" field.
<ZAda>: For the "Single-precision, multiple and single vectors", "Single-precision, multiple vectors", "Single-precision, single and multiple vectors", and "Single-precision, single vectors" variants: is the name of the ZA tile ZA0-ZA3, encoded in the "ZAda" field.
<ZAda>: For the "Double-precision, multiple and single vectors", "Double-precision, multiple vectors", "Double-precision, single and multiple vectors", and "Double-precision, single vectors" variants: is the name of the ZA tile ZA0-ZA7, encoded in the "ZAda" field.
<Zn>: Is the name of the first source scalable vector register, registers in the range Z0-Z15, encoded as "Zn" times 2.
<Zm1>: Is the name of the first scalable vector register of the second source multi-vector group, in the range Z16-Z31, encoded as "Zm" times 2 plus 16.
<Zm2>: Is the name of the second scalable vector register of the second source multi-vector group, in the range Z16-Z31, encoded as "Zm" times 2 plus 17.
<Zm>: Is the name of the second source scalable vector register, registers in the range Z16-Z31, encoded as "Zm" times 2 plus 16.
<Zn1>: Is the name of the first scalable vector register of the first source multi-vector group, in the range Z0-Z15, encoded as "Zn" times 2.
<Zn2>: Is the name of the second scalable vector register of the first source multi-vector group, in the range Z0-Z15, encoded as "Zn" times 2 plus 1.