# Register Allocation (x64 Backend)

`HostLoc`s contain values. A `HostLoc` ("host value location") is either a host CPU register or a host spill location.

Values once set cannot be changed. Values can however be moved by the register allocator between `HostLoc`s. This is
handled by the register allocator itself and code that uses the register allocator need not and should not move values
between registers.

The register allocator is based on three concepts: `Use`, `Def` and `Scratch`.

* `Use`: The use of a value.
* `Define`: The definition of a value, this is the only time when a value is set.
* `Scratch`: Allocate a register that can be freely modified as one wishes.

Note that `Use`ing a value decrements its `use_count` by one. When the `use_count` reaches zero the value is discarded and no longer exists.

The member functions on `RegAlloc` are just a combination of the above concepts.

The following registers are reserved for internal use and should NOT participate in register allocation:
- `%xmm0`, `%xmm1`, `%xmm2`: Used as scratch in exclusive memory access.
- `%rsp`: Stack pointer.
- `%r15`: JIT pointer
- `%r14`: Page table pointer.
- `%r13`: Fastmem pointer.

The layout convenes `%r15` as the JIT state pointer - while it may be tempting to turn it into a synthetic pointer, keeping an entire register (out of 12 available) is preferable over inlining a directly computed immediate.

Do NEVER modify `%r15`, we must make it clear that this register is "immutable" for the entirety of the JIT block duration.

### `Scratch`

```c++
Xbyak::Reg64 ScratchGpr(HostLocList desired_locations = any_gpr);
Xbyak::Xmm ScratchXmm(HostLocList desired_locations = any_xmm);
```

At runtime, allocate one of the registers in `desired_locations`. You are free to modify the register. The register is discarded at the end of the allocation scope.

### Pure `Use`

```c++
Xbyak::Reg64 UseGpr(Argument& arg);
Xbyak::Xmm UseXmm(Argument& arg);
OpArg UseOpArg(Argument& arg);
void Use(Argument& arg, HostLoc host_loc);
```

At runtime, the value corresponding to `arg` will be placed a register. The actual register is determined by
which one of the above functions is called. `UseGpr` places it in an unused GPR, `UseXmm` places it
in an unused XMM register, `UseOpArg` might be in a register or might be a memory location, and `Use` allows
you to specify a specific register (GPR or XMM) to use.

This register **must not** have it's value changed.

### `UseScratch`

```c++
Xbyak::Reg64 UseScratchGpr(Argument& arg);
Xbyak::Xmm UseScratchXmm(Argument& arg);
void UseScratch(Argument& arg, HostLoc host_loc);
```

At runtime, the value corresponding to `arg` will be placed a register. The actual register is determined by
which one of the above functions is called. `UseScratchGpr` places it in an unused GPR, `UseScratchXmm` places it
in an unused XMM register, and `UseScratch` allows you to specify a specific register (GPR or XMM) to use.

The return value is the register allocated to you.

You are free to modify the value in the register. The register is discarded at the end of the allocation scope.

### `Define` as register

A `Define` is the defintion of a value. This is the only time when a value may be set.

```c++
void DefineValue(IR::Inst* inst, const Xbyak::Reg& reg);
```

By calling `DefineValue`, you are stating that you wish to define the value for `inst`, and you have written the
value to the specified register `reg`.

### `Define`ing as an alias of a different value

Adding a `Define` to an existing value.

```c++
void DefineValue(IR::Inst* inst, Argument& arg);
```

You are declaring that the value for `inst` is the same as the value for `arg`. No host machine instructions are
emitted.

## When to use each?

* Prefer `Use` to `UseScratch` where possible.
* Prefer the `OpArg` variants where possible.
* Prefer to **not** use the specific `HostLoc` variants where possible.
