Whenever you compile using Rust, the compiler goes through different passes and in the end, generated binary code for the target processor. By default, it uses LLVM as backend to generate the binary code, but more backends exist like cranelift and GCC. This post is about how it鈥檚 possible for one compiler to use different backend to generate binaries, in particular GCC.
Passes
Before going into details, we need to describe how compilers actually work. They read source code and convert it internally into a format they can manipulate, commonly called Abstract Syntax Tree (shortened "AST").
However, compilers go through multiple passes, and often each pass has their own AST. Let鈥檚 take a short and very incomplete example with the Rust compiler passes. We have 4 steps (again, this is simplified!):
- AST: checks that the syntax is valid
- HIR: checks if types are valid
- MIR: checks lifetimes and runs borrow-checker
- codegen: generate binary code (which also has multiple steps, but not detailed here)
Each step generates a new AST with new information if no error was encountered and provides it to the next pass.
Little side-note: If enough people are interested by this topic, I can write a (much) longer explanation of these passes.
Backend vs front-end
So now that we have a high-level idea of Rust compiler passes, what is the difference between "front-end" and "back-end" exactly?
We consider the front-end to be the part handling (high-level non-exhaustive list) code parsing, linting, type-checking and borrow-checking (steps 1 to 3). When all this is done, it means the code is valid and needs to be translated to the target processor instructions set. To do so, we call LLVM/GCC which will translate the Rust compiler AST into assembly code (step 4).
The Rust compiler backends are the bridge between the Rust compiler AST and the actual code generator. They receive the AST and call the LLVM/GCC/... API which will in turn run their passes, optimize and finally generate the assembly code.
Why having a GCC backend
LLVM being much more recent than GCC (2003 vs 1987), a lot of older processors are not supported and will never be. So if you want to write a Rust programming on an old platform like Dreamcast, you have no choice to either write your own backend or use the GCC backend (or the gccrs front-end once ready).
For the readers interested in doing so, there is a guide explaining how to build Rust programs for Dreamcast here.
gccrs vs GCC backend
The GCC backend is different than gccrs which is a front-end for GCC written in C++, which doesn鈥檛 reuse the front-end of rustc, meaning they need to reimplement parsing, type-checking, linting, borrow-checking, compilation errors, etc.