# Locals

There are two usages of locals in zink.

1. The parameters of functions are loaded as locals.
2. local defined variables in functions.

|       | fn params   | local variables |
| ----- | ----------- | --------------- |
| stack | locals[..n] | locals[n..]     |

## Function Parameters

Let's go through the `add-two` example:

```wasm
(module
    (func (param (;0;) i32) (param (;1;) i32) (result i32)
    (local.get 0)
    (local.get 1)
    (i32.add)
    )
)
```

`(param (;0;) i32)` and `(param (;1;) i32)` will be pushed to the function
locals with index `0` and index `1` with their type `i32` recorded.

`zinkc` gets the defined local at index `0` when reaching `(local.get 0)`,
at index `1` for `(local.get 1)`, for example, for `(local.get 0)`, it will
be translated to:

```yul
push1 0x00
calldataload
```

for `(local.get 1)`, that would be

```yul
push1 0x20
calldataload
```

You may have problem why we `PUSH1 0x20` while getting local at index `1`, the
answer is that this offset is calculated by the size of the parameters.

The `CALLDATALOAD` operator has stack input `i` and output `data[i]` while `data[i]`
is a `32-byte` value starting from the given offset of the calldata, so the minimal
size of our types will be `32-byte`, therefore, we align all types sizes to `32-byte`
in `zinkc`.

> WARN: We don't care about the originals offset of the parameters in WASM bcz we will
> serialize them into our locals and calculate the offsets on our own when need anyway.

| type  | size     | aligned size |
| ----- | -------- | ------------ |
| `i32` | `[u8;4]` | `[u8;32]`    |
| `i64` | `[u8;8]` | `[u8;32]`    |

It is a waste of resources but sadly this is also how EVM works ))

## Local Variables

The locals variables will take the stack items right after the function
parameters, for example:

```wasm
(func (result i32)
  (local i32)
  i32.const 42
  local.set 0
  local.get 0)
```

In the program above, we set and get `42` to local variable `0` and returns it.

While compiling this function, `zinkc` will push local variable `0` on the stack
with an initializing value `0` first, getting with `dup` and setting with `swap`
and `drop`.

```yul
PUSH1 0x00       // initializing value 0 for local 0
                 //
                 //
PUSH1 0x28       // push value 42 on stack, the current stack is [0, 42]
                 //
                 //
SWAP1            // swap the value on the top of the stack to local 0 and
DROP             // drop the previous value of it for cleaning stack, `swapn`
                 // is calculated by `zinkc`. current stack: [42]
                 //
                 //
DUP1             // dup the value of local 0 and push it on the top of the
                 // stack, `dupn` is calculated by `zinkc`.
                 //
                 //
DROP             // clean the stack before returning results.
```

As we can see, the usages of `get` and `set` is verbose with `swap` and `dup`,
it is for adapting any usages but not necessary for all of them, however, we
will introduce optimizer for this in `v0.4.0`!