[SAOC 2026] DMD CTFE Performance Update #2

Abul Hossain Khan abulkhan19175 at gmail.com
Tue Oct 6 13:50:14 UTC 2026


Hi everyone,

Last time I went through the CTFE entrypoints and benchmarked 
Dennis's linear memory prototype. After that we had a call and 
decided to first measure how CTFE really behaves on real code. So 
that's what I did.

#### Probing

The interface we want is "here is a function, it's complete, run 
it, give me the result". What breaks that is semantic analysis 
getting triggered in the middle of CTFE. To see how much that 
happens I put a counter in `ctfeInterpret` and hooks in the 
semantic functions, each hit saves a backtrace. Also counted 
which `EXP` kinds go in and come out. Ran it on the test suite, 
the Phobos build and every Phobos module with `-unittest`.

- Semantic does run inside CTFE, in about 1% of the calls. Only 5 
different paths lead there, and really just one of them matters, 
calling a function whose body isn't analysed yet, mostly 
functions from imported modules.
- ~85% of `ctfeInterpret` calls return the input untouched, it's 
just simple constant folding.
- Out of 124 `EXP` kinds, 49 go in, 80 get evaluated inside and 
only 20 come out.
- The result is complete, the compiler doesn't have to analyse it 
again.

The lists and a minimal test for each of the 5 paths are here - 
https://gist.github.com/abulgit/43f640a032c95557de959f7120d4fd69


#### Doing the semantic upfront

I added a pre-pass that walks every function body the call can 
reach and analyses it first.

| | Normal | with pre-pass |
|---|--:|--:|
| semantic inside CTFE, test suite | 10,008 | 11 |
| semantic inside CTFE, Phobos unittests | 17,711 | 88 |
| failing tests if semantic inside CTFE is an error | 732 | 13 |

So it works, the only thing left is virtual calls, where the 
override that runs isn't known before. 11 tests fail with the 
pre-pass but it's only a different line after an error.

But it also breaks valid code that isn't in the test suite. Like 
a const that is read in a branch which isn't taken while that 
const is computed, or a function from an imported module that 
never runs but gives an error with `-de` or `-betterC`.

#### What's next

- Will try the other way, where the engine asks for semantic 
through a callback, and compare the two.
- Also add a small code example for every expression kind in the 
gist, and see if the list can be made smaller.
- Add a CTFE heavy workload to the perf bot.

If you have code where CTFE is slow or eats a lot of memory, 
please share it here. A small self contained file is best, but a 
dub package works too.

Thanks to Dennis for mentoring this. As always, feel free to 
leave any feedback or suggestions!



More information about the Digitalmars-d mailing list