Module Sarek_execute.Kernel_access

How a kernel uses its vector parameters, and whether it can be fused horizontally (specs/launch-window.md).

Both answers are read from the IR only and are conservative: a use this module cannot classify counts as a read AND a write, and a construct it does not understand makes the kernel non-fusable. Wrong in the other direction would let the launch window reorder or merge launches that conflict.

Read/write sets

type access = {
  1. read : bool;
  2. write : bool;
}
val no_access : access
val both : access
val join : access -> access -> access
val vector_params : Sarek_ir_types.kernel -> string list

Vector parameter names of k, in declaration order.

type acc = (string, access) Stdlib.Hashtbl.t
val note : acc -> string -> access -> unit
val read_ : access
val write_ : access
val base_access : acc -> access -> Sarek_ir_types.expr -> unit
val expr : acc -> Sarek_ir_types.expr -> unit
val lvalue : acc -> Sarek_ir_types.lvalue -> unit
val coopmat : acc -> Sarek_ir_types.coopmat_op -> unit
val stmt : acc -> Sarek_ir_types.stmt -> unit
val param_accesses : Sarek_ir_types.kernel -> (string * access) list

Access of each vector parameter of k, in declaration order. Helper functions receive vectors only as arguments, which expr already counts as both.

Horizontal fusability

val rewritten_intrinsics : string list

Position intrinsics that horizontal fusion rewrites, under the exact path Sarek_stdlib.Gpu only. Each rewritten form keeps the type the backends give the original: block_idx_x - off and gdx * block_dim_x stay in the backend's own unsigned type where it has one.

val refused_intrinsics : string list

Position intrinsics a member may not use at all. grid_dim_x would have to become an int parameter, while CUDA/HIP, OpenCL and Metal emit it as an unsigned value, so comparisons and divisions with negative operands would change meaning. block_id_x is an alias the backends accept for block_idx_x; it is refused rather than rewritten under a second name.

val gpu_path : string list
val is_stdlib_path : string list -> bool
exception Refuse of string
val refuse : ('a, unit, string, 'b) Stdlib.format4 -> 'a
module Ids : sig ... end
module Names : sig ... end
type scope = {
  1. ids : Ids.t;
  2. names : Names.t;
  3. helpers : Names.t;
  4. in_helper : bool;
}
val bind : scope -> Sarek_ir_types.var -> scope
val bind_pattern : scope -> Sarek_ir_types.pattern -> scope
val check_intrinsic : scope -> string list -> string -> unit
val check_expr : scope -> Sarek_ir_types.expr -> unit
val check_lvalue : scope -> Sarek_ir_types.lvalue -> unit
val check_stmt : scope -> Sarek_ir_types.stmt -> unit
val shared_bytes_of : Sarek_ir_types.elttype -> Sarek_ir_types.expr -> int
val kernel_scope : Sarek_ir_types.kernel -> scope
val check_kernel : Sarek_ir_types.kernel -> int
val horizontal_verdict : Sarek_ir_types.kernel -> (int, string) Stdlib.result

Ok bytes when k can be a member of a horizontally fused kernel, with the shared memory it declares; otherwise the reason it cannot.