Module Tolk.Decomp_op
Operations as the operations a target has.
Code generation lowers the operations a target lacks, and some it has, to cheaper ones: floor divisions to truncating ones, divisions by constants to multiplications and shifts, the Op.t.Threefry hash to integer arithmetic, and comparisons, negations and fused multiply-adds to the forms renderers expect. A target states its operations as a set of Op.t, the keys of its renderer's code_for_op.
Integer division
val fast_idiv : Renderer.t -> Ops.t -> Bigint.t -> Ops.t optionfast_idiv r x d is x divided by the positive constant d, rounding towards zero, as a multiplication and a right shift: (x * m) >> s, for x's values from 0 to its upper bound. It shifts the powers of two out of d first when the product would overflow x's type, and otherwise computes in the next wider integer type if r supports it (Renderer.supported_dtypes). It is const_like x 0 if x's upper bound is below d, and None if d is not positive, x can be negative, or no such computation fits.
Threefry
threefry2x32 x key is the Threefry-2x32 hash of the Dtype.t.Uint64 counter x under key, with 20 rounds, as 32-bit additions, rotations and exclusive ors: the two 32-bit words of the result, high word second, in a Dtype.t.Uint64.
Patterns
val simplifying_patterns : Op.Set.t -> (unit, Ops.t) Ops.Pattern_matcher.tsimplifying_patterns ops lowers, for a target with the operations ops:
- a floor division (
Op.t.Div) of an integer by a power of two, read in the integer's type, to a right shift ifopshasOp.t.Shr, and any other to a truncating division (Op.t.Truncdiv), corrected where the operands' signs can differ and the divisor is not0, by which the quotient is0; - a floor remainder (
Op.t.Mod) of an integer by a power of two, read in the integer's type, to a mask ifopshasOp.t.And, and any other to a truncating remainder (Op.t.Truncmod), corrected where the operands' signs can differ; Op.t.Threefrytothreefry2x32ifopslacks it.
A division or remainder of a committed integer reads a weak constant divisor in the integer's type, here and in late_patterns: on int8, a divisor of 128 is -128.
A set equal to an earlier call's gives that call's matcher.
val late_patterns :
disable_fast_idiv:bool ->
Op.Set.t ->
(Renderer.t, Ops.t) Ops.Pattern_matcher.tlate_patterns ~disable_fast_idiv ops rewrites, for a target with the operations ops and rendered by the context:
- a minimum of a minimum against one value
c, or a maximum of a maximum, each a selection of its comparison's operands, to one selection: the inner one where it pickscwhere its comparison is false, at a tie or a NaN, or where the two pick alike, and otherwise the selection of the inner one's other operandvthat pickscthere,where (v < c) v cfor minima andwhere (c < v) v cfor maxima; Op.t.Maxto a comparison and a selection ifopslacks it and hasOp.t.Cmplt;- the conjunction of two negated booleans to the negated disjunction if
opshasOp.t.Or; - a multiplication of an integer by a power of two, read modulo 2 to the integer's width, to a left shift if
opshasOp.t.Shl: the shift is below the width, as on int32x * 2^32isx * 0; - if
opshasOp.t.Shr, a truncating division of an integer by a power of two, read in the integer's type, to a right shift, rounding negative dividends up first; and, unlessdisable_fast_idiv, a truncating division or remainder by any other constant withfast_idivwhere it applies; - multiplications by
-1toOp.t.Neg, and additions of a negation toOp.t.Sub, ifopshas them; - if
opshasOp.t.Cmplt, negated comparisons of signed integers with constants to comparisons,x * -1 < y * ctoy * -c < x,x * -1 < cto-c < x, andc1 < x && x < c2tox == c1 + 1when it is the one integer between; - negated
Op.t.CmpeqtoOp.t.Cmpneifopshas it; a * b + c, and(x << n) + c, toOp.t.Mulaccifopshas it;- if
opshasOp.t.Fdiv, reciprocals to a division of1.0.
Arguments equal to those of an earlier call give that call's matcher.