Spoc_framework.Framework_sigval dims_1d : int -> dimsval dims_2d : int -> int -> dimsval dims_3d : int -> int -> int -> dimstype capabilities = {max_threads_per_block : int;max_block_dims : int * int * int;max_grid_dims : int * int * int;total_global_mem : int64;compute_capability : int * int;(major, minor) for CUDA, (0,0) for OpenCL
*)device_features : Sarek_ir_analysis.feature list;The wide element types this DEVICE provides, as the same vocabulary Sarek_ir_analysis.kernel_uses asks a kernel for. The pairing is the point: a kernel says what it REQUIRES, this says what the device PROVIDES, and a launch gate is one List.mem rather than a per-width boolean added to this record every time a width is.
Replaces the former supports_fp64 : bool (#142). It was a single boolean for a question that already had three answers — fp64, f16 and int64 — and the missing one had teeth: an int64 kernel reached vkCreateShaderModule declaring OpCapability Int64 against a logical device that had never enabled shaderInt64, because nothing in this record could express the int64 half of the question. Read it through Sarek_capability.permits, never by testing membership directly: an unprobed device must not fall into the permitted bucket.
Spoc_core.Device.allows_fp64 and allows_int64 are the derived accessors, so this stays the single source and the two cannot drift.
coopmat : Sarek_coopmat.device_support option;The cooperative-matrix (tensor-core) configurations this DEVICE advertises, or None when the backend does not probe for them (backlog-62 slice 2).
An OPTION rather than a plain list, for the same reason Sarek_capability.device_verdict takes one: an empty list and an unprobed device are different facts, and collapsing them makes "advertises nothing" indistinguishable from "nobody asked". Only the first is evidence. Sarek_coopmat.verdict maps None to Sarek_capability.verdict.Unknown, which does not permit.
Read it through Sarek_coopmat.verdict or Sarek_coopmat.find_config, never by matching on the list directly.
supports_atomics : bool;warp_size : int;Invocations that execute in lockstep — CUDA warp, AMD wavefront, Vulkan/Metal subgroup. Load-bearing for cooperative matrices, whose fragments are distributed across exactly this many invocations (Sarek_coopmat.components_per_invocation), so a wrong value here is a wrong ABI rather than a wrong statistic. The Vulkan backend now reports VkPhysicalDeviceSubgroupProperties.subgroupSize instead of a hard-coded 32; on the RX 7900 XTX under radv / Mesa 26.1.4-arch3.1 that is 64.
max_registers_per_block : int;clock_rate_khz : int;multiprocessor_count : int;is_cpu : bool;True for CPU devices - enables zero-copy optimization
*)}Device capabilities - queried from hardware
type device = {id : int;Global device ID (0, 1, 2...)
*)backend_id : int;ID within the backend (0, 1...)
*)name : string;Human-readable device name
*)framework : string;Backend name: "CUDA", "OpenCL", "Vulkan", "Native"
*)capabilities : capabilities;}Device representation - SDK layer type shared across all backends
module type S = sig ... endMinimal framework signature for plugin registration. Used by Framework_registry for basic plugin management.
Execution model for backends.
Extensible type for backend-specific kernel arguments. Each backend extends this type with its own variant. This allows type-safe passing of kernel args across the framework boundary with typed witnesses.
Placeholder kargs for testing - not associated with any backend
type run_source_arg = | RSA_Buffer of {binder : kargs -> int -> unit;Binds buffer to kernel arg
*)length : int;Vector length for generated kernels
*)}| RSA_Vector_Length of int32Auto-injected vector length (see Execute.expand_to_run_source_args ~inject_lengths), distinguished from a genuine caller-supplied RSA_Int32 so backends that derive lengths from the bound buffer itself (e.g. Vulkan) can drop it without relying on its position in the argument list - "immediately after a buffer" is not a safe test, since ~inject_lengths:false callers can put a real RSA_Int32 there instead. Backends that need the length as an ordinary scalar kernel argument (CUDA/Metal/OpenCL) treat this identically to RSA_Int32.
| RSA_Int32 of int32| RSA_Int64 of int64| RSA_Float32 of float| RSA_Float64 of floatArgument type for run_source. Buffer binder receives typed kargs.
Convergence behavior of an intrinsic.
module type INTRINSIC_REGISTRY = sig ... endIntrinsic registry interface for backend-specific intrinsics. Note: The actual intrinsic_impl type is defined in each backend's intrinsic registry module to avoid circular dependencies with Sarek_ir.
type exec_arg = Typed_value.exec_arg = | EA_Int32 of int32| EA_Int64 of int64| EA_Float32 of float| EA_Float64 of float| EA_Scalar : (module Typed_value.SCALAR_TYPE with type t = 'a) * 'a -> exec_arg| EA_Composite : (module Typed_value.COMPOSITE_TYPE
with type t = 'a)
* 'a -> exec_arg| EA_Vec of (module Typed_value.EXEC_VECTOR)Re-export typed value types for convenience
module type BACKEND = sig ... endExtended backend signature for Phase 4 unified execution. Adds execution model discrimination and IR-based code generation.
module type PLUGIN_BASE = sig ... endLow-level backend implementation interface shared by the CUDA, OpenCL, and Metal plugin-base modules. This is the device/memory/stream/event/kernel core that each backend's *_plugin_base.ml implements directly on top of its FFI bindings; the full BACKEND interface (source generation, direct execution, intrinsics, external-kernel execution, kargs wrapping) is assembled on top of it in each backend's *_plugin.ml.