Experiment, updated 1 November 2026
Bend to Odin
This project translates programs from a new language, Bend, into Odin, a simple language with direct control of memory. The goal is the same answers at the same speed or better.
- The idea
- The race
- One core against C
- Memory without a cleaner
- Three languages
- What we learned
- Right answers
- What comes next
The idea
Bend lets a programmer write down what a program must do, then have the computer prove that the program does it. That is very useful when an AI writes the code, because you do not have to trust the AI. Few teams use Bend today. This project gives those proofs to teams that use Odin.
Bend normally turns programs into C. It can also run them on a graphics card. So Odin has to compete with the best of both.
A processor is like a few expert chefs. A graphics card is like thousands of helpers who are fast only when they all do the same step together. Some jobs suit the chefs. Other jobs suit the helpers. The score below always compares with the faster of C on the processor and C on the graphics card.
Odin has no cleaner that stops the program to free memory. This suits Bend programs, which make millions of small objects. The translator cannot use the graphics card yet, so programs that suit the card are behind. That work is in progress.
The race, program by program
Each row is one test program. Further left is faster, and the scale is logarithmic because the times differ by up to 30 times. The ring shows the best C time. The filled dot shows Odin. Hover over a row to see all the times.
Odin and C on the processor ran in turn, with a 3-second rest. Each time is the best of 2 runs. C on the card comes from the Go table run just before. Odin uses the processor only. Bitonic is very close. Another job used up to 2 threads.
See all the times as a table
| Program | C 1 | Odin 1 | Odin 2 | C 2 | C card |
|---|---|---|---|---|---|
| bfs | 0.59 | 0.69 | 0.65 | 0.66 | 0.65 |
| editdist | 0.48 | 0.33 | 0.34 | 0.45 | 0.40 |
| gameoflife | 2.09 | 2.24 | 2.22 | 2.14 | 0.22 |
| hashmap | 0.51 | 0.18 | 0.20 | 0.50 | 0.73 |
| kmeans | 1.29 | 0.69 | 0.66 | 1.28 | 0.58 |
| lexer | 0.55 | 0.49 | 0.43 | 0.52 | 1.25 |
| mandelbrot | 0.55 | 0.54 | 0.56 | 0.56 | 0.19 |
| merkle | 0.62 | 0.66 | 0.68 | 0.63 | 0.20 |
| nbody | 0.56 | 0.63 | 0.65 | 0.56 | 0.20 |
| queens | 1.54 | 1.38 | 1.29 | 1.75 | 1.46 |
| raytrace | 1.24 | 1.27 | 1.40 | 1.20 | 1.20 |
| symreg | 0.51 | 0.33 | 0.42 | 0.57 | 0.51 |
| terrain | 0.47 | 0.52 | 0.52 | 0.47 | 0.36 |
| bitonic | 2.61 | 1.61 | 1.54 | 2.74 | 1.56 |
| matmul | 0.76 | 0.29 | 0.26 | 0.78 | 0.53 |
| radix | 1.02 | 0.57 | 0.57 | 1.01 | 0.71 |
One core against C
A fair test of the translated code removes parallel work and the card. On one processor core, Odin uses fewer cycles than Bend's C on 13 of 16 programs. On merkle, raytrace and terrain, the difference is 1.5% or less, which is inside the noise.
Under 100% means that Odin uses less work than C. Billions of user cycles on an Intel i7-10700.
Memory without a cleaner
Each worker takes boxes from its own tray of memory. This needs no lock. When nothing else can read a box, the program gives it back for the next use.
Odin normally passes a hidden context with an allocator to each function. On our test, that path was 7.6 times slower than a private tray, so generated code turns it off.
One thread. The standard path makes an indirect call and clears memory for each node.
The translator splits work into a tree of tasks, as in the diagram.
Three languages, side by side
Each cell shows how a language compares with the best C time for that program. Blue is faster than C. Red is slower. A plain number means times faster, and a minus sign means times slower. Go uses the graphics card where the translator can. Zig and Odin use the processor only so far.
Each lane uses the best C time from its own run. C on the graphics card comes from the Go run for Zig and Odin. Another job used up to 2 threads during these runs.
What we learned
Many numbers at once
The translator can rewrite a suitable loop to process 8 numbers in one step. So far this applies to kmeans only. It cut that program from 24.2 to about 18 billion cycles. The program then needs a processor with AVX2.
Flags that did not help
The most aggressive optimizer setting gave no gain. Tuning for the exact processor made nbody 12% slower.
A bug for everyone
Bend's compiler lost a mark that says a value has more than one reader. Hashmap hung until we kept the mark. The same bug gave wrong answers in Go, and that bug is now fixed there too.
Odd characters work
The Go version stops on characters outside Unicode. Odin keeps any 32-bit character. These tests pass here.
Does it give the right answers?
396 more programs are refused because they are outside what the translator supports.
- 653 of 653 supported test programs pass on the translator from the first stage of this work. 396 others are refused because they are outside what the translator supports.
- 1107 of 1107 test libraries pass, with 197 law checks. 1029 passed in one full run. The other 78 passed after a fix, and the 1029 did not run again after that fix.
A law check is a rule that the code must obey. We broke a function on purpose to prove that a law check can fail.
What comes next
- Graphics card support. Mandelbrot, nbody, gameoflife, merkle and terrain need it. Work has started.
- A better work queue. The queue has one lock and no work stealing.
- More SIMD. Bfs and raytrace are close enough for this to matter.
Honest limits
- The project is an experiment. The work is not published.
- We have one run on all cores so far, with another job on the machine.
- We have not tested on ARM.
- We check the translation with tests. We do not have a mathematical proof that the Odin matches the Bend.
Words used on this page
- Processor (CPU)
- The main chip in a computer. It has a few powerful workers.
- Graphics card, or card (GPU)
- A chip with thousands of simple workers.
- Thread
- One worker on the processor. This processor has 8 cores and 16 threads.
- Cleaner (garbage collector)
- The part of Go that finds and frees memory that a program no longer needs. Zig and Odin do not have one.
- Box and node
- A small piece of memory that holds part of a tree.
- Cache miss
- A read of data that is not near the processor. It can take 100 times longer than a read of nearby data.
- Law check
- A rule from the Bend program that the translated code must obey.