Alkaid Low-Level Intermediate Representation (ALIR)
ALIR is alkaid’s low-level static-dataflow representation. A CombLogic program is a single SSA-style combinational block: each operation writes one buffer slot, later operations may read earlier slots, and outputs are selected from the final buffer.
The serialized JSON form written by CombLogic.save() is:
meta: the stringALIRModel.spec_version: the ALIR spec version. The current version is4.model: theCombLogicpayload described below.
CombLogic Payload
The model payload is stored as an array in the same order as the CombLogic fields:
shape:[n_inputs, n_outputs].inp_shifts: input scale shifts.out_idxs: buffer indices used as outputs.-1means a zero output.out_shifts: output scale shifts.out_negs: output sign flags.ops: operation records.carry_size: CMVM cost/latency configuration.adder_size: CMVM cost/latency configuration.lookup_tables: optional lookup table records, present only when lookup operations are used.
Each operation record is stored in the same order as the Op fields:
addr: buffer dependency indices.opcode: operation code. See the operation code table below.data: signed 64-bit integer payload tuple whose meaning depends on the operation.qint: output quantization interval as[min, max, step].latency: estimated availability time.cost: estimated operation cost.
For non-input operations, every addr index must refer only to an earlier operation.
Operation Codes
-2: Explicit negation.addr = (x,),data = ().buf[i] = -buf[x]
-1: Copy from the external input buffer and quantize.addr = (),data = (input_idx,).buf[i] = input[input_idx]
0: Addition.addr = (a, b),data = (shift,).buf[i] = buf[a] + buf[b] * 2^shift
1: Subtraction.addr = (a, b),data = (shift,).buf[i] = buf[a] - buf[b] * 2^shift
2: ReLU with output quantization.addr = (x,),data = ().buf[i] = quantize(relu(buf[x]))
3: Output quantization.addr = (x,),data = (relative_shift,).buf[i] = quantize(buf[x] * 2^relative_shift).relative_shiftrecords the source-to-wrap-buffer scale shift needed when tracing-level wrap resets its implementation_factor.
4: Add a constant.addr = (x,),data = (value, shift).The constant is
value * 2^-shift.
5: Define a constant.addr = (),data = (value,).buf[i] = value * qint.step
6: Mux by the most-significant bit of a condition value.addr = (true_idx, false_idx, cond_idx),data = (false_shift,).buf[i] = MSB(buf[cond_idx]) ? buf[true_idx] : buf[false_idx] * 2^false_shift, then quantized toqint.
7: Multiplication.addr = (a, b),data = ().buf[i] = buf[a] * buf[b]
8: Logic lookup table.addr = (x,),data = (table_idx,).Bytecode appends an internal second data entry for the lookup pad offset derived from
x’s quantization interval.
9: Unary bitwise operation.addr = (x,),data = (subop,).subop = 0: bitwise NOT.subop = 1: reduce-any.subop = 2: reduce-all.
10: Binary bitwise operation.addr = (a, b),data = (shift, subop).subop = 0: AND.subop = 1: OR.subop = 2: XOR.
11: Variadic signed shifted sum. Only N=3 can emit RTL currently.addr = (x0, x1, ..., xN),data = (sign0, shift0, sign1, shift1, ..., signN, shiftN).N >= 1; eachsignKis1for+and0for-.buf[i] = sum((+1 if signK else -1) * buf[xK] * 2^shiftK for K in range(N + 1))
Quantizing operations use direct fixed-point bit drop semantics: wrap for overflow and truncate for rounding.
External Bytecode Representation
CombLogic.to_bytecode() produces the raw byte string consumed by the C++ ALIR interpreter. This is an in-memory interpreter format for Python -> C++ communication, not a stable on-disk format. The bytecode is further converted to another internal bytecode format in the C++ interpreter for faster dispatch, which is not described here.
The bytecode is little-endian and laid out sequentially:
Header:
magic,spec_version,n_inputs,n_outputs,n_ops,n_tables, encoded as<4sIIIII>.magicisALIR.inp_shifts:i32[n_inputs].out_idxs:i32[n_outputs].out_shifts:i32[n_outputs].out_negs:u8[n_outputs].Per-operation records, each followed by its variable-length address and data arrays.
Tables: for each table,
u32 table_sizefollowed byi32[table_size].
Each bytecode operation record starts with:
opcode:i8.signed:u8.integers: signed one-byte integer-bit count, excluding the sign bit.fractionals: signed one-byte fractional-bit count.n_addr:u16.n_data:u16.addr:u32[n_addr].data:i64[n_data].
For opcode 8, bytecode contains the semantic lookup table index plus an internal second data entry containing the derived lookup pad offset. JSON remains semantic and stores only (table_idx,).
Lookup table data is stored in increasing lookup-index order. The bytecode loader validates the magic, ALIR spec version, bytecode length, generic address causality, ranges, EOF, and the interpreter’s current 64-bit intermediate-width limit.
The JSON loader in the C++ interpreter accepts v4 plain JSON and gzip-compressed JSON with the same ALIRModel wrapper used by CombLogic.save(). v2 and v3 files can be loaded in Python, but the C++ JSON loader only accepts v4. Use alkaid convert old.json[.gz] new.json[.gz] --flavor json to convert on disk.