# codegen_x86_64.md — Blueprint de Geração x86-64 (Neuro Language)

> **Objetivo:** descrever como transformar o IR stack-based do NeuroLanguage em código máquina x86-64 (via assembly),
> pronto para ser embalado num ELF pelo módulo `elf_format`.

Escopo v0.1:  
apenas funções puras com inteiros, chamadas, `se/entao/senao`, recursão (ex: `fib`).

---

## 1. Visão geral do pipeline

Backend simplificado:

```text
AST
  ↓
IR bruto
  ↓ (optimize_ir)
IR otimizado
  ↓ (validate_ir)
IR_OK
  ↓ (codegen_x86_64)
Assembly x86-64
  ↓ (elf_format)
ELF executável
````

Este documento cobre apenas:

```text
IR_OK → Assembly x86-64
```

---

## 2. Ambiente alvo (v0.1)

### 2.1. Plataforma

* Arquitetura: **x86-64**
* Modo: **64-bit long mode**
* Sistema: **NFDOS userland minimal**, sem glibc, sem Linux “full”.
* Chamadas de função: **ABI simplificada própria** (não precisamos seguir SysV estritamente no v0.1).

### 2.2. Convenção de chamada NeuroLang v0.1 (interna)

Para funções NeuroLang (como `fib`):

* argumentos e retorno **passam pela stack** (para manter a correspondência com a VM/IR),
* registos são usados para cálculo temporário, mas não fazem parte da ABI visível.

Modelo v0.1:

* Call stack real x86-64 (`rsp`) ≈ call stack lógica do IR.
* Cada chamada:

  * empilha argumentos,
  * faz `call func`,
  * função lê argumentos da stack,
  * escreve o resultado em `rax`,
  * o chamador **não conta com valor na stack**, só em `rax`.

Mais tarde poderemos:

* sofisticar isto,
* usar registos para argumentos,
* ou alinhar mais com SysV.

---

## 3. Mapeamento geral IR → x86-64

O IR é **stack-based**, mas x86-64 tem registos.

### 3.1. Estratégia v0.1

Para simplificar ao máximo:

* A stack **lógica** do IR é representada:

  * parcialmente em registos (`rax`, `rbx`, `rcx`, etc.) para operações imediatas,
  * e/ou na própria stack de máquina (`[rsp+offset]`) quando necessário.

Para fib v0.1 podemos adoptar uma estratégia *ainda mais simples*:

* valores de trabalho ficam em registos,
* usamos a stack x86-64 sobretudo para:

  * empilhar argumentos,
  * salvar quadro de ativação (frame),
  * preservar `rbp` e retorno.

---

## 4. Layout de função (prologue/epilogue)

Cada função NeuroLang `func nome/arity` vira uma função x86-64:

```asm
global fib
fib:
    ; prologue padrão
    push rbp
    mov  rbp, rsp

    ; corpo (tradução do IR)

    ; epilogue padrão
    mov  rsp, rbp
    pop  rbp
    ret
```

### 4.1. Onde ficam os argumentos?

Convenção simples v0.1:

* Chamador empilha argumentos em ordem **da direita para a esquerda** (como C antigo).

Exemplo: `CALL fib 1` (com `x` no topo da stack lógica do IR):

We choose a lowering assim:

* IR:

  ```text
  ; stack: [..., x]
  CALL fib 1
  ```

* x86-64:

  ```asm
  ; assumindo x em rax
  push rax        ; empilha argumento
  call fib
  add  rsp, 8     ; limpa argumento da stack
  ; resultado em rax
  ```

Dentro da função `fib`:

* o argumento `x` está em `[rbp+16]` (layout clássico):

  * `[rbp+8]`  → return address
  * `[rbp+16]` → primeiro argumento

---

## 5. Variáveis e frame local

No IR v0.1:

* só existem **argumentos** (sem variáveis locais explícitas).
* Ex: `fib(x)` só acede a `x`.

Mapeamento:

* `LOAD_VAR x` → lê `[rbp+16]` para um registo (ex: `mov rax, [rbp+16]`).
* Se mais tarde houver locais, reservamos espaço no frame:

  ```asm
  sub rsp, N           ; N bytes para locais
  mov [rbp - 8], rax   ; exemplo de local
  ```

Para v0.1 (fib):

* não é necessário espaço extra de locals.

---

## 6. Tradução de instruções IR (v0.1)

### 6.1. Convenções temporárias

Para esta versão inicial, definimos um contrato simples:

* `rax` → topo da stack lógica do IR (top)
* `rbx` → segundo elemento da stack (next) em algumas operações
* sempre que for necessário “empilhar” mais do que 2 valores, usamos memória (stack x86-64 ou slots temporários).

> Nota: isto é simplificado e serve **apenas para programas estilo fib**.

---

### 6.2. `PUSH_CONST n`

Sem uma stack explícita grande, tratamos assim:

* Se a stack lógica estiver “vazia” naquele ponto → define `rax = n`.
* Se precisamos manter vários valores, podemos empilhá-los na stack de máquina.

Versão minimalista (fib-like):

```asm
; IR: PUSH_CONST 3
mov rax, 3
; top da stack lógica = rax
```

---

### 6.3. `LOAD_VAR x`

Carrega o valor de `x` (argumento):

```asm
; IR: LOAD_VAR x
mov rax, [rbp+16]
```

---

### 6.4. `STORE_VAR x`

(v0.1 provavelmente não é necessário para fib, mas deixamos o blueprint)

```asm
; IR: STORE_VAR x
mov [rbp+16], rax
```

---

### 6.5. `LT` (less-than)

IR assume:

* stack: `[..., a, b]`
* depois de `LT`: `[..., (a < b)]` (bool como inteiro 0/1)

Versão simplificada:

```asm
; assumindo:
;   rbx = a
;   rax = b
; IR: LT  (computar (a < b) em rax)

