Cinder is a work-in-progress C compiler targeting Aarch64.
Cinder is the successor to my previously made compiler called cc0. The goal of Cinder is to first target the broader C language, and second adopt more techniques used by clang and llvm to understand the architecture as well as get a more sophisticated base on which one can build a better and more robust compiler
Cinder currently supports compiling (Please note that this list is subject to change as the development continues)
- Integer arithmetic
- Bitwise operators
- SSA construction
- Fixed size arrays (stack allocated)
- Pointers (Deref and Address of)
- aacps64
- Basic if statements, short circuiting and condition materialization
Future planned features are
- Better cli infra (base is already done)
- Enums
- For and While loops (lol)
- Switch statements
- Function pointer invocation
- Basic optimization passes like Constant Folding, Constant Propagation, DCE and maybe some memory analysis
- Some experimental optimization passes
- Structs (This is a far reach, as implementing aacps64 for structs is a real hassle so expect this to take time)
- Some simple pre-processor for handling includes and basic macro expansion documented here
Cinder tries to mimik a large portion of the well established clang and llvm architecture. This results in the following compilation pipeline:
Source -> parsing -> AST -> sema -> Annotated AST -> hirgen -> HIR -> isel -> LIR -> register allocation -> physical LIR -> frame lowering and emission -> asm
Parsing is done through a hand written recursive descend parser more on that here.
The semantic analysis does type checking, address taken analysis, inserts implicit casts for pointer decay and lvalue-to-rvalue conversions and the other C typical semantic checks. Sema annotates the AST in-place so HIRGen can later use that information to build the IR
HIRGen is a simple AST to IR translator. It depends heavily on the annotated type information and on the value-category-classification. SSA Construction is currently a work in progress but will be done by the algorithms described in Braun et al., "Simple and Efficient Construction of Static Single Assignment Form" (CC 2013)
Instruction Selection is done through IR trees already provided by the "SSA" nature of the IR. It implements a version of Maximum Munch to cobine certain instruction patterns. This part is also under heavy editing, as more patterns are found. The ultimate goal would be to autogenerate this step just like llvm does with their tablegen
Just like in my previous compiler register allocation is done through Greedy Coloring on chordal interference graphs. The register allocation happens on the LIR that is still in SSA form, meaning SSA destruction happens after register allocation, thus resulting in the optimal coloring in polynomial time. Through the fact that we know we have optimal choloring for k colors on a graph, we do not need a classic chaitin briggs loop for spilling and recoloring, as the coloring is optimal. Coalescing is being done through George and Briggs conservative copy coalescing, although this is also subject to change. Spilling currently has no heuristics and loading/storing spills is relatively naive currently.
This is also pretty naive, as the stack slots and frame info is just being lowered without supporting vlas or dynamic allocation in this case
To build run
cmake --preset <debug/release>
cmake --build build/<debug/release>
For running
./build/debug/src/cinder <input.c>