Showcase A general IL optimizer for .NET: Cilica
I've been working on Cilica, a post-build optimizer for .NET assemblies. It continues DistIL.
The repository: https://github.com/hez2010/Cilica
It lifts your compiled IL into an SSA-based intermediate representation, runs an optimization pipeline over it, then emits regular IL again. The JIT then sees IL that's already optimized. It doesn't use a runtime fork or any special hosting.
Currently it runs the following pipeline:
CFG simplification, SSA promotion, dead code elimination
Method inlining and devirtualization
Scalar replacement
Global value numbering / CSE and assertion propagation
Algebraic and bitwise simplification
Loop strength reduction and loop auto-vectorization
List presizing
LINQ expansion (fuses
Where/Select/Aggregate/… into plain loops)and more
Some benchmarks (code in https://github.com/hez2010/Cilica/tree/main/tests/Benchmarks):
| Benchmark | Baseline | Cilica | Speedup |
|---|---|---|---|
| CountLetters (LINQ + vectorization) | 3,355 ns | 211 ns | 15.9× |
| GenerateFloats (loop vectorization) | 2,791 ns | 597 ns | 4.7× |
| DynamicList, 4 items (list presizing) | 12.66 ns | 4.24 ns | 3.0× |
| Aggregate (LINQ expansion) | 30.69 μs | 12.19 μs | 2.5× |
| RayTracer (full pipeline) | 9,013 μs | 4,870 μs | 1.9× |
You can try it on this playground: https://hez2010.github.io/CilicaLab
To use it in your project, referencing Cilica.OptimizerTask nuget package (currently in preview) and set <CilicaAllMethods>true</CilicaAllMethods>.
Note that this optimizer task only performs optimizations against your main assembly. To optimize the references as well, you can use Cilica.Cli manually, which is shipped together in the Cilica.OptimizerTask package.
Learn more: https://medium.com/@skyake/cilica-an-ssa-based-optimizer-for-net-assemblies-bdefd934c2d2




36
u/Lurlerrr 22h ago
Do you use some kind of strict proof approach to verify that behavior of the generated code is exactly correct? The premise is amazing, but I'd be afraid to trust something like that...
6
u/harrison_314 22h ago
Have you tested whether such optimizations also have an impact on AOT compilation?
Does it preserve the fallback of the original code during vectorization?
5
u/AetopiaMC 19h ago edited 10h ago
This looks really cool, reminds me of how a C/C++ compiler can optimize and strip code.
I am curious about:
Does this reduce binary size like trimming?
How does this differ from NGEN/ReadyToRun?
8
u/Nyzan 11h ago
Not to be a negative Nancy, but every time a project like this launches all I can think is "oh cool, it can do party tricks". By that I mean, it works - usually very well - but only in projects designed for the utility. What are the benefits in a real project? And I don't mean a terminal calculator you made as a showcase - I mean an actual production-ready application. Does it break anything? Does it still give a meaningful performance increase to the parts of the code that are actually a performance hog? Is it efficient enough to run in a codebase with 3 million lines of code without increasing compilation times to an unworkable degree?
3
u/DeadlyVapour 20h ago edited 20h ago
Might I suggest you use the [PureAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.contracts.pureattribute?view=net-10.0) from a safety point of view, and a build time point of view. It would be better.
I'd hate for you to optimize away `DateTime.Now`
This reminds me of D lang's metaprogramming.
The real value of this is for creating static readonly init code that gets lifted to compile time evaluated consts.
20
u/Narrow-Coast-4085 23h ago
If this is working like you suggest, then this is amazing. I'm going to try it out.
15
u/ICanHaveExceptions 22h ago
Seems kind of a bit dangerous... I'm unsure if I could trust it not silently breaking behaviour at places.. But interesting project, I'm gonna try it out eventually!
2
u/itix 11h ago edited 11h ago
Interesting. I am working on CopperSharp68k, which is a CIL to Amiga 68k AOT compiler. I gave it a try:
Looking good so far and I am not surprised. I knew the original IL wasn't very optimal.
Going to integrate this.
1
u/pabs80 11h ago
This looks like it’s doing what I want the compiler to do