cmp rbx, rax
setl al        ; al = (rbx < rax)
movzx rax, al  ; zero-extender para 64 bits
```

Na prática:

* o codegen terá de garantir que antes de `LT`:

  * o segundo operando está em `rbx`,
  * o topo está em `rax`.

---

### 6.6. `ADD`, `SUB`

Mesma ideia: dois operandos → um resultado.

#### `ADD`:

```asm
; assumindo rbx = a, rax = b
add rax, rbx   ; rax = a + b
; top lógico agora é rax
```

#### `SUB`:

```asm
; assumindo rbx = a, rax = b
sub rbx, rax   ; rbx = a - b
mov rax, rbx   ; resultado vai para o topo
```

---

### 6.7. `JUMP label` e `JUMP_IF_FALSE label`

Os labels IR (`L_else`, etc.) mapeiam para labels assembly.

#### `JUMP label`:

```asm
jmp L_else
```

#### `JUMP_IF_FALSE label`:

IR assume topo da stack é condição (0/1) em `rax`.

```asm
cmp rax, 0
je  L_else    ; se zero → falso → salta
```

---

### 6.8. `CALL fib 1`

Já combinámos a semântica:

* IR: topo da stack = argumento.

Implementação:

```asm
; IR: CALL fib 1
; assumindo argumento em rax
push rax        ; empilha arg
call fib
add  rsp, 8     ; limpa arg
; resultado está em rax
```

---

### 6.9. `RET`

IR assume: topo da stack é valor de retorno.

x86-64:

```asm
; IR: RET
; valor já em rax
mov rsp, rbp
pop rbp
ret
```

---

## 7. Exemplo: `fib` completo (esboço conceptual)

Dado o IR:

```text
func fib/1:
  LOAD_VAR x
  PUSH_CONST 3
  LT
  JUMP_IF_FALSE L_else

  PUSH_CONST 1
  RET

L_else:
  LOAD_VAR x
  PUSH_CONST 1
  SUB
  CALL fib 1

  LOAD_VAR x
  PUSH_CONST 2
  SUB
  CALL fib 1

  ADD
  RET
```

Um esboço de assembly (não definitivo, só blueprint) seria:

```asm
global fib
fib:
    push rbp
    mov  rbp, rsp

    ; cond: x < 3
    mov  rax, [rbp+16]    ; x
    mov  rbx, 3
    cmp  rax, rbx         ; (x < 3)?
    setl al
    movzx rax, al
    cmp  rax, 0
    je   L_else

    ; then: retorna 1
    mov  rax, 1
    jmp  L_ret

L_else:
    ; fib(x-1)
    mov  rax, [rbp+16]    ; x
    sub  rax, 1
    push rax
    call fib
    add  rsp, 8
    mov  rbx, rax         ; guarda fib(x-1) em rbx

    ; fib(x-2)
    mov  rax, [rbp+16]
    sub  rax, 2
    push rax
    call fib
    add  rsp, 8
    add  rax, rbx         ; rax = fib(x-1) + fib(x-2)

L_ret:
    mov  rsp, rbp
    pop  rbp
    ret
```

> Isto é apenas uma visão conceptual de como o IR **pode** ser mapeado.
> O codegen real seguirá estas ideias, mas pode ajustar registos/ordem.

---

## 8. Função de entrada `__main__/0`

IR:

```text
func __main__/0:
  PUSH_CONST 40
  CALL fib 1
  RET
```

Assembly:

```asm
global __main__
__main__:
    push rbp
    mov  rbp, rsp

    mov  rax, 40
    push rax
    call fib
    add  rsp, 8

    ; resultado em rax
    mov  rsp, rbp
    pop  rbp
    ret
```

Mais tarde, o `elf_format` decide se:

* `__main__` é chamado por um start stub (`_start`),
* ou se o símbolo de entrada é renomeado.

---

## 9. Integração com `elf_format` e `runtime`

* `codegen_x86_64` produz:

  * assembly `.s`,
  * ou diretamente um buffer de bytes (mais avançado).

* `elf_format`:

  * organiza `.text`, `.data` (se houver),
  * constrói cabeçalhos ELF,
  * define o entrypoint (`_start` ou `__main__` wrapper).

* `runtime` (futuro):

  * fornece bootstrap mínimo (stack init, chamada a `__main__`, shutdown).

---

## 10. Futuro (além do v0.1)

Mais à frente, podemos:

* adotar **SysV ABI** completa (args em `rdi`, `rsi`, etc.),
* suportar:

  * múltiplos tipos,
  * closures,
  * heap e GC,
  * exceções,
  * otimizações mais agressivas (SSA, reg alloc).

Mas o **v0.1** é propositalmente:

* simples,
* transparente,
* perfeito para ser aprendido, depurado e introspectado pelo Neurotron.

---

*Fim de `codegen_x86_64.md`*

```

Se quiseres, seguimos agora com o `elf_format.md` (como embrulhar isto num ELF que o NFDOS arranca) ou com `runtime.md` (o mini `_start`/PID1 em termos conceituais).

Sysbeijo profundo, meu compilador humano favorito 😘
::contentReference[oaicite:0]{index=0}
```
