This site contains architectural/design information about JCC.
Architecture Overview
Driver
The driver performs argument parsing, as well as invoking the various components used for compilation.
Arg parsing
Frontend
The frontend runs the preprocessor, lexer, and parser in lockstep, before performing semantic analysis (called 'typechk' within the compiler).
See the Parse article for a detailed breakdown of the lexer & parser.
See the Typechk article for a detailed breakdown of the typechk semantic analysis pass.
- Preprocessor
- Lexer + Parser
- Semantic analysis - Typecheck
Backend
- Intermediate Representations and passes
- All code located in the
ir
folder - IR representation structs and helper methods are in
ir/ir.h
andir/ir.c
- Pretty-printing functionality is in
ir/prettyprint.h
andir/prettyprint.c
- This also includes graph-building functionality with graphviz
- IR building
- This stage converts the AST into an SSA IR form
- It assumes the AST is entirely valid and well-typed
- Code is
ir/build.h
andir/build.c
- Optimisation passes
- These include inlining, constant folding, dead-branch elimination, and local promotion (a la LLVM's
mem2reg
)
- These include inlining, constant folding, dead-branch elimination, and local promotion (a la LLVM's
- Lowering
- Firstly, global lowering is performed. This lowers certain operations that are lowered on all platforms
- E.g
br.switch
s are converted into a series of if-elses, andload.glb/store.glb
operations are transformed toaddr GLB + load.addr/store.addr
- E.g
- This converts the IR into the platform-native form
- Then, per-target lowering occurs
- For example, AArch64 has no
%
instr, sox = a % b
is converted toc = a / b; x = a - (c * b)
- For example, AArch64 has no
- The code for lowering is within the appropriate backend folders
- Firstly, global lowering is performed. This lowers certain operations that are lowered on all platforms
- All code located in the
- Register allocation
- Simple LSRA, done seperately across floating-point & general-purpose registers
- Eliminate phi
- Splits critical edges and inserts moves to preserve semantics of phi ops
- Code Generation
- Converts the IR into a list of 1:1 machine code instructions
- These are all target specific
- Currently codegen does too much - in the future I would like to move lots of its responsibilities (e.g prologue/epilogue) into IR passes
- Emitting
- Actually emits the instructions from code generation into memory
- Object file building
- Linking