fms.md

December 24, 2024 · View on GitHub

Quick summary

InstructionGeneral themeWritemaskOptional special features
fms64 (63=0)
fms32 (63=0)
fms16 (63=0)
z[j][i] -= x[i] * y[j]7 bit X, 7 bit YX/Y/Z input disable
fms64 (63=1)
fms32 (63=1)
fms16 (63=1)
z[_][i] -= x[i] * y[i]7 bitX/Y/Z input disable

Instruction encoding

BitWidthMeaningNotes
1022A64 reserved instructionMust be 0x201000 >> 10
55Instruction11 for fms64
13 for fms32
16 for fms16
055-bit GPR indexSee below for the meaning of the 64 bits in the GPR

Operand bitfields

BitWidthMeaningNotes
631Vector mode (1) or matrix mode (0)
621Z is f32 (1) or Z is instruction width (0)Only used by fms16 in matrix mode, ignored otherwise
611X is f16 (1) or X is instruction width (0)Only used by fms32, ignored otherwise
601Y is f16 (1) or Y is instruction width (0)Only used by fms32, ignored otherwise
4812Ignored
462X enable mode
415X enable valueMeaning dependent upon associated mode
392Ignored
372Y enable modeIgnored in vector mode
325Y enable valueIgnored in vector mode
Meaning dependent upon associated mode
302Ignored
291Skip X input (1) or use X input (0)
281Skip Y input (1) or use Y input (0)
271Skip Z input (1) or use Z input (0)
261Ignored
206Z rowHigh bits ignored in matrix mode
191Ignored
109X offset (in bytes)
91Ignored
09Y offset (in bytes)

Combinations of bits 27-29 result in various floating-point ALU operations:

Operation29 (X)28 (Y)27 (Z)
z-x*y000
 -x*y001
z-x  010
 -x  011
z-  y100
 -  y101
z    110
 -0111

Combinations of the instruction and bits 60-63 result in various widths for X / Y / Z:

ModeXYZ63 (M)62 (Z)61 (X)60 (Y)Op
Matrixf16f16f16 (one row from each two)00fms16
Matrixf16f16f32 (all rows, interleaved pairs)01fms16
Matrixf32f32f32 (one row from each four)000fms32
Matrixf32f16 (even lanes)f32 (one row from each four)001fms32
Matrixf16 (even lanes)f32f32 (one row from each four)010fms32
Matrixf16 (even lanes)f16 (even lanes)f32 (one row from each four)011fms32
Matrixf64f64f64 (one row from each eight)0fms64
Vectorf16f16f16 (one row)1fms16
Vectorf32f32f32 (one row)100fms32
Vectorf32f16 (even lanes)f32 (one row)101fms32
Vectorf16 (even lanes)f32f32 (one row)110fms32
Vectorf16 (even lanes)f16 (even lanes)f32 (one row)111fms32
Vectorf64f64f64 (one row)1fms64

X/Y enable modes:

ModeMeaning of value (N)
0Enable all lanes (0), or odd lanes only (1), or even lanes only (2), or no lanes (anything else)
1Only enable lane #N
2Only enable the first N lanes, or all lanes when N is zero
3Only enable the last N lanes, or all lanes when N is zero

Description

In vector mode, performs a pointwise fused-multiply-subtract (or simplification thereof) operation between an X vector, a Y vector, and a Z vector, accumulating onto the Z vector. All three vectors have the same element type, either f16 or f32 or f64. Alternatively, when Z has type f32, X or Y (or both) can have type f16, though only the even lanes are used.

In matrix mode, performs a fused-multiply-subtract (or simplification thereof) outer-product between an X vector, a Y vector, and a 2D grid of Z values, accumulating onto Z. All three of X and Y and Z have the same element type, either f16 or f32 or f64. Alternatively, when Z has type f32, X or Y (or both) can have type f16, though only the even lanes are used. As a final alternative, when Z has type f32 and both X/Y have type f16, then all lanes of X and Y can be used in combination with the entire 64x64 byte grid of Z, with even lanes of X going into even Z registers and odd lanes of X going into odd Z registers (see Mixed lane widths).

Emulation code

See fms.c. Note the code in test.c to set the DN bit of fpcr.

A representative sample is:

void emulate_AMX_FMS64(amx_state* state, uint64_t operand) {
    uint64_t y_offset = operand & 0x1FF;
    uint64_t x_offset = (operand >> 10) & 0x1FF;
    uint64_t z_row = (operand >> 20) & 63;
    uint64_t x_enable = parse_writemask(operand >> 41, 8, 7);
    uint64_t y_enable = parse_writemask(operand >> 32, 8, 7);

    double x[8];
    double y[8];
    load_xy_reg(x, state->x, x_offset);
    load_xy_reg(y, state->y, y_offset);

    for (int i = 0; i < 8; i++) {
        if (!((x_enable >> (i * 8)) & 1)) continue;
        if (operand & FMA_VECTOR_PRODUCT) {
            double* z = &state->z[z_row].f64[i];
            *z = fms64_alu(x[i], y[i], *z, operand);
        } else {
            for (int j = 0; j < 8; j++) {
                if (!((y_enable >> (j * 8)) & 1)) continue;
                double* z = &state->z[(j * 8) + (z_row & 7)].f64[i];
                *z = fms64_alu(x[i], y[j], *z, operand);
            }
        }
    }
}

double fms64_alu(double x, double y, double z, uint64_t operand) {
    switch ((operand >> 27) & 7) {
    case 1: z = -0.; break;
    case 2: return z - x;
    case 3: return -x;
    case 4: return z - y;
    case 5: return -y;
    case 6: return z;
    case 7: return -0.;
    }
    double out;
    __asm("fmsub %d0, %d1, %d2, %d3" : "=w"(out) : "w"(x), "w"(y), "w"(z));
    return out;
}

Performance

Identical to corresponding fma instruction.