Sarek_metal.Metal_bindingsval objc_msgSend_lazy :
(unit Ctypes_static.ptr ->
unit Ctypes_static.ptr ->
unit Ctypes_static.ptr)
lazy_tobjc_msgSend - the core Objective-C message dispatch
sel_registerName - register a selector
objc_getClass - get a class by name
Load Foundation framework for NSString, NSArray, etc
val mtl_create_system_default_device_lazy :
(unit -> Metal_types.mtl_device) lazy_tMTLCreateSystemDefaultDevice - get default GPU
val mtl_create_system_default_device : unit -> Metal_types.mtl_deviceMTLCopyAllDevices - get all Metal devices
val mtl_device_max_threads_per_threadgroup :
unit Ctypes_static.ptr ->
Metal_types.mtl_size Ctypes.structureval mtl_device_new_buffer_with_length :
unit Ctypes_static.ptr ->
int ->
Unsigned.uint64 ->
Metal_types.mtl_bufferREAD FROM THE SDK, not guessed: MTLLibrary.h:241-246 and 258-262 on macOS 15.6.1 (Command Line Tools SDK). The previous revision of this file declined to use setMathMode: precisely because these values could not be checked; they can now.
val mtl_compile_options_conformant :
unit ->
Metal_types.mtl_compile_options optionBuild an MTLCompileOptions configured for Sarek's float semantics, or None if that cannot be done on this host.
WHY (backlog #125). Metal's defaults trade accuracy for speed, and until this change mtl_device_new_library_with_source took an _options argument and IGNORED it while Metal_api passed null anyway. So every Sarek Metal kernel took those defaults and there was no route to change them — not "no policy", but an UNSETTABLE wrong default.
MEASURED on Apple M4 / macOS 15.6.1 (24G90) / Apple clang 17.0.0. A freshly constructed MTLCompileOptions reports mathMode = 2 (MTLMathModeFast) and mathFloatingPointFunctions = 0 (...Fast). BOTH defaults are the fast one, which is why both are set here — setting mathMode alone still leaves single-precision math functions resolving to metal::fast.
THE OPTIONS ARE HONOURED, and that had to be established rather than assumed: a compile that succeeds proves plumbing, not semantics. Over 65536 inputs on sqrt(a) + 1/a, against the default:
mathMode=Safe alone changes 16017 results;mathMode=Safe + fpFunctions=Precise changes 22135.So Metal is NOT in the class of rusticl's OpenCL FP options, which are accepted and discarded (docs/fp-contraction-policy.md §9.2).
WHAT THESE OPTIONS DO NOT BUY: CONTRACTION. Measured on the same device, a*b+c is contracted into an fma on all 8773 observable elements under EVERY setting tried, including mathMode=Safe. Contraction is defeated in the generated source instead, by #pragma METAL fp contract(off) (Sarek_ir_metal.metal_fp_contract_pragma, measured 0/8773). Do not read this function as a contraction defence; it is not one.
WHY BOTH SPELLINGS. fastMathEnabled is deprecated since macOS 15.0 in favour of mathMode, but mathMode does not exist before macOS 15.0 / iOS 18.0, so the deprecated property is the only route on older systems. The modern pair is preferred when present and the boolean is the fallback. They are EQUIVALENT, measured: fastMathEnabled = NO and mathMode=Safe + fpFunctions=Precise are BIT-IDENTICAL over 65536 elements of sqrt + reciprocal + sin + log + exp. The fallback is therefore not a degraded path, and that is measured rather than believed.
FAIL-SOFT BY CONSTRUCTION. Every failure path returns None, and None makes the caller pass null, which is EXACTLY the behaviour that shipped before this change: a missing libobjc, a missing class, an OS responding to neither selector, or a null allocation all degrade to the old behaviour rather than propagating.
val mtl_device_new_library_with_source :
unit Ctypes_static.ptr ->
string ->
Metal_types.mtl_compile_options option ->
(Metal_types.mtl_library, string) Stdlib.resultCompile MSL source into an MTLLibrary.
options is now HONOURED. Before backlog #125 this function's parameter was named _options and dropped on the floor, so the only thing it could ever pass was null — see mtl_compile_options_conformant for what that meant.
val mtl_library_new_function_with_name :
unit Ctypes_static.ptr ->
string ->
Metal_types.mtl_functionval mtl_device_new_compute_pipeline_state :
unit Ctypes_static.ptr ->
Metal_types.mtl_function ->
(Metal_types.mtl_compute_pipeline_state, string) Stdlib.resultval mtl_compute_command_encoder_set_compute_pipeline_state :
unit Ctypes_static.ptr ->
Metal_types.mtl_compute_pipeline_state ->
unitval mtl_compute_command_encoder_set_buffer :
unit Ctypes_static.ptr ->
Metal_types.mtl_buffer ->
int ->
int ->
unitval mtl_compute_command_encoder_dispatch_threads :
unit Ctypes_static.ptr ->
Metal_types.mtl_size Ctypes.structure ->
Metal_types.mtl_size Ctypes.structure ->
unit