# Code Generation

The compiler library contains the functionality required to emit code in the intermediate language, compile it into machine code for the current platform, and to later execute the code (usually by binding it to a `Function`). The functionality related to the intermediate language is covered in detail in the language reference. This section covers the types in more detail.

In addition to the code generation facilities for the intermediate language, the library also contains a few utilities that can be used to make code generation more convenient.

## Operands

The value `core.asm.Operand` represents an operand for an instruction in the intermediate language. The different types of operands are described in detail here.

The `Operand` class has a number of cast constructors that allow implicit conversion from registers (`core.asm.Reg`), variables (`core.asm.Var`), labels (`core.asm.Label`), references (`core.asm.Ref`), and source positions (`core.lang.SrcPos`). There are also a number of functions that create operands from various types of literals.

The `Operand` type has the usual operators for comparison, and `toS` for creating a string representation. The empty operand (created by the default constructor) can also be checked for using the `empty` and `any` functions as usual. It also has the following operands for accessing the contents of the operand:

- `core.asm.OpType type()`

  Get the type of the operand.

- `core.asm.Size size()`

  Get the size of the operand.

- `core.Bool readable()`

  Is this operand readable?

- `core.Bool writable()`

  Is this operand writable?

The depending on the value returned from `type`, it is possible to extract the contents of the operand by calling the appropriate members below. These functions check the type internally and throws an error (`InvalidValue`) if they are used incorrectly.

- `core.Word constant()`

  Get the constant in the operand. Valid if `type` returns `constant`. If the value stored is a `Size` or an `Offset`, then the value obtained by calling `current` is returned.

- `core.asm.Reg reg()`

  Get the content register. Valid if `type` returns `register` or `relative`.

- `core.asm.Var var()`

  Get the variable accessed. Valid if `type` returns `variable`.

  Note: The size of the returned variable is equal to the size we wish to read. This may differ from the size of the original variable!

- `core.asm.Offset offset()`

  Get the offset used. Possible to call any time, but only makes sense for `relative`, `variable`, and `relativeLabel`.

- `core.asm.CondFlag condFlag()`

  Get the condition flag. Valid if `type` returns `condFlag`.

- `core.asm.Block block()`

  Get the block. Valid if `type` returns `block`.

- `core.asm.Label label()`

  Get the label. Valid if `type` returns `label`.

- `core.asm.Ref ref()`

  Get the reference. Valid if `type` returns `reference`.

- `core.lang.SrcPos srcPos()`

  Get the source position. Valid if `type` returns `srcPos`.

- `core.Maybe<core.Object> obj()`

  Get the referenced object. Valid if `type` returns `objReference`. Returns an `Object`.

- `core.Maybe<core.TObject> tObj()`

  Get the referenced object. Valid if `type` returns `objReference`. Returns a `TObject`.

## Instruction

The `core.asm.Instr` class represents a single instruction in the intermediate representation. The instruction format is described in detail here. In short, each instruction has two operands. The first one may be written to, and the second is only ever read from. The `Instr` class is created by one of many free functions with the same name as the op-codes described in the language reference. These functions perform basic checking of operand sizes and properties, and throw an error if they are used incorrectly.

The class itself has only a few members as follows:

- `core.asm.OpCode op()`

  Get the op-code.

- `core.asm.Operand src()`

  Get the source operand.

- `core.asm.Operand dest()`

  Get the destination operand.

- `core.asm.DestMode mode()`

  Get the mode of the destination operand. This determines how the instruction uses the destination (e.g. read/write, read, or write).

- `core.asm.Size size()`

  Get the maximum size of the operands.

- `core.asm.Instr alterSrc(core.asm.Operand src)`

  Create an instruction with a different source operand. Intended to be used by backends, so performs no sanity checking.

- `core.asm.Instr alterDest(core.asm.Operand dest)`

  Create an instruction with a different destination operand. Intended to be used by backends, so performs no sanity checking.

- `core.asm.Instr alter(core.asm.Operand dest, core.asm.Operand src)`

  Create an instruction with a different set of operands. Intended to be used by backends, so performs no sanity checking.

