X_eTaL on GPUs

X_eTaL states a computation as whole-array operations, which already expose their parallelism. This repository runs the same typed X_eTaL programs on GPUs through OpenCL C 1.2, on old and new cards alike (a Kepler Quadro and Maxwell and Pascal Teslas that the newest CUDA toolkits retire, Turing to Blackwell, and Apple silicon), and proves every answer against the X_eTaL evaluator. The goal is the concept, not speed.

What runs today

X_eTaL source, lowered. Every example program is lowered from its own .xtl by this repository's translator, which takes the program's Core (libraries included) from X_eTaL's own crates and builds the program the device runs; the checks prove each one gives the evaluator's output, exactly on the interpreter and within f32's tolerance on the GPU. The hand-written twins that stood in until 2026-10-13 were the translator's oracle and are gone. X_eTaL-ML's models still run from a script that writes their programs; their own source is next. The lowering belongs to X_eTaL in the end (asks G1 and G2).

One program, three executions

                X_eTaL program (.xtl)
                        |
          +-------------+-------------+
          v             v             v
      evaluator    XIR interpreter   OpenCL on a GPU
          |             |             |
          +-------------+-------------+
                        v
                  the same arrays

Read the code

Documentation

Every library, example program and the GPU facade: doc comments, examples that run, the source drawn decorated, every name linked to its definition and uses.

Browse the docs

Accel

The acceleratable subset of X_eTaL as a library: elementwise arithmetic, masks, reductions, products, transposes (attention scores, a weight gradient), a dense layer, a softmax. Each export is one array expression.

Accel's reference

The gpu extension

X_eTaL programs that call the GPU themselves, through X_eTaL-extensions' native ABI and its xetal-x bridge; and gp:a_ccel<, the macro that hands a function's text to the runner.

The macro Gpu's reference

In X_eTaL

The acceptance pipeline, as Accel writes it

ˡp̲ipeline ← { x w → ˡs̲um ˡr̲elu x + x × w }

A layer of a network

ˡd̲ense ← { x wb → (x '+ '× i̲nner -1 d̲rop wb) + (o̲ffsets t̲ally x) 'r̲ight t̲able r̲avel -1 t̲ake wb }

The same product on the GPU, from X_eTaL

c ← a ᵍᵖp̲roduct a

The macro, expanded

The framework: a macro hands a function's text to a runner. In accelerate.xtl each accelerated function is one definition, written as any X_eTaL function; below each, what xetal expand makes of it (generated here from the pinned xetal-x, the expansion the runner sees). Read the expansion from the right, as X_eTaL evaluates: the text goes to the runner with the calling file and the arguments' kinds, the arguments are bound, the program runs on the device, the result is read back; gp:a_fter returns its left after its right. The runner lowers the text for the arguments' shapes when they are bound and keeps the session. The macro's page.

ᵘl̲ayer ← "float float" ᵍᵖa̲ccel< "{ x wb -> ac:r_elu x ac:d_ense wb }"
u:l_ayer := ({ x wb -> gp:o_utput 1 gp:a_fter gp:r_un 0 gp:a_fter 2 gp:b_ind wb gp:a_fter 1 gp:b_ind x gp:a_fter "{ x wb -> ac:r_elu x ac:d_ense wb }" gp:l_ower "extensions/gpu/demos/accelerate.xtl|float float" })
ᵘa̲ttend ← "float float" ᵍᵖa̲ccel< "{ q k -> ac:s_oftmax q ac:s_cores k }"
u:a_ttend := ({ q k -> gp:o_utput 1 gp:a_fter gp:r_un 0 gp:a_fter 2 gp:b_ind k gp:a_fter 1 gp:b_ind q gp:a_fter "{ q k -> ac:s_oftmax q ac:s_cores k }" gp:l_ower "extensions/gpu/demos/accelerate.xtl|float float" })
ᵘe̲mbed ← "float int" ᵍᵖa̲ccel< "{ t ids -> t ac:e_mbed ids }"
u:e_mbed := ({ t ids -> gp:o_utput 1 gp:a_fter gp:r_un 0 gp:a_fter 2 gp:b_ind ids gp:a_fter 1 gp:b_ind t gp:a_fter "{ t ids -> t ac:e_mbed ids }" gp:l_ower "extensions/gpu/demos/accelerate.xtl|float int" })

Measured

One X_eTaL program, offload.xtl, on two GPUs so far: an Apple M1 Max (OpenCL 1.2, this Mac) and an RTX 5060 Ti (16 GB, an Arch Linux machine). Each GPU is compared with the evaluator on its own host, not with the other card. The GPU side includes the bridge, which carries arrays as text.

WorkEvaluator on the MacApple M1 MaxEvaluator on the Arch hostRTX 5060 Ti
512 by 512 product14545 ms462 ms (31 times faster)24994 ms979 ms (25 times faster)
a million items, elementwise, summed188 ms2447 ms (13 times slower)254 ms1440 ms (5.7 times slower)

Products gain even through the bridge; elementwise work does not. Why, and which macros and extensions are justified: the analysis. X_eTaL-ML's benchmarks and its world model, the device's time and the bridge's apart: on the M1 Max docs/ml-results.md, on the RTX 5060 Ti docs/rtx5060-ml-results.md and its hardware report.

More

The plan

Architecture decisions, the hardware, the sagas done and to come: products, models, then each card.

docs/plan.md

Asks for X_eTaL

What this needs from the language: an accelerator IR and a lowering to it, static shapes, a native hook with binary arrays.

docs/xetal-asks.md

Source

The IR, the OpenCL emitter, the runtime, the tool, the extension, the tests.

GitHub