← Home

Mnemo

A compiler from a subset of C to Kairos: your C program runs forwards and backwards.

What Mnemo is

Mnemo compiles C to Kairos, a reversible concurrent language. C destroys information all the time: x = 5 loses the old value of x. Mnemo saves every overwritten value on a history stack, so the whole run stays invertible. The output is plain Kairos with no VM extensions. On programs in the supported subset, Mnemo aims for the same output and exit code as gcc.

#include <stdio.h>
int sq(int x) { return x * x; }
int main(void) {
    int a[4] = {1, 2, 3, 4};
    int s = 0;
    for (int i = 0; i < 4; i++) s += sq(a[i]);
    printf("%d\n", s);          /* 30 */
    return 0;
}

You can compile and run C in this page: Mnemo, the Kairos frontend and the Kairos VM run in your browser.

How it works

prog.c ─ gcc -E -DMNEMO ─ pycparser ─▶ AST
      ─ rewrites (early returns, switch, static, stdlib…)
      ─ layout: one memory cell per variable, array, field
      ─ lowering: reversible assignments, history, if/from
      ─ cells → Kairos array __mn_mem
      ─ library procedures (printing, bits, division…)
      ─ emit .kairos ─▶ Kairos VM

Reversibility

Every assignment becomes push(x, __mn_hist); x += 5: the old value goes onto the history stack, and running backwards pops it again. C control flow becomes Kairos if … fi and from … until with the exit assertions the inverse needs. The cost is code size: the eight-line example above becomes about 1,200 lines of Kairos. The playground shows the generated code for every program you run.

Memory

All named state (scalars, arrays, structs, globals) and the first part of the malloc heap live in one Kairos array, __mn_mem, and a pointer is an index into it. Kairos arrays cannot grow, so past the end of that array the heap continues on a tape made of two Kairos stacks. free only reuses the most recently allocated block.

--opt-uncall-user-calls

The history grows with every assignment. With this option, after call f(…) Mnemo saves the cells f wrote, runs uncall f to empty the history f produced, and puts the results back with an XOR swap. The result is the same and long programs use much less memory. Recursive functions, functions with channels or par, and some pointer writes are excluded.

The C subset

AreaSupported
Typesint, unsigned, char, bool, short/long/long long (as int), size_t, int*_t/uint*_t, enum, struct, union, typedef. No floating point.
Pointersvoid *, multi-level pointers, arithmetic, &x, &s.field, &a[i], malloc/calloc/free
Arraysmultidimensional, initialisers (designated too), run-time indices. No VLAs.
Control flowif, switch, while, do, for, break, continue, return anywhere, ternary, short-circuit &&/||. No goto or setjmp.
Functionsrecursion (mutual too), structs by value, function pointers. No user-defined variadic functions.
stdio.hprintf (%d %i %u %x %X %o %c %s %p, width, flags), putchar, puts
string.hstrlen, strcmp, strcpy, strcat, memcpy, memset, memmove, strdup and more

The README has the complete list, including stdlib.h, strings.h and stdarg.h.

Parallelism

mnemo_pthread_parallel2(f, g) with two different functions becomes a Kairos par block running two real threads. The branches share no writable memory, so a global written by one branch and used by the other is a compile error. Branches communicate through Kairos channels (mnemo_kairos_channel_t with ssend/srecv), including channel passing.

try / rollback

Mnemo adds Kairos's try to C:

try (x < 10) {
    x += step;           /* runs forwards */
} rollback {
    attempts++;          /* if the condition is false: the body is undone, then this runs */
}

Try it

Pick an example, edit it if you like, and press Run. The first run downloads the Python runtime that hosts Mnemo (about 10 MB), so it takes a few seconds. Start from Blank to write your own program. Under the output you get the exit code of main and how many VM cells the run kept alive: at the end, on average and at the peak. Turn on --opt-uncall-user-calls to watch those numbers drop. If main takes argc, a field appears to set it.

Download file Tab indents · Esc, Tab leaves · Ctrl+Enter runs
Output appears here.

More programs are in tests/c/. make test-gcc-compat runs 190 of them and checks that the output and exit code match gcc.

Known differences from gcc

Install locally

Mnemo needs Kairos, which provides the VM, and gcc, which it uses as the preprocessor. One line installs both, Kairos first if it is missing, and asks for the sudo password:

curl -fsSL https://github.com/nicologiuliani6/mnemo/releases/latest/download/install.sh | bash

Or install the packages from the releases by hand:

DistributionInstall
Debian / Ubuntusudo apt install ./kairos_<version>_amd64.deb ./mnemo_<version>_amd64.deb
Fedora / RHELsudo dnf install ./kairos-<version>-1.<dist>.x86_64.rpm ./mnemo-<version>-1.<dist>.x86_64.rpm
Arch Linuxsudo pacman -U ./kairos-<version>-1-x86_64.pkg.tar.zst ./mnemo-<version>-1-x86_64.pkg.tar.zst

From source

Clone Kairos next to Mnemo (or set KAIROS_ROOT=/path) and build it:

git clone https://github.com/nicologiuliani6/kairos.git
git clone https://github.com/nicologiuliani6/mnemo.git
(cd kairos && make install-deps && make)
cd mnemo && make venv          # .venv + pip install -e .

Each release also ships a wheel: pip install mnemo-<version>-py3-none-any.whl.

Usage

mnemo prog.c [options]                           # compile to Kairos and run
mnemo dump-kairos prog.c [-o out.kairos] [--stdout]  # write the generated Kairos
mnemo compile prog.c [-o exe] [--keep-kairos]     # native executable: bytecode + libvm.so

mnemo prog.c prints the program's output and exits with the value returned by main.

OptionEffect
--check-invertibilityruns main, then inverts it; the VM reports every step that cannot be undone
--opt-uncall-user-callsafter each eligible call, frees the history it produced
--autodecides by itself whether to enable the option above
--main-argc Nvalue of argc (also set with a // mnemo-main-argc: N line in the source)
--vm-dump, --vm-statsprint the final VM dump / how many cells are still alive
--kairos PATHKairos executable to use
-vprint commands and exit codes on stderr

Questions

Open an issue on the repository, or email me@nicologiuliani.site.