For function class, the derived class `core.asm.TypeInstr` is used. This adds the members `type` and `member`. The `type` member contains a type description of the parameter or return type. The `member` member is only used for function call instructions and determines whether the called function is a member function or not.

## Arena

An `core.asm.Arena` describes the platform-specific bits of code generation. The function `core.asm.Arena core.asm.arena()` can be used to create an `Arena` for the current platform. Creating an `Arena` for another platform allows generating code for another platform. This is, however, not very useful currently, as it is not possible to save generated code to disk. It does, however, open up for future cross-platform builds.

## Listing

The `core.asm.Listing` object represents a sequence of instructions, alongside information about local variables, labels, and blocks. The concepts behind the listing is described in more detail here. In short, the listing can be seen as representing a namespace for labels, blocks, and variables. As such, it is able to generate new names for these concepts that are only usable in that particular listing. These names are represented as instances of the types `core.asm.Label`, `core.asm.Block`, and `core.asm.Var` respectively. These created names can then be used as operands to instructions that are then added to the listing. Labels can also be added directly to the listing to allow other instructions to reference other instructions easily (e.g. for jump instructions).

### Creation

A listing stores the expected return type of the function it will be bound to. As such, it can be created in any of the following ways:

- `init()`

  Create a listing for a function that returns `void`.

- `init(core.Bool member, core.asm.TypeDesc result)`

  Create a listing for a function that may be a member function (based on `member`), and returns the type `result`.

There are also two overloads that accept an `arena`. This is to allow the listing to format backend-specific things properly. It does not otherwise affect how the `Listing` works.

### Adding and Inspecting Instructions

Instructions and labels are added using the `<<` operator. The `Listing` also provides the usual `empty`, `any`, `count`, and `[]` members to allow iterating through the instructions in the listing. Labels that appear before a particular instruction are retrieved using the `labels` function.

### Labels

Labels are created using the function `core.asm.Label label()`. It returns a new, unique label that is valid in the listing. As mentioned above, labels can be used as operands to instructions, and they can be inserted in between instructions. Each label is assumed to be added to the listing exactly once.

### Variables and Blocks

Variables in a `Listing` are arranged in a tree of blocks, similarly to many block-scoped languages. The `Listing` provides the following members to create and manipulate blocks:

- `core.asm.Block root()`

  Get the root block.

- `core.asm.Block createBlock(core.asm.Block parent)`

  Create a block inside `parent`. Note that it does not matter if `parent` is the block or any part inside that block.

- `core.asm.Block parent(core.asm.Block b)`

  Get the parent part to a variable or a block.

- `core.Bool isParent(core.asm.Block parent, core.asm.Block q)`

  See if the part `q` is an indirect parent to `parent`.

- `core.Array<core.asm.Block> allBlocks()`

  Get all blocks.

- `void addCatch(core.asm.Block block, core.asm.Listing.CatchInfo add)`

  Add a catch handler to a block. Multiple handlers may be added to a single block. If so, they are evaluated in the order they were added.

- `void addCatch(core.asm.Block block, core.lang.Type type, core.asm.Label resume)`

  Convenience function to create a `CatchInfo` value.

- `core.Maybe<core.Array<core.asm.Listing.CatchInfo>> catchInfo(core.asm.Block block)`

  Get all catch clauses for a block.

Variables can then be added to blocks using any of the `createVar` overloads. Parameters are treated specially, and are created by the `createParam` overloads. Variables and parameters can then be inspected and manipulated using any of the following functions:

- `core.Bool accessible(core.asm.Var v, core.asm.Block p)`

  See if the variable `v` is accessible in the part `p`. This is almost equivalent to checking if any parent blocks of `p` contains the variable.

- `core.Bool isParam(core.asm.Var v)`

  Is this a parameter?

- `core.Maybe<core.asm.TypeDesc> paramDesc(core.asm.Var v)`

  Get parameter info about a variable.

- `core.Maybe<core.asm.Listing.VarInfo> varInfo(core.asm.Var v)`

  Get debug info about a variable.

- `void varInfo(core.asm.Var v, core.Maybe<core.asm.Listing.VarInfo> info)`

  Set debug info.

- `core.asm.Block parent(core.asm.Var b)`

  Get the parent part to a variable or a block.

