Compiler

Compiler interface.

Overview

BaseCompiler is a high-level interface, which provides register allocation and support for defining and invoking functions, built on top of BaseBuilder interface At the moment it's the easiest way of generating code in AsmJit as most architecture and OS specifics is properly abstracted and handled by AsmJit automatically. However, abstractions also mean restrictions, which means that BaseCompiler has more limitations than BaseAssembler or BaseBuilder.

Since BaseCompiler provides register allocation it also establishes the concept of functions - a function in Compiler sense is a unit in which virtual registers are allocated into physical registers by the register allocator. In addition, it enables to use such virtual registers in function invocations.

BaseCompiler automatically handles function calling conventions. It's still architecture dependent, but makes the code generation much easies. Functions are essential; the first-step to generate some code is to define a signature of the function to be generated (before generating the function body itself). Function arguments and return value(s) are handled by assigning virtual registers to them. Similarly, function calls are handled the same way.

Compiler Nodes

BaseCompiler adds some nodes that are required for function generation and invocation:

BaseCompiler also makes the use of passes (Pass) and automatically adds an architecture-dependent register allocator pass to the list of passes when attached to CodeHolder.

Compiler Examples

  • x86::Compiler - Compiler implementation targeting X86 and X86_64 architectures.
  • a64::Compiler - Compiler implementation targeting AArch64 architecture.

Compiler Tips

Users of AsmJit have done mistakes in the past, this section should provide some useful tips for beginners:

  • Virtual registers in compiler are bound to a single function. At the moment the implementation doesn't care whether a single virtual register is used in multiple functions, but it sees it as two independent virtual registers in that case. This means that virtual registers cannot be used to implement global variables. Global variables are basically memory addresses which functions can read from and write to, and they have to be implemented in the same way.
  • Compiler provides a useful debugging functionality, which can be turned on through FormatFlags. Use Logger::addFlags() to turn on additional logging features when using Compiler.

Classes