2024-02-10 23:26:51 +00:00
|
|
|
# generator
|
|
|
|
|
2024-02-10 23:32:35 +00:00
|
|
|
## Responsibilities
|
2024-02-10 23:26:51 +00:00
|
|
|
|
|
|
|
Given a compilation target, turn a well-formed FSPL semantic tree into an LLVM
|
|
|
|
IR module tree.
|
|
|
|
|
|
|
|
## Organization
|
|
|
|
|
|
|
|
Generator defines the Target type, which contains information about the system
|
2024-02-10 23:32:35 +00:00
|
|
|
that the program is being compiled for. The native sub-package uses Go's
|
|
|
|
conditional compilation directives to provide a default Target that matches the
|
|
|
|
system the compiler has been natively built for.
|
2024-02-10 23:26:51 +00:00
|
|
|
|
|
|
|
The entry point for all logic defined in this package is Target.Generate(). This
|
|
|
|
method creates a new generator, and uses it to recursively generate and return an
|
|
|
|
LLVM module. The details of the generator are hidden from other packages, and
|
|
|
|
instances of it only last for the duration of Target.Generate().
|
|
|
|
|
|
|
|
The generator contains a stack of blockManagers, which plays a similar role to
|
2024-02-10 23:32:35 +00:00
|
|
|
analyzer.scopeContextManager, except that the stack of blockManagers is managed
|
|
|
|
directly by the generator, which contains appropriate methods for
|
|
|
|
pushing/popping them.
|
2024-02-10 23:26:51 +00:00
|
|
|
|
|
|
|
Like the analyzer, the generator greedily generates code, and one function may
|
|
|
|
be generated in the middle of the generation process of another function. Thus,
|
|
|
|
each blockManager is tied to a specific LLVM function, and is in charge of
|
|
|
|
variables/stack allocations and to a degree, control flow flattening
|
|
|
|
(specifically loops). It also embeds the current active block, allowing for
|
|
|
|
generator routines to call its methods to add new instructions to the current
|
|
|
|
block, and switch between different blocks when necessary.
|
|
|
|
|
|
|
|
## Operation
|
|
|
|
|
|
|
|
When Target.Generate() is called, a new generator is created. It is given the
|
|
|
|
semantic tree to generate, as well as a copy of the Target. All data structure
|
|
|
|
initialization within the generator happens at this point.
|
|
|
|
|
|
|
|
Then, the generate() method on the newly created generator is called. This is
|
|
|
|
the entry point for the actual generation logic. This routine is comprised of
|
|
|
|
two phases:
|
|
|
|
|
|
|
|
- Function generation
|
|
|
|
- Method generation
|
|
|
|
|
|
|
|
You'll notice that there is no step for type generation. This is because types
|
|
|
|
are generated on-demand in order to reduce IR clutter.
|
|
|
|
|
|
|
|
## Expression Generation
|
|
|
|
|
|
|
|
Since expressions make up the bulk of FSPL, expression generation makes up the
|
|
|
|
bulk of the code generator. The generator is able to produce expressions in one
|
|
|
|
of three modes:
|
|
|
|
|
|
|
|
- Location: The generator will return an IR register that contains a pointer to
|
|
|
|
the result of the expression.
|
|
|
|
- Value: The generator will return an IR register that directly contains the
|
|
|
|
result of the expression.
|
|
|
|
- Any: The generator will decide which of these two options is best for the
|
|
|
|
specific expression, and will let the caller know which was chosen, in case it
|
|
|
|
cares. Some expressions are better suited to returning a pointer, such as
|
|
|
|
array subscripting or member access. Other expressions are better suited to
|
|
|
|
returning a value, such as arithmetic operators and function calls.
|
|
|
|
|
|
|
|
It is important to note that generating a Value expression may return a pointer,
|
|
|
|
because *FSPL pointers are first-class values*. The distinction between location
|
|
|
|
and value generation modes is purely to do with LLVM. It is similar to the
|
|
|
|
concept of location expressions within the analyzer, but not 100% identical all
|
|
|
|
of the time.
|
|
|
|
|
|
|
|
Whenever an expression needs to be generated, one of the following routines is
|
|
|
|
called:
|
|
|
|
|
|
|
|
- generator.generateExpression()
|
|
|
|
- generator.generateAny()
|
|
|
|
- generator.generateVal()
|
|
|
|
- generator.generateLoc()
|
|
|
|
|
|
|
|
The generator.generateExpression() routine takes in a mode value and depending
|
|
|
|
on it, calls one of the other more specific routines. Each of these routines, in
|
|
|
|
turn, calls a more specialized generation routine depending on the specific
|
|
|
|
expression.
|
|
|
|
|
|
|
|
If it is specifically requested to generate a value for an expression with only
|
|
|
|
its location component defined or vice versa, generator.generateVal/Loc() will
|
2024-02-10 23:32:35 +00:00
|
|
|
automatically perform the conversion.
|