- `core.asm.Var prev(core.asm.Var v)`

  Get the variable stored just before `v` in this stack frame. Within a single block, it just returns the variable added before `v`. If `v` is the first variable in that block, the last variable of the previous block is returned. This will give all variables visible at the same time as the start variable of the iteration. Parameters are returned lastly.

- `core.Array<core.asm.Var> allVars()`

  Get all variables. Always in order, so allVars()i.key() == i

- `core.Array<core.asm.Var> allVars(core.asm.Block b)`

  Get all variables in a block.

- `core.Array<core.asm.Var> allParams()`

  Get all parameters.

- `void moveParam(core.asm.Var param, core.Nat to)`

  Move a parameter to a specific location.

- `void moveFirst(core.asm.Var var)`

  Move a variable to the beginning of a block. This impacts memory layout and destruction order.

## ExprResult

The value `core.lang.ExprResult` is a utility class that can be convenient to use for code generation in various languages. It is, for example, used in Basic Storm.

The `ExprResult` is intended to represent a result from evaluating an expression. It encapsulates the idea that an expression may either result in some value (represented as a `core.lang.Value`), or it may instead stop execution before it evaluates to a value (e.g. returning from the function or throwing an exception). As such, an `ExprResult` thus has a separate representation of will never return, which is distinct from returns, but produces no value.

It provides the following members:

- `init(core.lang.ExprResult& other)`

  Copy constructor.

- `init()`

  Return void.

- `init(core.lang.Value result)`

  Return a value.

- `core.lang.Value type()`

  Result type. If this is the no-return value, then `void` is returned here.

- `core.Bool value()`

  Does the expression return a value (ie. not `void`)?

- `core.Bool empty()`

  Does the expression return void?

- `core.Bool nothing()`

  Does the expression not return at all.

- `core.lang.ExprResult asRef(core.Bool v)`

  Convert the result to a by-reference value.

The free function `noReturn` creates the special value that indicates that the expression will not return.

## CodeGen

The utility class `core.lang.CodeGen` encapsulates a `core.asm.Listing` (stored in the member `l`) that is being used to output instructions to. It also contains additional state that is typically needed during code generation. This state is a `core.lang.RunOn` that indicates the current thread, and a `core.asm.Block` that represents the current block. This means that instead of passing three variables to code generation functions, one can instead use a single `CodeGen` object.

In addition to bundling three concepts together, it provides a few convenience functions:

- `core.lang.CodeGen child(core.asm.Block block)`

  Create a child code gen where another block is the topmost one.

- `core.lang.CodeGen child()`

  Create a child code gen with a new child block.

- `core.asm.Var createParam(core.lang.Value type)`

  Add a parameter with the specified type.

- `core.lang.VarInfo createVar(core.lang.Value type)`

  Add a variable in the current block.

- `core.lang.VarInfo createVar(core.lang.Value type, core.asm.Block in)`

  Add a variable in the specified block.

The `createVar` functions returns a `core.lang.VarInfo` object. This object stores a `core.asm.Var` alongside a value that records if this variable needs to be activated after it has been constructed. It is typically not necessary to inspect this value manually, it is enough to call the `void created(core.lang.CodeGen gen)` member as soon as the variable has been initialized.

There are also a number of free functions that accomplish some common tasks:

- `void allocObject(core.lang.CodeGen s, core.lang.Type type, core.lang.Function ctor, core.Array<core.asm.Operand> params, core.asm.Var to)`

  Allocate an object on the heap, allow the case where the type and the type of the ctor does not match (i.e. where we will run some other ctor later).

- `core.asm.Var allocObject(core.lang.CodeGen s, core.lang.Type type, core.lang.Function ctor, core.Array<core.asm.Operand> params)`

  Allocate an object on the heap, allow the case where the type and the type of the ctor does not match (i.e. where we will run some other ctor later).

- `void allocObject(core.lang.CodeGen s, core.lang.Function ctor, core.Array<core.asm.Operand> params, core.asm.Var to)`

  Allocate an object on the heap. Store it in variable `to`.

- `core.asm.Var allocObject(core.lang.CodeGen s, core.lang.Function ctor, core.Array<core.asm.Operand> params)`

  Allocate an object on the heap. Store it in variable `to`.

