Module Sarek_execute.Fusion_horizontal

Horizontal fusion of independent kernels (specs/launch-window.md, FR-011).

Members M_0 .. M_{n-1} with the same block shape become one kernel whose grid x is the sum of theirs. Work-group b with off_k <= b < off_k + gx_k runs member k's body unchanged, except that the work-group position it observes is rewritten back to its own: block_idx_x reads b - off_k, grid_dim_x reads gx_k, and the global index and size intrinsics follow. No value flows between members and no arithmetic is added to a member's data path, so the result is bit-identical to running the members one after the other, on every backend.

The dispatch condition depends only on block_idx_x, so it is uniform per work-group: barriers inside a member stay legal.

Every name of member k (parameters, locals, shared arrays, loop and pattern variables) is prefixed m<k>_ and its var ids are offset, so members cannot capture each other's names. The fused kernel's parameters are the members' parameters in order, followed by hf<k>_off and hf<k>_gdx (int32) for each member, a namespace no renamed member name can enter.

val prefix : int -> string -> string
val int32_var : stride:int -> members:int -> int -> string -> Sarek_ir_types.var
val gpu : string -> Sarek_ir_types.expr

Renaming and position rewrite

type ctx = {
  1. k : int;
  2. stride : int;
  3. off : Sarek_ir_types.expr;
  4. gdx : Sarek_ir_types.expr;
}
val member_block : ctx -> Sarek_ir_types.expr
val position : ctx -> string -> Sarek_ir_types.expr option
val renaming : ctx -> Ir_rename.ctx

Assembly

exception Incompatible of string
val union_named : what:string -> ('a -> string) -> 'a list list -> 'a list
type member_parts = {
  1. binds : (Sarek_ir_types.var * Sarek_ir_types.expr) list;
    (*

    hoisted shared arrays, renamed

    *)
  2. body : Sarek_ir_types.stmt;
    (*

    renamed and rewritten

    *)
  3. params : Sarek_ir_types.decl list;
  4. locals : Sarek_ir_types.decl list;
  5. off_var : Sarek_ir_types.var;
  6. gdx_var : Sarek_ir_types.var;
}
val member_parts : stride:int -> members:int -> int -> Sarek_ir_types.kernel -> member_parts
val dispatch : member_parts list -> Sarek_ir_types.stmt
val fuse : name:string -> Sarek_ir_types.kernel list -> Sarek_ir_types.kernel

Fuse members (at least two, each with Kernel_access.horizontal_verdict = Ok) into one kernel named name. Raises Incompatible when two members define the same type or helper name differently.

val content_named : prefix:string -> Sarek_ir_types.kernel -> Sarek_ir_types.kernel option

k renamed prefix ^ digest, the digest of everything in k but its name: the same fusion gets the same name in every process, so a device compiler's on-disk cache keyed on name and source serves it, and two fused kernels whose IR differs get different names short of an MD5 collision; nothing relies on that, as every compile cache also keys on the source. None when k holds a function value (inline native code), whose bytes have no stable digest.