Ir.OpsOperation types shared by all backends; and precision types.
module Lazy = Utils.Lazytype ('ocaml, 'impl) precision = | Byte : (Base.char, uint8_elt) precision| Uint16 : (Base.int, uint16_elt) precision| Int32 : (Base.int32, int32_elt) precision| Uint32 : (Base.int32, int32_elt) precisionUsing int32_elt representation but treating as unsigned
*)| Int64 : (Base.int64, int64_elt) precision| Uint64 : (Base.int64, int64_elt) precisionUsing int64_elt representation but treating as unsigned
*)| Uint4x32 : (Stdlib.Complex.t, Stdlib.Bigarray.complex64_elt) precisionA 128-bit value that corresponds to e.g. CUDA's uint4 type. Luckily, the OCaml Bigarray library supports complex64_elt which is a 128-bit value, so we avoid dims conversions.
*)| Half : (Base.float, float16_elt) precision| Bfloat16 : (Base.int, uint16_elt) precisionUsing uint16 representation for now
*)| Fp8 : (Base.char, uint8_elt) precisionUsing uint8 representation for now
*)| Single : (Base.float, float32_elt) precision| Double : (Base.float, float64_elt) precisionval sexp_of_precision :
'ocaml 'impl. ('ocaml -> Sexplib0.Sexp.t) ->
('impl -> Sexplib0.Sexp.t) ->
('ocaml, 'impl) precision ->
Sexplib0.Sexp.ttype prec = | Void_prec| Byte_prec of (Base.char, uint8_elt) precision| Uint16_prec of (Base.int, uint16_elt) precision| Int32_prec of (Base.int32, int32_elt) precision| Uint32_prec of (Base.int32, int32_elt) precision| Int64_prec of (Base.int64, int64_elt) precision| Uint64_prec of (Base.int64, int64_elt) precision| Uint4x32_prec of (Stdlib.Complex.t, Stdlib.Bigarray.complex64_elt) precision| Half_prec of (Base.float, float16_elt) precision| Bfloat16_prec of (Base.int, uint16_elt) precision| Fp8_prec of (Base.char, uint8_elt) precision| Single_prec of (Base.float, float32_elt) precision| Double_prec of (Base.float, float64_elt) precisionval byte : precval uint16 : precval int32 : precval uint32 : precval int64 : precval uint64 : precval uint4x32 : precval half : precval bfloat16 : precval fp8 : precval single : precval double : precval index_prec : unit -> precReturns the precision to use for indexing arithmetic: signed int32, or int64 under the large_models setting (docs/proposals/signed-index-precision.md). Signedness makes machine index arithmetic agree with mathematical integers (no wrap traps for negative intermediates such as convolution offset = -padding forms), and is friendlier to C compilers than defined-wrap unsigned. Unsigned precisions remain for data domains only (uint4x32 RNG state, uint8/uint32 stored values such as class IDs). Int32 overflow is excluded by contract, not by widening: every per-node (padded) element count must fit int32 unless 64-bit indices are in use -- enforced once per node by Tnode.create forcing dims. large_models still selects the 64-bit width here pending the tnode-granular, interval-driven codegen resolution (which also needs a separate resolution for the Metal pool-slot width before the flag can be retired).
val is_up_to_fp16 : prec -> boolval is_narrow_float : prec -> boolThe floating-point formats narrower than f32: the ones a CPU has no arithmetic for, so that every operator over them is a widen/op/narrow round-trip through f32 (gh-ocannl-517). Integer precisions are excluded — their arithmetic is native at every width.
Whether a constant is too large to be safe in a half-precision node. The cutoff (check_half_prec_constants_cutoff, default 2^14) sits well below fp16's 65504 max finite: it is headroom against overflow during arithmetic on the constant, not a representability test.
Both infinities are therefore out of scope by construction, not by exception (gh-ocannl-547). They are exactly representable in IEEE binary16; they are emitted deliberately as reduction identities — see neutral_elem, whose Max is neg_infinity and Min is infinity, with C_syntax rendering them as (-INFINITY) / INFINITY and the GPU backends converting through __float2half / __double2half / a (half) cast, all of which map infinities per IEEE; and no arithmetic can push an infinity past a finite bound, so there is no headroom to preserve. An identity is a sentinel arithmetic is expected to consume, not to accumulate.
Refusing them made every fp16 max-reduction — hence every fp16 softmax, hence every attention model at f16 — fail during lowering, on every backend. NaN is likewise out of scope, by the comparison below being false for it.
val sexp_of_prec : prec -> Base.Sexp.tval prec_of_sexp : Base.Sexp.t -> precval precision_to_string : ('ocaml, 'elt_t) precision -> stringval prec_string : prec -> stringval prec_of_string : Base.String.t -> precval prec_in_bytes : prec -> intval is_float : prec -> boolPrefer precision which is more likely to remain functional in the resulting computations. uint4x32 always dominates, because operations that work on uint4x32 do not support other precisions. Otherwise, fractional number precisions dominate; within them, larger dynamic range precisions dominate.
val apply_prec : ?default:'a -> 'a apply_prec -> prec -> 'aval c_typ_of_prec : prec -> stringval vec_unop_lanes : prec -> Base__Int.tval c_vec_typ_of_prec : length:int -> prec -> stringval hum_typ_of_prec : prec -> stringSee: tinygrad ops, CUDA Math API (intrinsics).
This is a redundant set of operations, aiming to expose hardware-supported "intrinsics", to reduce the need for backends to pattern-match and optimize. Also for convenience.
type binop = | Arg1| Arg2| Add| Sub| Mul| Div| ToPowOf| Relu_gate| Satur01_gate| Max| Min| Mod| Cmplt| Cmple| Cmpeq| Cmpne| Or| And| Threefry4x32_crypto4x32-bit Threefry PRNG, 20-round cryptographic version. Requires a 128-bit key and a 128-bit counter and outputs a 128-bit value (precision Uint4x32).
| Threefry4x32_light4x32-bit Threefry PRNG, 2-round light version (as in JAX/XLA). Requires a 128-bit key and a 128-bit counter and outputs a 128-bit value (precision Uint4x32).
| Uint4x32_to_prec_uniform_laneExtracts one lane of the packed uniform conversion: the first argument is a Uint4x32 block, the second an integer lane index in [0, vec_unop_lanes prec); the result is lane i of vec_unop.Uint4x32_to_prec_uniform applied to the block, guaranteed bitwise-identical to the corresponding vectorized store. IR-internal (gh-509 task 4): minted by the virtualizer to inline packed-uniform results per cell; not exposed in the user-facing syntaxes. Heterogeneous: the arguments must not be converted to the result precision.
val binop_of_sexp : Sexplib0.Sexp.t -> binopval sexp_of_binop : binop -> Sexplib0.Sexp.ttype unop = | Identity| Relu| Satur01Saturate (truncate) to within the interval [0; 1].
| Exp| Log| Exp2| Log2| Sin| Cos| Sqrt| Recip| Recip_sqrt| Neg| TruncTruncate toward zero to an integer value (matches a C (int) cast).
| Tanh_approx| Not0. -> 1. | _ -> 0.
*)| Uint4x32_to_prec_uniform1Non-vectorized variant of Uint4x32_to_prec_uniform that converts the given Uint4x32 to a single value of the output precision. Less bit-efficient but operates poitwise. For random bits, the result is uniform over the range of the precision for integer precisions, and over the range [0.0, 1.0) for floating point precisions.
val unop_of_sexp : Sexplib0.Sexp.t -> unopval sexp_of_unop : unop -> Sexplib0.Sexp.ttype vec_unop = | Uint4x32_to_prec_uniformConverts the given Uint4x32 to the precision of the output in a bit-efficient manner. For random bits, the result is uniform over the range of the precision for integer precisions, and over the range [0.0, 1.0) for floating point precisions. When used in an access pattern, the indices are converted to a byte offset depending on the given precision. NOTE: this operation, unlike any others, impacts projections and shape inference (one input cell corresponds to a few output cells).
*)val vec_unop_of_sexp : Sexplib0.Sexp.t -> vec_unopval sexp_of_vec_unop : vec_unop -> Sexplib0.Sexp.tval ternop_of_sexp : Sexplib0.Sexp.t -> ternopval sexp_of_ternop : ternop -> Sexplib0.Sexp.tval op_of_sexp : Sexplib0.Sexp.t -> opval sexp_of_op : op -> Sexplib0.Sexp.tval neutral_elem : binop -> Base.Float.tEither the left-neutral or right-neutral element of the operation. Unspecified if the operation does not have a neutral element.
val interpret_binop : binop -> Base.Float.t -> Base.Float.t -> Base.Float.tval interpret_unop : unop -> Base.Float.t -> Base.Float.tval interpret_ternop :
ternop ->
Base.Float.t ->
Base.Float.t ->
Base.Float.t ->
Base.Float.tNote: currently the %cd syntax only supports infix binops as assignment ops.
val is_binop_nice_infix : binop -> boolval binop_cd_syntax : binop -> stringval binop_cd_fallback_syntax : binop -> stringIn the %cd syntax, we support uncurried notation for binary ops in addition to the infix notation.
val is_assign_op : binop -> boolval assign_op_cd_syntax : initialize_neutral:bool -> binop -> stringval unop_cd_syntax : unop -> stringNote: currently we do not support unary prefix symbols.
val vec_unop_cd_syntax : vec_unop -> stringval ternop_cd_syntax : ternop -> stringIn the %cd syntax, we use uncurried notation for ternary ops.
val c_rawptr_to_string : Base.nativeint -> prec -> Base.String.tval rawptr_to_string_hum : Base.nativeint -> prec -> Base.String.tval c_ptr_to_string : 'elem Ctypes.ptr -> prec -> Base.String.tval ptr_to_string_hum : 'elem Ctypes.ptr -> prec -> Base.String.tval axis_padding_of_sexp : Sexplib0.Sexp.t -> axis_paddingval sexp_of_axis_padding : axis_padding -> Sexplib0.Sexp.tval equal_axis_padding : axis_padding -> axis_padding -> Base.boolval copy_with_padding_c :
('a, 'b, Stdlib.Bigarray.c_layout) Stdlib.Bigarray.Genarray.t ->
('a, 'b, Stdlib.Bigarray.c_layout) Stdlib.Bigarray.Genarray.t ->
axis_padding Base.array ->
Base.unitThreefry4x32 PRNG - 20 round cryptographic version
Threefry4x32 PRNG - 2 round light version
Threefry4x32 PRNG - default version
Conversion from uint4x32 to various uniform distributions
val is_homogeneous_prec_unop : unop -> boolReturns true if the unary operation is homogeneous in precision, meaning its argument should be converted to the result precision.
val is_homogeneous_prec_vec_unop : vec_unop -> boolReturns true if the vec_unop operation is homogeneous in precision, meaning its argument should be converted to the result precision.
val is_homogeneous_prec_binop : binop -> boolReturns true if the binary operation is homogeneous in precision, meaning its arguments should be converted to the result precision.
val is_homogeneous_prec_ternop : ternop -> boolReturns true if the ternary operation is homogeneous in precision, meaning its arguments should be converted to the result precision.