Sarek_matrix_patternRecognition of matrix-product (GEMM) loop nests in Sarek IR.
A GEMM nest is an accumulator acc (a let mut) updated by a for loop over a reduction variable kv as acc := acc + A[ia] * B[ib] (or fma A[ia] B[ib] acc) and then stored once as C[ic] <- e(acc), where the three indices are affine (Sarek_ir_affine) and separate into a row index M (in A and C), a column index N (in B and C), kv (in A and B) and optional batch indices (in C, and in A or B or both). The full pattern and every rejection are specified in specs/matrix-pattern-advice.md.
This module only recognises. Sarek_matrix_advice says which matrix-unit configuration applies; the PPX turns that into a compile-time alert; and Sarek_fusion uses it to explain why a GEMM operand is not fused.
Scope: the kernel body only, not helper functions. An accumulation written directly into memory (c.(i) <- c.(i) + a * b in the loop) is not a candidate.
include module type of struct include Sarek_matrix_pattern_types endHow an operand is laid out in memory, from its two strides: row-major when the column stride is 1, column-major when the row stride is 1. Any other operand (no unit stride, equal strides, overlapping rows) is not a GEMM operand: a matrix unit loads a tile with one base and one leading dimension.
type operand = Sarek_matrix_pattern_types.operand = {array : string;elt : Sarek_ir_types.elttype;index : Sarek_ir_types.expr;row_stride : Sarek_ir_types.expr;col_stride : Sarek_ir_types.expr;layout : layout;offset : Sarek_ir_types.expr;}One matrix of C = A × B. Rows and columns are those of the matrix: A is M × K, B is K × N, C is M × N. The strides are uniform expressions; offset is everything in the index that is neither the row nor the column term (constants and batch terms). index is the let-inlined index.
type update = Sarek_matrix_pattern_types.update = type epilogue = Sarek_matrix_pattern_types.epilogue = | PlainC[ic] <- acc, possibly through a cast
| Epilogue of Sarek_ir_types.expracc occurs once, beside uniform values and reads of C[ic] (e.g. alpha * acc + beta * C[ic])
type gemm = Sarek_matrix_pattern_types.gemm = {acc : Sarek_ir_types.var;init : Sarek_ir_types.expr;the accumulator's initial value, let-inlined
*)k_var : Sarek_ir_types.var;k_lo : Sarek_ir_types.expr;inclusive, uniform
*)k_hi : Sarek_ir_types.expr;inclusive, uniform
*)m_index : Sarek_ir_types.expr;the row atom, e.g. global_idx_y or tid / n
n_index : Sarek_ir_types.expr;the column atom
*)batch : Sarek_ir_types.expr list;batch atoms of C
*)a : operand;b : operand;c : operand;update : update;epilogue : epilogue;guards : Sarek_ir_types.expr list;conditions of the enclosing ifs, outermost first, then the store's own guard; let-inlined
enclosing_loops : Sarek_ir_types.var list;outermost first
*)unmodelled_control : string option;control on the path to the nest that guards does not describe (an else branch, a while, a match case): guards is then not the whole condition under which the store runs
}type reason = Sarek_matrix_pattern_types.reason = | Downto_loop| Loop_body_not_single_update| Not_a_product| Operand_not_an_element of Sarek_ir_types.expr| Operand_not_global of string| Bounds_not_uniform| Bounds_data_dependent| Index_not_affine of string * Sarek_ir_types.expr option| Int64_arithmetican index, bound or guard computes in 64 bits (compiler review C-11)
*)| Operand_independent_of_reduction of string| Output_depends_on_reduction| No_row_column_split| Stray_index_atom of string| Nested_accumulation| Accumulator_escapes| No_output_store| Unsupported_epilogue| Output_aliases_operand of string| Operand_written of string| Overlapping_operand of string| Constant_leading_dimension of string| Output_written_elsewhere of string| Operand_not_unit_stride of string| Dependent_indices| Unsupported_initWhy a reduction loop is not a GEMM nest. Payloads name the array or the sub-expression at fault.
type near_miss = Sarek_matrix_pattern_types.near_miss = {nm_acc : Sarek_ir_types.var;nm_loop : Sarek_ir_types.var;nm_reason : reason;}A reduction loop (a for whose body updates a let mut from itself) that is not a GEMM nest.
val reason_text : reason -> stringval layout_name : layout -> stringval analyze : Sarek_ir_types.kernel -> finding listEvery reduction loop of the kernel body, in body order.
val recognise : Sarek_ir_types.kernel -> gemm listThe Gemm findings of analyze.