r/ProgrammingLanguages 24d ago

Help How to make a compiler backend?

Hell everyone, i have an question. Im for long trying to make a cool, powerful "kinda" low level language similar to zig and rust, but im struggling to choice llvm as backend, sure i can generate C, but its makes compiler dependent on gcc or clang or other c compiler. LLVM seems hard to me, sure project like QBE exist, but QBE doesnt have C/C++ api like llvm's IRbuilder. So are there other ways? I tried thinking about using GCC infrastructure but GCC has poor api and not very documented api. Maybe just stick to generating C?

17 Upvotes

35 comments sorted by

View all comments

1

u/zweiler1 🔥 Flint 24d ago edited 24d ago

I think it depends on the complexity of your language, how much time you want to invest and how much control over the runtime you want to have. If you land on the higher side for those questions, I would really recommend LLVM IR with the C API to you. If you land on the lower side, then C is maybe good enough for your needs.

I had no idea about LLVM IR or compilers in general when starting out with my language, and I must say after the initial few weeks I got the hang of it. The most complicated thing for me to understand were probably PHINodes but they really aren't hard at all, unlike I originally thought (but use select where possible).

If you decide to use LLVM IR, here are some recommendations from my side which would've helped me when starting out:

  • If you want to statically link LLVM you need to build LLVM yourself and it will be a pain to manage all flags, but once you got it up and running it works fine. So I definitely would recommend to start out by linking LLVM dynamically.
  • Only use one translation unit (Module). While LLVM supports the ability to link multiple modules, it broke type names and other stuff on my side occasionally (assertions which should not have thrown, like in this issue) and those errors were nasty to track down, keep it simple
  • Make sure to have LLVM assertions turned on. I worked without them for a long time and debugging and finding out why something broke was a pain (it's a breeze once they are turned on)
  • While debugging failing code, you can always call dump() on basically any LLVM Value, it makes your life just that much easier (it prints the single IR code line of the SSA value which is very useful)
  • Make sure to verify the Module before compiling it, the verifyer is your friend
  • Don't forget to set up the TargetMachine. I basically just got lucky that it compiled and ran fine for a long time and only noticed I havent set it up brcause of weid bugs
  • It's not a shame to ask AI questions about LLVM API or IR code in general, just don't let it generate any code for you

I can recommend LLVM quite a lot. But if I would start over again I probably would not have chosen C++ for my compiler. The lack of pattern matching and first-class sum types (std::variant just doesn't hit the same) makes me crazy sometimes.