Module Spoc_core.Soa

type leaf = {
  1. path : string;
  2. ty : Sarek_ir_types.elttype;
  3. aos_offset : int;
  4. size : int;
}

One scalar leaf of a flattened record: its dotted path, scalar type, byte offset within the packed AoS element, and scalar byte size.

type plan = {
  1. name : string;
  2. leaves : leaf list;
  3. aos_stride : int;
}

A SoA storage plan for a flat record type. aos_stride is the packed AoS element size in bytes (the stride between consecutive elements in AoS).

exception Unsupported of string

Raised to refuse an operation the SoA layer cannot do without either corrupting data or misrepresenting what happened.

Below is the list of RAISERS, which is closed as of this comment (grep -rn "Unsupported" sarek/core/Soa.ml sarek/core/Soa_vector.ml to re-derive it). The reasons under each raiser are examples, not an enumeration — read the message, not this list, to learn why a particular call refused.

  • plan and plan_of_elttype: the element type is not a v1-supported SoA target. Reached by a non-record; by a nested-record, variant, array or vector field; by an f16 or uint8 field; and by a Sarek_ir_layout.record_layout failure such as a misaligned field.
  • Soa_vector.create, and therefore Soa_vector.create_transparent: the element type's custom_type.ir_fields is None, so no flat-record layout is derivable at all. Raised before plan is reached.
  • Soa_vector.scatter: a vector's host data is out of date while auto-sync is disabled, so the transpose cannot be done correctly and silently.

That last cause is unlike the others and callers must not conflate them: it is a transient property of one VECTOR's state, not a permanent property of a TYPE, and the same call succeeds once the host copy is refreshed. A handler that reads Unsupported as "this type can never be SoA" and installs a permanent AoS fallback is wrong for it.

val plan : name:string -> (string * Sarek_ir_types.elttype) list -> plan

Build a SoA plan from a record's named fields. Reuses Sarek_ir_layout.record_layout for leaf offsets/sizes/stride. Every field must be a scalar; nested records, variants and arrays are rejected with Unsupported.

val plan_of_elttype : Sarek_ir_types.elttype -> plan

plan_of_elttype t requires t to be a TRecord.

val num_leaves : plan -> int

Number of scalar leaves (= number of SoA sub-buffers / kernel base pointers a SoA vector of this type needs).

val aos_bytes : plan -> length:int -> int

Total bytes an AoS buffer of length elements occupies (length * aos_stride).

val scatter : plan -> aos:unit Ctypes.ptr -> length:int -> leaves:unit Ctypes.ptr array -> unit

scatter plan ~aos ~length ~leaves copies each element's field values from the packed AoS buffer aos into the per-leaf contiguous buffers leaves (leaves.(k) receives the k-th leaf, in plan.leaves order). Bit-preserving copy; works for any scalar leaf types.

val gather : plan -> leaves:unit Ctypes.ptr array -> length:int -> aos:unit Ctypes.ptr -> unit

Inverse of scatter: gather per-leaf SoA buffers back into a packed AoS buffer.