# What materials should I read extending the compiler?

**URL:** <https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841>\
**Category:** General Usage\
**Created:** [November 28, 2023, 12:16pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841 "2023-11-28T12:16:48Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tarny\_GG\_Channie](https://avatars.discourse-cdn.com/v4/letter/t/3bc359/32.png) [@Tarny\_GG\_Channie](https://discourse.julialang.org/u/Tarny_GG_Channie)\
**Post date:** [November 28, 2023, 12:16pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/1 "2023-11-28T12:16:48Z")

</div>

I have some knowledge of metaprogramming from my last package. Now, I need to descend into madness, to figure out how the compiler works and how I can access and modify the working of each stage in the pipeline.

Implementing a performant attribute system in a moddable game requires taking some optimizations not found in typical Julia compilation. For example, if there is a union of 5 types, the Julia compiler might resolve to ANY and let the runtime do the work. However, that’s not suitable for some use cases. I might need it to use 3 bits for type, 64 bits for data, and do some bit tricks to optimize away dynamic dispatches and such. I would need to play with the compiler. What resource should I read.

---

<div class="post-metadata">

**Author:** ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)\
**Post date:** [November 28, 2023, 12:30pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/2 "2023-11-28T12:30:40Z")

</div>

What you describe is not too much of the scope of typical Julia performance optimization. But using 3-bits for the type and 64-bits for the data is far from the proper solution for such problems, as the level you indicate deals much rather with good usage of caches and SIMD & Co type of optimizations. You could for example look at the packages and pointers here: [Optimizing your code (modernjuliaworkflows.github.io)](https://modernjuliaworkflows.github.io/pages/optimizing/optimizing/)

I would suggest revisiting the `@code_*` commands and then try to identify precisely what kind of optimization you need. Looking at different outputs will also teach you how the compiler works.

If you are interested, you could try to learn from some HPC/Game programming courses information that might be focused on `C/C++` but can help you to understand and write good Julia code as well. I doubt that at this point a modification of the compiler itself is necessary.

---

<div class="post-metadata">

**Author:** ![Tarny\_GG\_Channie](https://avatars.discourse-cdn.com/v4/letter/t/3bc359/32.png) [@Tarny\_GG\_Channie](https://discourse.julialang.org/u/Tarny_GG_Channie)\
**Post date:** [November 28, 2023, 12:37pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/3 "2023-11-28T12:37:02Z")

</div>

> [@SteffenPL](#):
>
> But using 3-bits for the type and 64-bits for the data is far from the proper solution for such problems,

I mean… Java performs virtual method table lookup, but that’s still far from an ideal way. I’m trying to optimize away virtual method lookup, dictionary lookup, etc… what do you mean by “not proper solution”?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 28, 2023, 1:24pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/4 "2023-11-28T13:24:15Z")

</div>

So, off the bat, I rather doubt that messing with the compiler internals is a good fit for what you’re describing here, e.g. your example of

> [@Tarny\_GG\_Channie](#):
>
> For example, if there is a union of 5 types, the Julia compiler might resolve to ANY and let the runtime do the work

is much more easily avoided by using union splitting, or using something like SumTypes.jl to enacpsulate the union and automate the splitting. Julia is a very powerful and flexible language, and most goals can be accomplished without compiler modifications. This is a bit like trying to learn to do a backflip while still learning to walk.

With that said, let me link to a few resources on the topic in case this ends up being useful to people whose use-cases _do_ involve working with compiler modifications.

The most user-friendly\[1\] thing here is to use [`@generated function`s](https://docs.julialang.org/en/v1/manual/metaprogramming/#Generated-functions) which are a powerful way you can specialize code generation based on the input types of a function. Generated functions also let you return a `CodeInfo` object instead of an `Expr` and this has super far reaching implications. The section on Cassette of this blogpost: [The Emergent Features of JuliaLang: Part I · Invenia Blog](https://invenia.github.io/blog/2019/10/30/julialang-features-part-1/) has a great explanation.

That leads naturally to the tools built on generated functions, namely Cassette.jl and IRTools.jl. Both of those have pretty good documentation pages I’d recommend reading. These tools are now kinda old-fashioned and frozen in time. They give some cool capabilities but have some fundamental limitations people are somewhat unhappy with.

Next we have the new generation of compiler plugins via the abstract interpreter mechanisms. This is the bleeding edge of compiler plugins, and there’s exciting stuff happening here, but it’s also constantly changing, and very unstable. Here be dragons. There are two big, stable-ish, and modern packages that take advantage of this mechanism for different purposes: Enzyme.jl and JET.jl. Most other newer or more experimental packages that use the abstract interpreter are developed by copy-pasting chunks of code from Enzyme.jl’s compiler passes and tweaking it until it works for their purposes. For example, StaticCompiler.jl and AllocCheck.jl were developed via liberal use of reverse engineered Enzyme code.

For these compiler plugings, there’s not really any pedagogical material, just existing code bases you can try to understand. One nice exception though would be a series of discourse posts by @Tomas_Pevny. I’d strongly recommend checking out this thread: [Materials about AbstractInterpreter](https://discourse.julialang.org/t/materials-about-abstractinterpreter/106442) and this thread: [Manual type inference of hand-written IRCode](https://discourse.julialang.org/t/manual-type-inference-of-hand-written-ircode/106356)

This information has a very short half-life though and will probably all be out of date in a matter of months, so there’s not going to be any useful pedagogical materials to learn from until it stabilizes.

* * *

* * *

1. note: I’m using “user friendly” in relative terms. Generated functions should probably be avoided if there’s a simpler way of accomplishing the same goal

---

<div class="post-metadata">

**Author:** ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)\
**Post date:** [November 28, 2023, 1:26pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/5 "2023-11-28T13:26:44Z")

</div>

In the mean time… @Mason gave you a nice reply 🙂 I just copy my text here in case it is interesting 😉

Data layouts should be multiples of `8-bits`, hence, if you add a `3-bit` field, it will either eat up additional `5-bits` in order to fit, or you need to create a specialized type, such as `BitVector`. (As @Mason added, something like SumTypes.jl could do the job.)

Anyway, I didn’t want to discourage you. From the little information I know, my advice would be to focus on foundations such as those found in good books on game programming in the language XY (doesn’t really matter, but probably C++ as that dominates game programming). In such a book, you will learn how in general the CPU works and compilers work and how to overcome such issues as dealing with heterogeneous data. Reading such a book will also improve your Julia skills and I think there is no Julia-specific book with such a scope. Of course, you can also learn by doing and try many examples and incrementally improve.

---

<div class="post-metadata">

**Author:** ![Tarny\_GG\_Channie](https://avatars.discourse-cdn.com/v4/letter/t/3bc359/32.png) [@Tarny\_GG\_Channie](https://discourse.julialang.org/u/Tarny_GG_Channie)\
**Post date:** [November 28, 2023, 1:47pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/6 "2023-11-28T13:47:09Z")

</div>

> [@Mason](#):
>
> So, off the bat, I rather doubt that messing with the compiler internals is a good fit for what you’re describing here, e.g. your example

Oh, I forgot… they can come from different mods. One mod might add 2 types of projectile and another mod adds 2 more types and suddenly there are five types of projectile and your core game code wouldn’t know in advance. I may’ve made the problem seem a bit easier than it actually is. Here’s what I meant.

Imagine a game. Now, one mod might add an armor system, and another mod might add an armor piercing on top of the previous mod. One mod might add unit shield and another might add unit morale. Suddenly, the unit struct you held suddenly need more space. And you want to make it as performant as if the armor system, morale system, etc… were hard-coded into the game.

I apologize for making the problem look too easy.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 28, 2023, 2:01pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/7 "2023-11-28T14:01:45Z")

</div>

This doesn’t change anything I said. I strongly recommend learning more about the regular tools available in the language for your purposes. Customizing the compilation pipeline is very unlikely to be what you need

---

<div class="post-metadata">

**Author:** ![Tarny\_GG\_Channie](https://avatars.discourse-cdn.com/v4/letter/t/3bc359/32.png) [@Tarny\_GG\_Channie](https://discourse.julialang.org/u/Tarny_GG_Channie)\
**Post date:** [November 28, 2023, 2:08pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/8 "2023-11-28T14:08:04Z")

</div>

Wait… I don’t actually need to mess with the compiler to do these things? Yay!

The last time I checked, however, Stellaris, a great game BTW, suffers from a massive lag problem because the engine is allowing mods and perhaps has its own mod compiler or interpreter in it, adding overhead. Some games use inheritance to deal with multiple object types, but virtual function calls use virtual method table, which is a performance loss.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [November 28, 2023, 2:29pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/9 "2023-11-28T14:29:28Z")

</div>

The canonical approach (which somewhat unironically is most widely championed in gamedev circles) is to use handles instead of pointers/objects.

In other words, your entities have an integer `id`, and then each extensible attribute is represented by an array like `extraFancyName::Vector{Symbol}`, and you access that not by `entity.extraFancyName` but instead via `extraFancyName[entity.id]`.

If you have multiple types of entities, and it is conceivable that these types get mixed, then don’t express that in the julia type system (dynamic dispatch BAD in inner loops); instead use some bits of your `id` for the entity-type.

This requires that you maintain global-ish control over entity lifetimes, and almost surely requires you to write dedicated code for batch updates. On the upside, this gives you de-facto arena allocation for all your relevant data, so you ideally produce minimal GC pressure.

This kind of approach works not just in C or C++ but also in julia and even in java (really! That’s my day job! This is not entirely idiomatic java code, but what can we do…).

---

<div class="post-metadata">

**Author:** ![Tarny\_GG\_Channie](https://avatars.discourse-cdn.com/v4/letter/t/3bc359/32.png) [@Tarny\_GG\_Channie](https://discourse.julialang.org/u/Tarny_GG_Channie)\
**Post date:** [November 28, 2023, 3:14pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/10 "2023-11-28T15:14:42Z")

</div>

Oh, that’s one nice way to do stuffs for sure. I think I explored multiple possibilities before.

Still, mods can usually run arbitrary logic in it and to be fast… well… issues.

And I’m quite self-taught on how to make games so I’m quite a bit clumsy.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [November 28, 2023, 4:01pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/11 "2023-11-28T16:01:09Z")

</div>

> [@Tarny\_GG\_Channie](#):
>
> Still, mods can usually run arbitrary logic in it and to be fast… well… issues.

I don’t think this is an issue that needs a lot of thinking. Just don’t follow fads that piss away cycles like there is no tomorrow. Look at what amazing things could be done with mods on half-life, i.e. the q2 engine, on late 90s technology (cf eg: counterstrike, natural selection, day of defeat).

> [@Tarny\_GG\_Channie](#):
>
> And I’m quite self-taught on how to make games

I have no clue on gamedev. But I somehow question your fixation on julia for that?

Like, I would understand if you e.g. discover your inner antifascist and want to improve the state of a training simulator / games for FPV pilots to help in the war effort, and want to use the recently linked [AerialVehicles.jl](https://help.juliahub.com/drone/dev/) as a major component. Sure, awesome! But that is no reason for the majority of your stuff to be written in julia.

The language is just a tool. Mix-and-match components you like from where ever you get them.

---

<div class="post-metadata">

**Author:** ![Tortar](https://avatars.discourse-cdn.com/v4/letter/t/6bbea6/32.png) [@Tortar](https://discourse.julialang.org/u/Tortar)\
**Post date:** [November 28, 2023, 5:18pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/12 "2023-11-28T17:18:20Z")

</div>

Ok, this could be very useful in Agents.jl for multi-agent models 😮

> <https://github.com/JuliaDynamics/Agents.jl/issues/841>
>
> It is known that Agents.jl suffers from dynamic dispatch when working with a hig…h number of agents types. I think that now that we have an abstract interface to rely on and to implement we can try to solve the issue. Currently, we just have some workarounds: representing every type in only one struct, but this is unnatural, and wastes some RAM (and it is probably not as performant as the possible implementation described below)
> 
> I tried to use \[Virtual.jl\](https://github.com/thautwarm/Virtual.jl) and \[ManualDispatch.jl\](https://github.com/jlapeyre/ManualDispatch.jl) and custom macros to solve the problem, but to no avail, even though the first package seems actually suited to improve the matter it didn't work well (performance was worse) when I tried to make use of it.
> 
> So I think we have only the hard way to move forward on the issue: implement all the interface for a model where the main data structure is \*\*a tuple where each type is inside its own Dict/Vector\*\*. This should be even better in terms of performance than compressing in only one struct different agent types without the need to change anything.

---

<div class="post-metadata">

**Author:** ![Tarny\_GG\_Channie](https://avatars.discourse-cdn.com/v4/letter/t/3bc359/32.png) [@Tarny\_GG\_Channie](https://discourse.julialang.org/u/Tarny_GG_Channie)\
**Post date:** [November 29, 2023, 12:54am UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/14 "2023-11-29T00:54:12Z")

</div>

> [@foobar\_lv2](#):
>
> I have no clue on gamedev. But I somehow question your fixation on julia for that?

I started out in pygame.  
Now…  
I have an option of going into c++ (pain)  
Or I could use Julia.  
So I decided, maybe Julia it is?  
And yeah… I’m like a blind monster crawling toward something.

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [November 29, 2023, 11:00am UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/15 "2023-11-29T11:00:44Z")

</div>

To give you a pointer that might be helpful: Learning about [Entity component systems](https://en.wikipedia.org/wiki/Entity_component_system). This seems to be the common way to design modular and extensible (like with mods and stuff) systems in gamedev. There are implementations in Julia like f.e. [`Overseer.jl`](https://github.com/louisponet/Overseer.jl). I’d recommend checking out the Readme of Overseer.jl for an example.

---

<div class="post-metadata">

**Author:** ![Tarny\_GG\_Channie](https://avatars.discourse-cdn.com/v4/letter/t/3bc359/32.png) [@Tarny\_GG\_Channie](https://discourse.julialang.org/u/Tarny_GG_Channie)\
**Post date:** [November 29, 2023, 1:09pm UTC](https://discourse.julialang.org/t/what-materials-should-i-read-extending-the-compiler/106841/16 "2023-11-29T13:09:21Z")

</div>

I actually made an ECS. It’s supposedly quite performant but… hard to use.
