Lyx – ABI & Calling Conventions
Die ABI definiert, wie Funktionen auf Binärebene miteinander kommunizieren. Da Lyx ein nativer Compiler ist, folgt er den Standard-Konventionen der jeweiligen Zielplattform, um Kompatibilität mit System-Aufrufen (Syscalls) und externen Bibliotheken (Shared Objects/DLLs) zu gewährleisten.
1) Register-Belegung (x86_64)
Unter Linux und macOS folgt Lyx der System V AMD64 ABI. Unter Windows wird die Microsoft x64 Calling Convention genutzt.
| Zweck | System V (Linux/macOS) | Microsoft x64 (Windows) |
|---|---|---|
| 1. Argument | RDI | RCX |
| 2. Argument | RSI | RDX |
| 3. Argument | RDX | R8 |
| 4. Argument | RCX | R9 |
| 5. Argument | R8 | Stack |
| 6. Argument | R9 | Stack |
| Rückgabewert | RAX | RAX |
Hinweis: Weitere Argumente werden bei beiden Systemen über den Stack übergeben.
2) Register-Belegung (ARM64 / AArch64)
Für ARM64 (Linux & Apple Silicon) nutzt Lyx die Standard AAPCS64 (Procedure Call Standard).
Argumente 1-8: Register X0 bis X7.
Rückgabewert: Register X0.
Stack Pointer: SP (muss immer 16-Byte ausgerichtet sein).
Link Register: X30 (enthält die Rücksprungadresse nach einem bl).
3) Stack-Layout & Alignment
Lyx garantiert bei jedem Funktionsaufruf ein 16-Byte Alignment des Stacks. Dies ist besonders wichtig für:
SIMD-Instruktionen (SSE/AVX/NEON): Viele dieser Befehle stürzen ab, wenn die Daten nicht korrekt ausgerichtet sind.
Blatt-Funktionen (Leaf Functions): Funktionen, die keine weiteren Funktionen aufrufen, können den Stack-Pointer oft unverändert lassen, um Performance zu sparen.
Prolog & Epilog
Jede nicht-getunte Funktion in Lyx führt beim Eintritt einen Prolog aus:
push rbp // Sichere alten Base-Pointer mov rbp, rsp // Setze neuen Base-Pointer sub rsp, 32 // Reserviere Platz für lokale Variablen (Beispiel)
Beim Verlassen (return) sorgt der Epilog für die Wiederherstellung:
leave // Entspricht mov rsp, rbp; pop rbp ret // Rücksprung
4) Interaktion mit C (extern)
Wenn du eine Funktion als extern deklarierst, verlässt sich Lyx darauf, dass die Ziel-Bibliothek die oben genannten Regeln einhält.
// Lyx weiß, dass 'printf' das erste Argument in RDI (Linux) erwartet
extern "libc.so.6" fn printf(format: pchar, val: int64): int32;
fn Main() {
printf("Wert: %d\n", 42);
}
5) Datentyp-Größen in der ABI
| Typ | Größe (Bytes) | Alignment |
|---|---|---|
| int8 / uint8 | 1 | 1 |
| int32 / uint32 | 4 | 4 |
| int64 / uint64 | 8 | 8 |
| f64 (Float) | 8 | 8 (XMM/Floating-Point Register) |
| pchar (Pointer) | 8 | 8 |
| bool | 1 | 1 |
6) Besonderheit: QBool (Probabilistisch)
Der Datentyp qbool (Quantum Boolean) wird intern als f64 (8 Byte) behandelt, da er Wahrscheinlichkeitswerte zwischen 0.0 und 1.0 speichert. In Verzweigungen (if) wird er gegen einen internen Schwellenwert (Standard 0.5) oder einen Hardware-Zufallsgenerator (sofern vorhanden) geprüft.
