A compiler tuned to your project, not to the average of all programs.
General-purpose compilers optimise for every program at once — which means for none of them in particular. evolve works out which transformations are correct for your code on your target, tunes them against real measurements on that hardware, and freezes the result into a compiler you run offline.
You do not have to read any of this to use it. One command installs it and connects it to the agent you already work with; this page is for when you want to know what it is doing.
It may only use what is safe for all of them at once.
One program, one target — the whole area is open.
Your program is not the average program.
A general compiler has one set of heuristics for every program anyone will ever write, on every machine they will ever run it on. It can only apply what is safe across all of them at once, and it cannot measure your code on your part, because it has never seen either.
What that leaves behind is the structure specific to your workload: the shapes your data actually takes, the operations your target actually has, the sizes your loops actually run. A compiler that knew those could commit where a general one must keep hedging.
Designed against your code, checked, measured, then frozen.
A compiler is designed by the agent you already work with, against a C program you point it at. What comes out the far end is a binary.
- 01 proposed Rewrites are proposed. Every one is a guess until it is checked. 12 marks
- 02 proved What survives its obligations. Anything that cannot be discharged is dropped. 7 marks
- 03 faster What also measured faster on the part you ship. Correct is not the same as faster. 4 marks
- 04 admitted What enters the library as a pass, with its preconditions attached. 2 marks
- 05 one compiler The admitted set, frozen with its tuned parameters. It runs offline. one
Your agent, your program
You connect evolve to the agent you already code with, over MCP, and point it at a C program you already have — real code rather than a description of it. What comes back is a measurement against your own host's baseline compilers at their standard optimisation levels, not a model's opinion: no agent, no search and no model anywhere on that path.
- input
- one C program you point it at, and the target you build for
- driven by
- the coding agent you already use, over MCP
- today
- a narrow family of programs; anything outside it is refused rather than attempted
- needs
- an account
Correct before it is fast
A candidate arrives carrying the preconditions it assumes and the equivalence it claims. Those are discharged mechanically against what the function actually reads, writes and does, at the scope the rewrite applies to. Anything that cannot be discharged is refused, and the reason is kept — a rejection is a record rather than a shrug.
What ends up on your machine carries the matcher, not the prover.
- checks
- preconditions, and the equivalence claimed
- scope
- the region the rewrite applies to
- on failure
- refused, with the reason kept
On the part you actually ship
Candidates that survive are compiled and timed on the target you build for, interleaved against your ordinary build so both arms meet the same machine in the same state. Floating-point behaviour is held to the strict setting on both arms, and the difference against the baseline is checked against a stated tolerance — evidence about this run, never a proof.
If the measured result does not beat your default compiler, the baseline is what ships.
- measured on
- the target you build for
- compared against
- your ordinary build, interleaved
- if it is not faster
- the baseline ships
A compiler, not a service
What survives is pinned: a frozen, versioned composition together with the parameters that were measured for it. For a given version, identical input gives identical output, and it needs nothing from us to run — no account, no lookup, no network.
That also means it is a thing you can hand to someone else. It was tuned for one program, so how much of the advantage survives depends on how close theirs is to yours.
- form
- a versioned binary, with its tuned parameters
- determinism
- same input, same output, per version
- to run it
- nothing from us
The command your build calls
evocc is what a build system calls in place of gcc;
evolve manages your projects and the compilers on this machine. A build
whose compiler changed with nothing on screen saying so is the failure this product
exists to avoid — so invoking it, including under a compiler's name, resolves a
.evolve/ folder in your project that names which compiler to use, and it
stops if that folder is not there. The choice lives in your repository, where it can be
read and reviewed, rather than in your PATH.
curl -fsSL --proto '=https' --proto-redir '=https' https://api.evocompiler.com/install.sh | sh
Click the line to select all of it · ⌘C to copy. Tap and hold the line to select it, then choose Copy.
- the compiler command
- evocc
- the management command
- evolve
- what selects the compiler
- a .evolve/ folder in your project, not your PATH
Why measure instead of assume
On one worked example a hand-set parameter measured 3.13× where the searched one measured 9.77× on the same hardware. That is one example, measured on real hardware, not proof-backed, and not a promise about your code. It is the argument for measuring rather than assuming, and nothing more than that.
One small program, four times over.
The same small function as source, as an intermediate form, after the rewrites that survived, and as instructions for one part. Beside it, the record of what each rewrite had to hold and what could not be discharged. Nothing here was produced by a compiler, and every pane says so on its own header.
/* Add up n bytes. This says what, and nothing about how. */
#include <stddef.h>
#include <stdint.h>
uint32_t sum_bytes(const uint8_t *restrict p, size_t n)
{
uint32_t acc = 0;
for (size_t i = 0; i < n; ++i)
acc += p[i];
return acc;
}
region @sum_bytes {
facts
shapes p:[n] bytes n is known only at run time
aliasing p is not written here -- from restrict and const
numerics uint32 accumulator wraparound is defined
effects reads p[0..n), writes nothing
contract p addresses n readable bytes -- the caller's promise
reduce %acc = sum_i ( zext32( p[i] ) )
return %acc
hot the i-loop: n iterations, one byte each
}
region @sum_bytes.tgt {
peel i until p + i is 4-byte aligned
held: the peel establishes the alignment rather than
assuming it, and it runs at most 3 times
widen the aligned body loads 4 bytes at once
held: every byte it reads is inside p[0..n)
split %acc into four partial sums, added at the end
held: uint32 addition wraps, so regrouping returns
the same value for every input
guard tail of 0..3 bytes, added one at a time, kept
not admitted for this target:
read past the end to finish the last word
-- reads outside the object; the page after p may not exist
hoist the n == 0 test out of the loop
-- n == 0 is reachable, and the answer there is 0
}
@ hand-written for this page; not emitted by any compiler
@ target: armv7e-m, DSP extension present
@ on entry p is 4-byte aligned and r3 holds the number of
@ whole words; the peel above established both.
movs r5, #0 @ zero, for the byte differences
.Lword:
ldr r4, [r0], #4 @ four bytes at once
usada8 r2, r4, r5, r2 @ r2 += b0 + b1 + b2 + b3
subs r3, r3, #1
bne .Lword
@ tail: 0..3 bytes, still added one at a time
@ without the DSP extension this lowers to four widening adds
- loop order
- as written, one iteration at a time
- loads
- one byte per iteration
- alignment
- none assumed, because none is known
- trip count
- not known until the call happens
- rewrite
- peel, widen, split, guard the tail
- assumes
- p is readable across the whole of p[0..n)
- assumes
- uint32 addition wraps
- Held
- the value returned, for every n including 0
- Held
- nothing outside p[0..n) is read
- Held
- every load lies inside p[0..n)
- Held
- alignment is established by the peel, not assumed
- Held
- regrouping returns the same value, since uint32 addition wraps
- Held
- the 0..3 tail bytes are still added one at a time
- Held
- n == 0 is reachable, and the answer there is 0
- Not admitted
- read past the end to finish the last word
- Not admitted
- hoist the n == 0 test out of the loop
evocc's own, and no timing of any kind appears here. What each pane is
really showing is which rewrites were allowed and why the others were not.
Doing four bytes at once is not four times faster — what it is
worth is a question only measurement answers.
Designing needs us; using what you designed does not.
Everything expensive — the agent, the search, the proving, the runs on real hardware — happens on our side of a line. What crosses the line is a binary. After that your build is source, compiler, binary, and nothing else.
A drawing of how the two halves relate. It carries no measurement, no timing and no quantity of any kind.
Correctness is a question with several answers, and they are not the same one.
“It gives the same answer” is not one claim. These are the different things somebody can mean by it, and which of them this system makes.
| Technique | The question it answers | Where this system stands |
|---|---|---|
| A parser or a type checker | Is this program structurally valid and well typed? | Necessary, and it says nothing about whether two versions compute the same thing. |
| Tests run on both versions | Did both agree on the examples we actually executed? | This is what your own test suite does, and it is what the adapter you write runs on every trial. Evidence, not a proof. |
| A bounded check | Can a difference exist inside this explicit model, up to these sizes? | This is what the free proposal checker does. It is the strongest claim here and it is still bounded. |
| Universal equivalence | Is this rewrite equivalent for every input it could ever be given? | Not what a bounded result says, and we do not present one as if it were. |
| A verified compiler | Does a proof cover the compiler itself and every transformation it makes? | Not what this system claims. |
What you designed is yours to run.
A compiler you have saved runs on your own machine with no account, no lookup and no network. Designing needs us; using what you designed does not.
Install Evo · The commands, written out · What your agent reads