- `core.asm.Var allocObject(core.lang.CodeGen s, core.lang.Type type)`

  Create an object on the heap using the default constructor.

- `core.Array<core.asm.Operand> spillRegisters(core.lang.CodeGen s, core.Array<core.asm.Operand> params)`

  Make sure all parameters in a parameter list reside in memory, moving any values stored in registers into memory as necessary. Returns either the original parameter list or a modified version if at least one parameter was flushed to memory.

- `core.asm.Var createFnCall(core.lang.CodeGen to, core.Array<core.lang.Value> formals, core.Array<core.asm.Operand> actuals, core.Bool copy)`

  Allocate and fill a `FnCall` object, copying arguments depending on `copy`.

- `core.asm.Var createFnCall(core.lang.CodeGen to, core.Array<core.lang.Value> formals, core.Array<core.asm.Operand> actuals, core.asm.Var env)`

  Allocate and fill a `FnCall` object. Using 'env' to create and store a CloneEnv. The variable is assumed to be empty from the start.

## CodeResult

The utility class `core.lang.CodeResult` is a class that can be used by language implementations to communicate the location of data during code generation. To illustrate the usage, imagine you wish to generate code for a particular AST node. The node procudes a result of type `T`. You wish to use the result eventually, but it is not important where it is located. This wish can be expressed as a `CodeResult` and passed to the code generation function of the AST node. The AST node inspects the wish, and updates the `CodeResult` with the location of the result. The caller can then inspect the location and use it as desired.

The benefit of this approach is that it is in most cases not important where the result from an AST node is located. So if the AST node represents a local variable, the AST node may just inform the caller that the result is located in a variable already, and thus avoids a copy if possible.

A `CodeResult` can represent three different types of wishes, as indicated by the constructors:

- `init()`

  The caller is not interested in the result. Only evaluate the AST node for side-effects is applicable, and skip creating the result if suitable.

- `init(core.lang.Value type, core.asm.Var var)`

  The caller asks for a result of type `type`, and it needs to be stored in the provided variable. This means that the AST node is not able to propose another location in order to avoid copies.

- `init(core.lang.Value type, core.asm.Block block)`

  The caller asks for a result of type `type`. The variable needs to be visible in `block`, but apart from that it does not matter which variable is used. As such, this allows the AST node to propose an already existing variable to avoid copying.

The AST node then inspects the `CodeResult` instance to find out which type was asked for, and may propose a location using the following functions:

- `core.lang.Value type()`

  What type was requested? If `void` then no result is required.

- `core.Bool needed()`

  Does the caller need a result at all?

- `core.Bool suggest(core.lang.CodeGen s, core.asm.Var v)`

  Suggest a location for the result. Returns true if the suggestion is acceptable, otherwise, it is necessary to use the variable returned by `location`. If the suggestion is used, we assume it is already created (i.e. `created` will be a no-op).

- `core.Bool suggest(core.lang.CodeGen s, core.asm.Operand v)`

  Suggest a location for the result. Returns true if the suggestion is acceptable, otherwise, it is necessary to use the variable returned by `location`. If the suggestion is used, we assume it is already created (i.e. `created` will be a no-op).

- `core.asm.Var location(core.lang.CodeGen s)`

  Get a location to store the variable in. Asserts if the result is not needed.

- `void created(core.lang.CodeGen s)`

  Call when the variable was initialized to set up any cleanup required. If you are entirely sure that no cleanup is required for the contained variable, the call to `created` may be omitted.

- `core.asm.Var safeLocation(core.lang.CodeGen s, core.lang.Value type)`

  Get the location of the result even if the result is not needed. Can be used in cases where it is not suitable to avoid creating a result even if it is not needed.

- `core.lang.CodeResult split(core.lang.CodeGen s)`

  Create a copy of this result that is usable when multiple pieces of code may produce the result represented by this object. Essentially, this means that cleanup will not be set up until `created` is called on this object. Thus, make sure to call `created` here!

  Call `split` once for each branch that is expected to create a new value, so that each producer gets its own object. Otherwise, issues will arise when they call `created` multiple times.

Finally, the caller may call `location` to retrieve the created value.